[
  {
    "path": ".dockerignore",
    "content": ".dockerignore\n.env\n.git\n.gitignore\n.vs\n.vscode\ndocker-compose.yml\ndocker-compose.*.yml\n*/bin\n*/obj\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n*.sh text eol=lf\n"
  },
  {
    "path": ".gitignore",
    "content": "/.build/\n/global.json\nQueryBaseline.cs\n\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n*.user.sln*\n/test.ps1\n*.stackdump\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# BenchmarkDotNet Results\n[Bb]enchmarkDotNet.Artifacts/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n**/Properties/launchSettings.json\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Typescript v1 declaration files\ntypings/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\ntest/Microsoft.EntityFrameworkCore.MongoDB.Tests/.data/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: csharp\nsudo: false\ndotnet: 2.1.2\ndist: trusty\nenv:\n  global:\n    - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n    - DOTNET_CLI_TELEMETRY_OPTOUT: 1\nmono: none\nservices:\n  - mongodb\nos:\n  - linux\n#  - osx\nosx_image: xcode8.1\naddons:\n  apt:\n    packages:\n      - libunwind8\nbranches:\n  only:\n    - master\n    - release\n    - develop\n    - /^rel\\/.*/\n    - /^(.*\\/)?ci-.*$/\nscript:\n  - ./build.sh"
  },
  {
    "path": "Blueshift.EntityFrameworkCore.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.27004.2010\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"build\", \"build\", \"{FAF9C31C-A1AF-42A9-9306-EC190DCACCC7}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tbuild\\dependencies.props = build\\dependencies.props\n\t\tbuild\\repo.beforecommon.props = build\\repo.beforecommon.props\n\t\tbuild\\repo.props = build\\repo.props\n\t\tbuild\\repo.targets = build\\repo.targets\n\t\tbuild\\sources.props = build\\sources.props\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Globals\", \"Globals\", \"{6841D576-C833-4614-89D8-4CF4DECD1CFA}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.travis.yml = .travis.yml\n\t\tappveyor.yml = appveyor.yml\n\t\tbuild.cmd = build.cmd\n\t\tbuild.sh = build.sh\n\t\tDirectory.Build.props = Directory.Build.props\n\t\tDirectory.Build.targets = Directory.Build.targets\n\t\tglobal.json = global.json\n\t\tkorebuild-lock.txt = korebuild-lock.txt\n\t\tkorebuild.json = korebuild.json\n\t\tNuGet.config = NuGet.config\n\t\tREADME.md = README.md\n\t\trun.cmd = run.cmd\n\t\trun.ps1 = run.ps1\n\t\trun.sh = run.sh\n\t\tversion.props = version.props\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"src\", \"src\", \"{CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tsrc\\Directory.Build.props = src\\Directory.Build.props\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{258D5057-81B9-40EC-A872-D21E27452749}\"\n\tProjectSection(SolutionItems) = preProject\n\t\ttest\\Directory.Build.props = test\\Directory.Build.props\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Shared\", \"Shared\", \"{2B598BE4-9107-4F65-90E7-749F3A41F9D6}\"\n\tProjectSection(SolutionItems) = preProject\n\t\tsrc\\Shared\\Check.cs = src\\Shared\\Check.cs\n\t\tsrc\\Shared\\CodeAnnotations.cs = src\\Shared\\CodeAnnotations.cs\n\t\tsrc\\Shared\\MemberInfoExtensions.cs = src\\Shared\\MemberInfoExtensions.cs\n\t\tsrc\\Shared\\PropertyInfoExtensions.cs = src\\Shared\\PropertyInfoExtensions.cs\n\t\tsrc\\Shared\\SharedTypeExtensions.cs = src\\Shared\\SharedTypeExtensions.cs\n\t\tsrc\\Shared\\StringBuilderExtensions.cs = src\\Shared\\StringBuilderExtensions.cs\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Blueshift.EntityFrameworkCore.MongoDB\", \"src\\Blueshift.EntityFrameworkCore.MongoDB\\Blueshift.EntityFrameworkCore.MongoDB.csproj\", \"{E0841FBC-A266-41BF-AA5F-4514692D2161}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\", \"src\\Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\\Blueshift.EntityFrameworkCore.MongoDB.SampleDomain.csproj\", \"{169261F6-0B97-47A5-98B8-E6AA084FF6A4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Blueshift.EntityFrameworkCore.MongoDB.Tests\", \"test\\Blueshift.EntityFrameworkCore.MongoDB.Tests\\Blueshift.EntityFrameworkCore.MongoDB.Tests.csproj\", \"{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Blueshift.Identity.MongoDB\", \"src\\Blueshift.Identity.MongoDB\\Blueshift.Identity.MongoDB.csproj\", \"{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Blueshift.Identity.MongoDB.Tests\", \"test\\Blueshift.Identity.MongoDB.Tests\\Blueshift.Identity.MongoDB.Tests.csproj\", \"{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25}\"\nEndProject\nProject(\"{E53339B2-1760-4266-BCC7-CA923CBCF16C}\") = \"docker-compose\", \"docker-compose.dcproj\", \"{04CEB217-71E2-4DBD-B35A-737EE7D258B8}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E0841FBC-A266-41BF-AA5F-4514692D2161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E0841FBC-A266-41BF-AA5F-4514692D2161}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E0841FBC-A266-41BF-AA5F-4514692D2161}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E0841FBC-A266-41BF-AA5F-4514692D2161}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{169261F6-0B97-47A5-98B8-E6AA084FF6A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{169261F6-0B97-47A5-98B8-E6AA084FF6A4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{169261F6-0B97-47A5-98B8-E6AA084FF6A4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{169261F6-0B97-47A5-98B8-E6AA084FF6A4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{04CEB217-71E2-4DBD-B35A-737EE7D258B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{04CEB217-71E2-4DBD-B35A-737EE7D258B8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{04CEB217-71E2-4DBD-B35A-737EE7D258B8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{04CEB217-71E2-4DBD-B35A-737EE7D258B8}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{2B598BE4-9107-4F65-90E7-749F3A41F9D6} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}\n\t\t{E0841FBC-A266-41BF-AA5F-4514692D2161} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}\n\t\t{169261F6-0B97-47A5-98B8-E6AA084FF6A4} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}\n\t\t{314B80D1-CBB7-4EF5-A5BD-3AD9F14069E8} = {258D5057-81B9-40EC-A872-D21E27452749}\n\t\t{85A1B2BB-BF46-445A-85C3-CFB1CCCB33CE} = {CE6B50B2-34AE-44C9-940A-4E48C3E1B3BC}\n\t\t{E7AF1BE9-6017-4FDF-BDEC-B3FAC1888A25} = {258D5057-81B9-40EC-A872-D21E27452749}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {AA7DD3E1-6124-4D69-A1C3-E4D643A5C4D5}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Blueshift.EntityFrameworkCore.sln.DotSettings",
    "content": "﻿<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namespace:System;assembly=mscorlib\" xmlns:ss=\"urn:shemas-jetbrains-com:settings-storage-xaml\" xmlns:wpf=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">\n\t<s:Boolean x:Key=\"/Default/UserDictionary/Words/=Materializer/@EntryIndexedValue\">True</s:Boolean></wpf:ResourceDictionary>"
  },
  {
    "path": "Directory.Build.props",
    "content": "﻿<Project>\n  <Import Project=\"version.props\" />\n  <Import Project=\"build/dependencies.props\" />\n  <Import Project=\"build/sources.props\" />\n\n  <PropertyGroup>\n    <BuildYear>$([System.DateTime]::Now.ToString('yyyy'))</BuildYear>\n    <RepositoryType>git</RepositoryType>\n    <RepositoryRoot>$(MSBuildThisFileDirectory)</RepositoryRoot>\n    <RepositoryUrl>https://github.com/crhairr/EntityFrameworkCore.MongoDb.git</RepositoryUrl>\n    <!--<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)Key.snk</AssemblyOriginatorKeyFile>\n    <PublicSign Condition=\"'$(OS)' != 'Windows_NT'\">True</PublicSign>\n    <SignAssembly>True</SignAssembly>-->\n    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>\n    <Company>Blueshift Software, LLC</Company>\n    <Authors>$(Company)</Authors>\n    <Copyright>© $(Company) @ $(BuildYear) - all rights reserved.</Copyright>\n    <PackageTags>Blueshift;MongoDB;Entity Framework Core;entity-framework-core;EF;Data;O/RM</PackageTags>\n    <Product>Blueshift Software MongoDB Provider for Entity Framework Core</Product>\n    <DebugType Condition=\"'$(Configuration)' == 'Debug' AND '$(OS)' == 'Windows_NT'\">full</DebugType>\n    <LangVersion>7.2</LangVersion>\n    <NoWarn>$(NoWarn);CS8032;</NoWarn>\n\n    <AssemblyName>$(MSBuildProjectName)</AssemblyName>\n    <RootNamespace>$(MSBuildProjectName)</RootNamespace>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Include=\"**\\*.rd.xml\" />    \n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "Directory.Build.targets",
    "content": "﻿<Project>\n  <PropertyGroup>\n    <!-- Assign these values at the end of the project after TargetFramework has been assigned. TargetFramework is not assigned yet in Directory.Build.props. -->\n    <RuntimeFrameworkVersion Condition=\" '$(TargetFramework)' == 'netcoreapp2.0' \">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>\n    <NETStandardImplicitPackageVersion Condition=\" '$(TargetFramework)' == 'netstandard2.0' \">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>\n    <!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->\n    <NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>\n  </PropertyGroup>\n</Project>\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2017 Blueshift Software, LLC. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthese files except in compliance with the License. You may obtain a copy of the\nLicense at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n"
  },
  {
    "path": "NuGet.config",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <clear />\n    <!-- Restore sources should be defined in build/sources.props. -->\n  </packageSources>\n</configuration>\n"
  },
  {
    "path": "README.md",
    "content": "This repository has been defunct for some time. Due to a lack of both public interest and general support from the Microsoft Entity Framework team, I have decided to formally end support for the solution and archive the repository.\n\n\n# Document Database Providers for Entity Framework Core\n\nWelcome to the home of Document Database (NoSQL) Providers for EntityFrameworkCore!\n\n[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/iip86emc94ncp0ao?svg=true&style=flat-square)](https://ci.appveyor.com/project/crhairr/entityframeworkcore-mongodb/) [![Travis CI Build Status](https://travis-ci.org/BlueshiftSoftware/EntityFrameworkCore.svg?branch=develop&label=travis-ci&style=flat-square)](https://travis-ci.org/BlueshiftSoftware/EntityFrameworkCore)\n\nThis repository currently only contains a MongoDB provider for EF Core. However, there are plans in the current roadmap to expand this with further NoSQL provider offerings.\n\nMongoDb is a highly popular No-SQL database solution for storing structured, non-relational document data. This provider enables applications built with EntityFrameworkCore to use MongoDb instances as a backing data store.\n\nFind out how to get started by visiting the [Wiki pages](https://github.com/crhairr/EntityFrameworkCore.MongoDb/wiki). Feel free to contribute to this repository with code, comments, wiki entries, and/or issues.\n\nThe latest release and CI previews builds are available at the EntityFrameworkCore.MongoDb [MyGet Feed](https://www.myget.org/gallery/efcore-mongodb/).\n"
  },
  {
    "path": "appveyor.yml",
    "content": "init:\n  - git config --global core.autocrlf true\nclone_depth: 1\ntest: off\nservices:\n  - mongodb\nenvironment:\n  global:\n    DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true\n    DOTNET_CLI_TELEMETRY_OPTOUT: 1\nmatrix:\n  fast_finish: true\nfor:\n  -\n    matrix:\n      only:\n        - image: Ubuntu\n    build_script:\n      - sh: chmod +x ./run.sh\n      - sh: ./run.sh default-build\n  -\n    matrix:\n      only:\n        - image: Visual Studio 2017\n    build_script:\n      - ps: .\\run.ps1 default-build\nartifacts:\n  - path: 'artifacts\\build\\*.nupkg'\n    name: MyGet\ndeploy:\n  - provider: Environment\n    name: MyGet\n    artifact: 'artifacts\\build\\*.nupkg'\n    on:\n      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\nimage:\n- Ubuntu\n- Visual Studio 2017\n"
  },
  {
    "path": "build/dependencies.props",
    "content": "﻿<Project>\n\n  <PropertyGroup>\n    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Platform Packages\">\n    <MicrosoftNETCoreApp21PackageVersion>2.1.1</MicrosoftNETCoreApp21PackageVersion>\n    <NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"AspNetCore Packages\">\n    <MicrosoftAspNetCoreIdentityPackageVersion>2.1.3</MicrosoftAspNetCoreIdentityPackageVersion>\n    <MicrosoftEntityFrameworkCorePackageVersion>2.1.2</MicrosoftEntityFrameworkCorePackageVersion>\n    <MicrosoftEntityFrameworkCoreSpecificationTestsPackageVersion>2.1.2</MicrosoftEntityFrameworkCoreSpecificationTestsPackageVersion>\n    <MicrosoftExtensionsConfigurationPackageVersion>2.1.1</MicrosoftExtensionsConfigurationPackageVersion>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Third-Party Packages\">\n    <MongoDBDriverPackageVersion>2.7.3</MongoDBDriverPackageVersion>\n  </PropertyGroup>\n\n  <PropertyGroup Label=\"Test Packages\">\n    <MicrosoftNETTestSdkPackageVersion>15.9.0</MicrosoftNETTestSdkPackageVersion>\n    <MoqPackageVersion>4.10.1</MoqPackageVersion>\n    <XunitPackageVersion>2.4.1</XunitPackageVersion>\n    <XunitRunnerConsolePackageVersion>2.4.1</XunitRunnerConsolePackageVersion>\n    <XunitRunnerVisualstudioPackageVersion>2.4.1</XunitRunnerVisualstudioPackageVersion>\n  </PropertyGroup>\n\n  <Import Project=\"$(DotNetPackageVersionPropsPath)\" Condition=\" '$(DotNetPackageVersionPropsPath)' != '' \" />\n\n</Project>"
  },
  {
    "path": "build/repo.beforecommon.props",
    "content": "<Project>\n  <PropertyGroup>\n    <!-- for local builds, always use the time-based build number -->\n    <IncrementalVersion>true</IncrementalVersion>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "build/repo.props",
    "content": "<Project>\n\n  <PropertyGroup>\n    <CoreOnly Condition=\"'$(CoreOnly)' == ''\">False</CoreOnly>\n\n    <DisablePackageReferenceRestrictions>true</DisablePackageReferenceRestrictions>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <ExcludeFromPack Include=\"$(RepositoryRoot)src\\*Sample*\\*.csproj\" />\n    <ExcludeFromPack Include=\"$(RepositoryRoot)src\\*Tests*\\*.csproj\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "build/repo.targets",
    "content": "<Project>\n  <Target Name=\"_FilterTestProjects\" BeforeTargets=\"TestProjects\">\n    <ItemGroup Condition=\"'$(TestFilter)' != ''\">\n      <ProjectsToTest Remove=\"@(ProjectsToTest)\"/>\n      <ProjectsToTest Include=\"$(RepositoryRoot)test\\*$(TestFilter)*\\*.csproj\" Exclude=\"@(ExcludeFromTest)\" />\n    </ItemGroup>\n\n    <Error Text=\"Could not find test projects to run\" Condition=\"@(ProjectsToTest->Count()) == 0\" />\n  </Target>\n\n  <Target Name=\"SetupTests\" BeforeTargets=\"TestProjects\">\n    <Exec Condition=\"'$(APPVEYOR)' != 'true' AND '$(TRAVIS)' != 'true'\"\n          Command=\"docker-compose.exe -p &quot;efcore-mongodb&quot; -f &quot;$(MSBuildThisFileDirectory)\\..\\docker-compose.yml&quot; up -d\" />\n  </Target>\n\n  <Target Name=\"TearDownTests\" AfterTargets=\"TestProjects\">\n    <Exec  Condition=\"'$(APPVEYOR)' != 'true' AND '$(TRAVIS)' != 'true'\"\n        Command=\"docker-compose.exe -p &quot;efcore-mongodb&quot; -f &quot;$(MSBuildThisFileDirectory)\\..\\docker-compose.yml&quot; down\" />\n  </Target>\n</Project>\n"
  },
  {
    "path": "build/sources.props",
    "content": "<Project>\n  <Import Project=\"$(DotNetRestoreSourcePropsPath)\" Condition=\"'$(DotNetRestoreSourcePropsPath)' != ''\"/>\n\n  <PropertyGroup Label=\"RestoreSources\">\n    <RestoreSources>$(DotNetRestoreSources)</RestoreSources>\n    <RestoreSources Condition=\"'$(DotNetBuildOffline)' != 'true' AND '$(AspNetUniverseBuildOffline)' != 'true' \">\n      $(RestoreSources);\n      https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;\n      https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;\n      https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;\n      https://www.myget.org/F/efcore-mongodb/api/v3/index.json;\n    </RestoreSources>\n    <RestoreSources Condition=\"'$(DotNetBuildOffline)' != 'true'\">\n      $(RestoreSources);\n      https://api.nuget.org/v3/index.json;\n    </RestoreSources>\n  </PropertyGroup>\n</Project>"
  },
  {
    "path": "build.cmd",
    "content": "@ECHO OFF\nPowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command \"[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE\"\n"
  },
  {
    "path": "build.sh",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\n# Call \"sync\" between \"chmod\" and execution to prevent \"text file busy\" error in Docker (aufs)\nchmod +x \"$DIR/run.sh\"; sync\n\"$DIR/run.sh\" default-build \"$@\"\n"
  },
  {
    "path": "docker-compose.dcproj",
    "content": "<Project Sdk=\"Microsoft.Docker.Sdk\">\n  <PropertyGroup Label=\"Globals\">\n    <ProjectVersion>2.1</ProjectVersion>\n    <DockerTargetOS>Linux</DockerTargetOS>\n    <ProjectGuid>04ceb217-71e2-4dbd-b35a-737ee7d258b8</ProjectGuid>\n    <DockerLaunchAction>LaunchBrowser</DockerLaunchAction>\n    <DockerServiceUrl>{Scheme}://localhost:{ServicePort}</DockerServiceUrl>\n    <DockerServiceName>blueshift.authoring</DockerServiceName>\n  </PropertyGroup>\n  <ItemGroup>\n    <None Include=\"docker-compose.yml\" />\n    <None Include=\".dockerignore\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "docker-compose.yml",
    "content": "version: '3.4'\n\nservices:\n  mongo-efcore:\n    image: mongo:4.1.2-xenial\n    restart: always\n    ports:\n      - 27017:27017\n  mongo-efcore-express:\n    image: mongo-express\n    restart: always\n    ports:\n      - 27027:8081\n    environment:\n      ME_CONFIG_MONGODB_SERVER: mongo-efcore\n"
  },
  {
    "path": "korebuild-lock.txt",
    "content": "version:2.1.3-rtm-15802\ncommithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a"
  },
  {
    "path": "korebuild.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/aspnet/BuildTools/release/2.1/tools/korebuild.schema.json\",\n    \"channel\": \"release/2.1\"\n}"
  },
  {
    "path": "run.cmd",
    "content": "@ECHO OFF\nPowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command \"[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE\"\n"
  },
  {
    "path": "run.ps1",
    "content": "#!/usr/bin/env powershell\n#requires -version 4\n\n<#\n.SYNOPSIS\nExecutes KoreBuild commands.\n.DESCRIPTION\nDownloads korebuild if required. Then executes the KoreBuild command. To see available commands, execute with `-Command help`.\n.PARAMETER Command\nThe KoreBuild command to run.\n.PARAMETER Path\nThe folder to build. Defaults to the folder containing this script.\n.PARAMETER Channel\nThe channel of KoreBuild to download. Overrides the value from the config file.\n.PARAMETER DotNetHome\nThe directory where .NET Core tools will be stored.\n.PARAMETER ToolsSource\nThe base url where build tools can be downloaded. Overrides the value from the config file.\n.PARAMETER Update\nUpdates KoreBuild to the latest version even if a lock file is present.\n.PARAMETER Reinstall\nRe-installs KoreBuild\n.PARAMETER ConfigFile\nThe path to the configuration file that stores values. Defaults to korebuild.json.\n.PARAMETER ToolsSourceSuffix\nThe Suffix to append to the end of the ToolsSource. Useful for query strings in blob stores.\n.PARAMETER CI\nSets up CI specific settings and variables.\n.PARAMETER Arguments\nArguments to be passed to the command\n.NOTES\nThis function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be.\nWhen the lockfile is not present, KoreBuild will create one using latest available version from $Channel.\nThe $ConfigFile is expected to be an JSON file. It is optional, and the configuration values in it are optional as well. Any options set\nin the file are overridden by command line parameters.\n.EXAMPLE\nExample config file:\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/aspnet/BuildTools/dev/tools/korebuild.schema.json\",\n  \"channel\": \"dev\",\n  \"toolsSource\": \"https://aspnetcore.blob.core.windows.net/buildtools\"\n}\n```\n#>\n[CmdletBinding(PositionalBinding = $false)]\nparam(\n    [Parameter(Mandatory = $true, Position = 0)]\n    [string]$Command,\n    [string]$Path = $PSScriptRoot,\n    [Alias('c')]\n    [string]$Channel,\n    [Alias('d')]\n    [string]$DotNetHome,\n    [Alias('s')]\n    [string]$ToolsSource,\n    [Alias('u')]\n    [switch]$Update,\n    [switch]$Reinstall,\n    [string]$ToolsSourceSuffix,\n    [string]$ConfigFile = $null,\n    [switch]$CI,\n    [Parameter(ValueFromRemainingArguments = $true)]\n    [string[]]$Arguments\n)\n\nSet-StrictMode -Version 2\n$ErrorActionPreference = 'Stop'\n\n#\n# Functions\n#\n\nfunction Get-KoreBuild {\n\n    $lockFile = Join-Path $Path 'korebuild-lock.txt'\n\n    if (!(Test-Path $lockFile) -or $Update) {\n        Get-RemoteFile \"$ToolsSource/korebuild/channels/$Channel/latest.txt\" $lockFile $ToolsSourceSuffix\n    }\n\n    $version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1\n    if (!$version) {\n        Write-Error \"Failed to parse version from $lockFile. Expected a line that begins with 'version:'\"\n    }\n    $version = $version.TrimStart('version:').Trim()\n    $korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version)\n\n    if ($Reinstall -and (Test-Path $korebuildPath)) {\n        Remove-Item -Force -Recurse $korebuildPath\n    }\n\n    if (!(Test-Path $korebuildPath)) {\n        Write-Host -ForegroundColor Magenta \"Downloading KoreBuild $version\"\n        New-Item -ItemType Directory -Path $korebuildPath | Out-Null\n        $remotePath = \"$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip\"\n\n        try {\n            $tmpfile = Join-Path ([IO.Path]::GetTempPath()) \"KoreBuild-$([guid]::NewGuid()).zip\"\n            Get-RemoteFile $remotePath $tmpfile $ToolsSourceSuffix\n            if (Get-Command -Name 'Microsoft.PowerShell.Archive\\Expand-Archive' -ErrorAction Ignore) {\n                # Use built-in commands where possible as they are cross-plat compatible\n                Microsoft.PowerShell.Archive\\Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath\n            }\n            else {\n                # Fallback to old approach for old installations of PowerShell\n                Add-Type -AssemblyName System.IO.Compression.FileSystem\n                [System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath)\n            }\n        }\n        catch {\n            Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore\n            throw\n        }\n        finally {\n            Remove-Item $tmpfile -ErrorAction Ignore\n        }\n    }\n\n    return $korebuildPath\n}\n\nfunction Join-Paths([string]$path, [string[]]$childPaths) {\n    $childPaths | ForEach-Object { $path = Join-Path $path $_ }\n    return $path\n}\n\nfunction Get-RemoteFile([string]$RemotePath, [string]$LocalPath, [string]$RemoteSuffix) {\n    if ($RemotePath -notlike 'http*') {\n        Copy-Item $RemotePath $LocalPath\n        return\n    }\n\n    $retries = 10\n    while ($retries -gt 0) {\n        $retries -= 1\n        try {\n            Invoke-WebRequest -UseBasicParsing -Uri $($RemotePath + $RemoteSuffix) -OutFile $LocalPath\n            return\n        }\n        catch {\n            Write-Verbose \"Request failed. $retries retries remaining\"\n        }\n    }\n\n    Write-Error \"Download failed: '$RemotePath'.\"\n}\n\n#\n# Main\n#\n\n# Load configuration or set defaults\n\n$Path = Resolve-Path $Path\nif (!$ConfigFile) { $ConfigFile = Join-Path $Path 'korebuild.json' }\n\nif (Test-Path $ConfigFile) {\n    try {\n        $config = Get-Content -Raw -Encoding UTF8 -Path $ConfigFile | ConvertFrom-Json\n        if ($config) {\n            if (!($Channel) -and (Get-Member -Name 'channel' -InputObject $config)) { [string] $Channel = $config.channel }\n            if (!($ToolsSource) -and (Get-Member -Name 'toolsSource' -InputObject $config)) { [string] $ToolsSource = $config.toolsSource}\n        }\n    }\n    catch {\n        Write-Warning \"$ConfigFile could not be read. Its settings will be ignored.\"\n        Write-Warning $Error[0]\n    }\n}\n\nif (!$DotNetHome) {\n    $DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } `\n        elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} `\n        elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}`\n        else { Join-Path $PSScriptRoot '.dotnet'}\n}\n\nif (!$Channel) { $Channel = 'dev' }\nif (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' }\n\n# Execute\n\n$korebuildPath = Get-KoreBuild\nImport-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1')\n\ntry {\n    Set-KoreBuildSettings -ToolsSource $ToolsSource -DotNetHome $DotNetHome -RepoPath $Path -ConfigFile $ConfigFile -CI:$CI\n    Invoke-KoreBuildCommand $Command @Arguments\n}\nfinally {\n    Remove-Module 'KoreBuild' -ErrorAction Ignore\n}"
  },
  {
    "path": "run.sh",
    "content": "#!/usr/bin/env bash\n\nset -euo pipefail\n\n#\n# variables\n#\n\nRESET=\"\\033[0m\"\nRED=\"\\033[0;31m\"\nYELLOW=\"\\033[0;33m\"\nMAGENTA=\"\\033[0;95m\"\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n[ -z \"${DOTNET_HOME:-}\" ] && DOTNET_HOME=\"$HOME/.dotnet\"\nverbose=false\nupdate=false\nreinstall=false\nrepo_path=\"$DIR\"\nchannel=''\ntools_source=''\ntools_source_suffix=''\nci=false\n\n#\n# Functions\n#\n__usage() {\n    echo \"Usage: $(basename \"${BASH_SOURCE[0]}\") command [options] [[--] <Arguments>...]\"\n    echo \"\"\n    echo \"Arguments:\"\n    echo \"    command                The command to be run.\"\n    echo \"    <Arguments>...         Arguments passed to the command. Variable number of arguments allowed.\"\n    echo \"\"\n    echo \"Options:\"\n    echo \"    --verbose                                             Show verbose output.\"\n    echo \"    -c|--channel <CHANNEL>                                The channel of KoreBuild to download. Overrides the value from the config file..\"\n    echo \"    --config-file <FILE>                                  The path to the configuration file that stores values. Defaults to korebuild.json.\"\n    echo \"    -d|--dotnet-home <DIR>                                The directory where .NET Core tools will be stored. Defaults to '\\$DOTNET_HOME' or '\\$HOME/.dotnet.\"\n    echo \"    --path <PATH>                                         The directory to build. Defaults to the directory containing the script.\"\n    echo \"    -s|--tools-source|-ToolsSource <URL>                  The base url where build tools can be downloaded. Overrides the value from the config file.\"\n    echo \"    --tools-source-suffix|-ToolsSourceSuffix <SUFFIX>     The suffix to append to tools-source. Useful for query strings.\"\n    echo \"    -u|--update                                           Update to the latest KoreBuild even if the lock file is present.\"\n    echo \"    --reinstall                                           Reinstall KoreBuild.\"\n    echo \"    --ci                                                  Apply CI specific settings and environment variables.\"\n    echo \"\"\n    echo \"Description:\"\n    echo \"    This function will create a file \\$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be.\"\n    echo \"    When the lockfile is not present, KoreBuild will create one using latest available version from \\$channel.\"\n\n    if [[ \"${1:-}\" != '--no-exit' ]]; then\n        exit 2\n    fi\n}\n\nget_korebuild() {\n    local version\n    local lock_file=\"$repo_path/korebuild-lock.txt\"\n    if [ ! -f \"$lock_file\" ] || [ \"$update\" = true ]; then\n        __get_remote_file \"$tools_source/korebuild/channels/$channel/latest.txt\" \"$lock_file\" \"$tools_source_suffix\"\n    fi\n    version=\"$(grep 'version:*' -m 1 \"$lock_file\")\"\n    if [[ \"$version\" == '' ]]; then\n        __error \"Failed to parse version from $lock_file. Expected a line that begins with 'version:'\"\n        return 1\n    fi\n    version=\"$(echo \"${version#version:}\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\"\n    local korebuild_path=\"$DOTNET_HOME/buildtools/korebuild/$version\"\n\n    if [ \"$reinstall\" = true ] && [ -d \"$korebuild_path\" ]; then\n        rm -rf \"$korebuild_path\"\n    fi\n\n    {\n        if [ ! -d \"$korebuild_path\" ]; then\n            mkdir -p \"$korebuild_path\"\n            local remote_path=\"$tools_source/korebuild/artifacts/$version/korebuild.$version.zip\"\n            tmpfile=\"$(mktemp)\"\n            echo -e \"${MAGENTA}Downloading KoreBuild ${version}${RESET}\"\n            if __get_remote_file \"$remote_path\" \"$tmpfile\" \"$tools_source_suffix\"; then\n                unzip -q -d \"$korebuild_path\" \"$tmpfile\"\n            fi\n            rm \"$tmpfile\" || true\n        fi\n\n        source \"$korebuild_path/KoreBuild.sh\"\n    } || {\n        if [ -d \"$korebuild_path\" ]; then\n            echo \"Cleaning up after failed installation\"\n            rm -rf \"$korebuild_path\" || true\n        fi\n        return 1\n    }\n}\n\n__error() {\n    echo -e \"${RED}error: $*${RESET}\" 1>&2\n}\n\n__warn() {\n    echo -e \"${YELLOW}warning: $*${RESET}\"\n}\n\n__machine_has() {\n    hash \"$1\" > /dev/null 2>&1\n    return $?\n}\n\n__get_remote_file() {\n    local remote_path=$1\n    local local_path=$2\n    local remote_path_suffix=$3\n\n    if [[ \"$remote_path\" != 'http'* ]]; then\n        cp \"$remote_path\" \"$local_path\"\n        return 0\n    fi\n\n    local failed=false\n    if __machine_has wget; then\n        wget --tries 10 --quiet -O \"$local_path\" \"${remote_path}${remote_path_suffix}\" || failed=true\n    else\n        failed=true\n    fi\n\n    if [ \"$failed\" = true ] && __machine_has curl; then\n        failed=false\n        curl --retry 10 -sSL -f --create-dirs -o \"$local_path\" \"${remote_path}${remote_path_suffix}\" || failed=true\n    fi\n\n    if [ \"$failed\" = true ]; then\n        __error \"Download failed: $remote_path\" 1>&2\n        return 1\n    fi\n}\n\n#\n# main\n#\n\ncommand=\"${1:-}\"\nshift\n\nwhile [[ $# -gt 0 ]]; do\n    case $1 in\n        -\\?|-h|--help)\n            __usage --no-exit\n            exit 0\n            ;;\n        -c|--channel|-Channel)\n            shift\n            channel=\"${1:-}\"\n            [ -z \"$channel\" ] && __usage\n            ;;\n        --config-file|-ConfigFile)\n            shift\n            config_file=\"${1:-}\"\n            [ -z \"$config_file\" ] && __usage\n            if [ ! -f \"$config_file\" ]; then\n                __error \"Invalid value for --config-file. $config_file does not exist.\"\n                exit 1\n            fi\n            ;;\n        -d|--dotnet-home|-DotNetHome)\n            shift\n            DOTNET_HOME=\"${1:-}\"\n            [ -z \"$DOTNET_HOME\" ] && __usage\n            ;;\n        --path|-Path)\n            shift\n            repo_path=\"${1:-}\"\n            [ -z \"$repo_path\" ] && __usage\n            ;;\n        -s|--tools-source|-ToolsSource)\n            shift\n            tools_source=\"${1:-}\"\n            [ -z \"$tools_source\" ] && __usage\n            ;;\n        --tools-source-suffix|-ToolsSourceSuffix)\n            shift\n            tools_source_suffix=\"${1:-}\"\n            [ -z \"$tools_source_suffix\" ] && __usage\n            ;;\n        -u|--update|-Update)\n            update=true\n            ;;\n        --reinstall|-[Rr]einstall)\n            reinstall=true\n            ;;\n        --ci)\n            ci=true\n            ;;\n        --verbose|-Verbose)\n            verbose=true\n            ;;\n        --)\n            shift\n            break\n            ;;\n        *)\n            break\n            ;;\n    esac\n    shift\ndone\n\nif ! __machine_has unzip; then\n    __error 'Missing required command: unzip'\n    exit 1\nfi\n\nif ! __machine_has curl && ! __machine_has wget; then\n    __error 'Missing required command. Either wget or curl is required.'\n    exit 1\nfi\n\n[ -z \"${config_file:-}\" ] && config_file=\"$repo_path/korebuild.json\"\nif [ -f \"$config_file\" ]; then\n    if __machine_has jq ; then\n        if jq '.' \"$config_file\" >/dev/null ; then\n            config_channel=\"$(jq -r 'select(.channel!=null) | .channel' \"$config_file\")\"\n            config_tools_source=\"$(jq -r 'select(.toolsSource!=null) | .toolsSource' \"$config_file\")\"\n        else\n            __warn \"$config_file is invalid JSON. Its settings will be ignored.\"\n        fi\n    elif __machine_has python ; then\n        if python -c \"import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))\" >/dev/null ; then\n            config_channel=\"$(python -c \"import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')\")\"\n            config_tools_source=\"$(python -c \"import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')\")\"\n        else\n            __warn \"$config_file is invalid JSON. Its settings will be ignored.\"\n        fi\n    else\n        __warn 'Missing required command: jq or pyton. Could not parse the JSON file. Its settings will be ignored.'\n    fi\n\n    [ ! -z \"${config_channel:-}\" ] && channel=\"$config_channel\"\n    [ ! -z \"${config_tools_source:-}\" ] && tools_source=\"$config_tools_source\"\nfi\n\n[ -z \"$channel\" ] && channel='dev'\n[ -z \"$tools_source\" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools'\n\nget_korebuild\nset_korebuildsettings \"$tools_source\" \"$DOTNET_HOME\" \"$repo_path\" \"$config_file\" \"$ci\"\ninvoke_korebuild_command \"$command\" \"$@\""
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/AbstractBaseClassConvention.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Attributes;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <inheritdoc cref=\"ConventionBase\" />\n    /// <inheritdoc cref=\"IClassMapConvention\" />\n    /// <summary>\n    /// A convention that specifies that a discriminator is required when the given type is abstract.\n    /// </summary>\n    public class AbstractBaseClassConvention : BsonClassMapAttributeConvention<BsonKnownTypesAttribute>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Process the conventions on <paramref name=\"classMap\"/> according to the given <paramref name=\"attribute\"/>.\n        /// </summary>\n        /// <param name=\"classMap\">The <see cref=\"BsonClassMap\"/> to which the conventions will be assigned.</param>\n        /// <param name=\"attribute\">The <see cref=\"BsonKnownTypesAttribute\" /> that defines the convention.</param>\n        protected override void Apply(BsonClassMap classMap, BsonKnownTypesAttribute attribute)\n        {\n            Check.NotNull(classMap, nameof(classMap));\n            if (!classMap.DiscriminatorIsRequired)\n            {\n                classMap.SetDiscriminatorIsRequired(classMap.ClassType.IsAbstract);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/BsonClassMapAttributeConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <inheritdoc cref=\"ConventionBase\" />\n    /// <inheritdoc cref=\"IClassMapConvention\" />\n    /// <summary>\n    /// Base class for attribute-based <see cref=\"T:MongoDB.Bson.Serialization.BsonMemberMap\" /> convention processing.\n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The type of attribute to process.</typeparam>\n    public abstract class BsonClassMapAttributeConvention<TAttribute> : ConventionBase, IClassMapConvention\n        where TAttribute : Attribute\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BsonClassMapAttributeConvention{TAttribute}\"/>.\n        /// </summary>\n        protected BsonClassMapAttributeConvention()\n            : base(Regex.Replace(typeof(TAttribute).Name, \"Attribute$\", \"\"))\n        {\n        }\n\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Processes each <typeparamref name=\"TAttribute\"/> defined on the given <paramref name=\"classMap\"/>\n        /// member info and \n        /// </summary>\n        /// <param name=\"classMap\">The <see cref=\"BsonMemberMap\"/> to </param>\n        public virtual void Apply(BsonClassMap classMap)\n        {\n            Check.NotNull(classMap, nameof(classMap));\n            IEnumerable<TAttribute> memberMapAttributes = classMap\n                .ClassType\n                .GetCustomAttributes<TAttribute>();\n            foreach (TAttribute attribute in memberMapAttributes)\n            {\n                Apply(classMap, attribute);\n            }\n        }\n\n        /// <summary>\n        /// Process the conventions on <paramref name=\"classMap\"/> according to the given <paramref name=\"attribute\"/>.\n        /// </summary>\n        /// <param name=\"classMap\">The <see cref=\"BsonClassMap\"/> to which the conventions will be assigned.</param>\n        /// <param name=\"attribute\">The <typeparamref name=\"TAttribute\" /> that defines the convention.</param>\n        protected abstract void Apply([NotNull] BsonClassMap classMap, [NotNull] TAttribute attribute);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/BsonMemberMapAttributeConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing System.Text.RegularExpressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <summary>\n    /// Base class for attribute-based <see cref=\"BsonMemberMap\"/> convention processing.\n    /// </summary>\n    /// <typeparam name=\"TAttribute\">The type of attribute to process.</typeparam>\n    public abstract class BsonMemberMapAttributeConvention<TAttribute> : ConventionBase, IMemberMapConvention\n        where TAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"BsonMemberMapAttributeConvention{TAttribute}\"/>.\n        /// </summary>\n        protected BsonMemberMapAttributeConvention()\n            : base(Regex.Replace(typeof(TAttribute).Name, \"Attribute$\", \"\"))\n        {\n        }\n\n        /// <summary>\n        /// Processes each <typeparamref name=\"TAttribute\"/> defined on the given <paramref name=\"memberMap\"/>\n        /// member info and \n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\"/> to </param>\n        public virtual void Apply([NotNull] BsonMemberMap memberMap)\n        {\n            Check.NotNull(memberMap, nameof(memberMap));\n            IEnumerable<TAttribute> memberMapAttributes = memberMap.MemberInfo\n                .GetCustomAttributes<TAttribute>();\n            foreach (TAttribute attribute in memberMapAttributes)\n            {\n                Apply(memberMap, attribute);\n            }\n        }\n\n        /// <summary>\n        /// Process the conventions on <paramref name=\"memberMap\"/> according to the given <paramref name=\"attribute\"/>.\n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\"/> to which the conventions will be assigned.</param>\n        /// <param name=\"attribute\">The <typeparamref name=\"TAttribute\" /> that defines the convention.</param>\n        protected abstract void Apply([NotNull] BsonMemberMap memberMap, [NotNull] TAttribute attribute);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/IgnoreEmptyEnumerablesConvention.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Text.RegularExpressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <summary>\n    /// A convention that ignores empty <see cref=\"IEnumerable\"/> instances when serializing Bson documents. \n    /// </summary>\n    public class IgnoreEmptyEnumerablesConvention : ConventionBase, IMemberMapConvention\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IgnoreEmptyEnumerablesConvention\"/> class.\n        /// </summary>\n        public IgnoreEmptyEnumerablesConvention()\n            : base(Regex.Replace(nameof(IgnoreEmptyEnumerablesConvention), \"Convention$\", \"\"))\n        {\n        }\n\n        /// <summary>\n        /// Applies the Ignore Empty Enumerables convention to the given <paramref name=\"memberMap\"/>.\n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\" /> to which the convention will be applied.</param>\n        public virtual void Apply([NotNull] BsonMemberMap memberMap)\n        {\n            Check.NotNull(memberMap, nameof(memberMap));\n            if (memberMap.MemberType.TryGetSequenceType() != null)\n            {\n                memberMap.SetShouldSerializeMethod(@object =>\n                    {\n                        object value = memberMap.Getter(@object);\n                        return (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;\n                    });\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/IgnoreNullOrEmptyStringsConvention.cs",
    "content": "﻿using System.Text.RegularExpressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <summary>\n    /// Instructs the MongoDb C# driver to ignore null, empty, or default values of <see cref=\"string\"/> properties.\n    /// </summary>\n    public class IgnoreNullOrEmptyStringsConvention : ConventionBase, IMemberMapConvention\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IgnoreNullOrEmptyStringsConvention\"/> class.\n        /// </summary>\n        public IgnoreNullOrEmptyStringsConvention()\n            : base(Regex.Replace(nameof(IgnoreNullOrEmptyStringsConvention), \"Convention$\", \"\"))\n        {\n        }\n\n        /// <summary>\n        /// Applies the Ignore Null or Empty Strings convention to the given <paramref name=\"memberMap\"/>.\n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\" /> to which the convention will be applied.</param>\n        public virtual void Apply([NotNull] BsonMemberMap memberMap)\n        {\n            Check.NotNull(memberMap, nameof(memberMap));\n            if (memberMap.MemberType == typeof(string))\n            {\n                SetShouldSerializeMethod(memberMap);\n            }\n        }\n\n        private static void SetShouldSerializeMethod(BsonMemberMap memberMap)\n        {\n            var defaultString = memberMap.DefaultValue as string;\n            if (!string.IsNullOrEmpty(defaultString))\n            {\n                ShouldSerializeIfNotDefault(memberMap, defaultString);\n            }\n            else\n            {\n                ShouldSerializeIfNotEmpty(memberMap);\n            }\n        }\n\n        private static void ShouldSerializeIfNotEmpty(BsonMemberMap memberMap)\n            => memberMap.SetShouldSerializeMethod(@object => !string.IsNullOrEmpty(memberMap.Getter(@object) as string));\n\n        private static void ShouldSerializeIfNotDefault(BsonMemberMap memberMap, string defaultString)\n            => memberMap.SetShouldSerializeMethod(@object => !string.Equals(defaultString, memberMap.Getter(@object) as string));\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/KeyAttributeConvention.cs",
    "content": "﻿using System.ComponentModel.DataAnnotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <summary>\n    /// A convention that sets the <see cref=\"BsonClassMap.IdMemberMap\"/> of a <see cref=\"BsonClassMap\"/>\n    /// if that property has been decorated with a <see cref=\"KeyAttribute\"/>.\n    /// </summary>\n    public class KeyAttributeConvention : BsonMemberMapAttributeConvention<KeyAttribute>\n    {\n        /// <summary>\n        /// Applies the Key Attribute convention to the given <paramref name=\"memberMap\"/>.\n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\" /> to which the convention will be applied.</param>\n        /// <param name=\"attribute\">The <see cref=\"KeyAttribute\"/> to apply.</param>\n        protected override void Apply(BsonMemberMap memberMap, KeyAttribute attribute)\n            => Check.NotNull(memberMap, nameof(memberMap))\n                .ClassMap\n                .SetIdMember(memberMap);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/NavigationSrializationMemberMapConvention.cs",
    "content": "﻿using System;\nusing System.ComponentModel.DataAnnotations;\nusing System.Linq;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Attributes;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <inheritdoc cref=\"ConventionBase\" />\n    /// <inheritdoc cref=\"IPostProcessingConvention\" />\n    /// <summary>\n    /// A convention for specifying how to serialize navigation properties.\n    /// </summary>\n    public class NavigationSrializationMemberMapConvention : ConventionBase, IMemberMapConvention\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Checks whether the member map represents a navigation, and sets the member map's serializer.\n        /// </summary>\n        /// <param name=\"memberMap\">The member map.</param>\n        public void Apply(BsonMemberMap memberMap)\n        {\n            Type memberTargetType = Check.NotNull(memberMap, nameof(memberMap)).MemberType.TryGetSequenceType()\n                                    ?? memberMap.MemberType;\n            if (!memberTargetType.IsPrimitive && HasIdMember(memberTargetType))\n            {\n                IBsonSerializer memberMapSerializer = (IBsonSerializer) Activator.CreateInstance(\n                    typeof(NavigationBsonMemberMapSerializer<>).MakeGenericType(memberTargetType),\n                    memberMap);\n                memberMap.SetSerializer(memberMapSerializer);\n            }\n        }\n\n        private bool HasIdMember(Type type)\n            => !type.IsPrimitive\n               && type\n                   .GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance)\n                   .Any(memberInfo => memberInfo.IsDefined(typeof(BsonIdAttribute))\n                                      || memberInfo.IsDefined(typeof(KeyAttribute)));\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Conventions/NotMappedAttributeConvention.cs",
    "content": "﻿using System.ComponentModel.DataAnnotations.Schema;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions\n{\n    /// <summary>\n    /// Marks a <see cref=\"BsonMemberMap\"/> as ignored during serialization.\n    /// </summary>\n    public class NotMappedAttributeConvention : BsonMemberMapAttributeConvention<NotMappedAttribute>\n    {\n        /// <summary>\n        /// Applies the Not Mapped convention to the given <paramref name=\"memberMap\"/>.\n        /// </summary>\n        /// <param name=\"memberMap\">The <see cref=\"BsonMemberMap\" /> to which the convention will be applied.</param>\n        /// <param name=\"attribute\">The <see cref=\"NotMappedAttribute\"/> to apply.</param>\n        protected override void Apply(BsonMemberMap memberMap, NotMappedAttribute attribute)\n            => Check.NotNull(memberMap, nameof(memberMap))\n                .ClassMap\n                .UnmapMember(memberMap.MemberInfo);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/EntityFrameworkConventionPack.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing MongoDB.Bson.Serialization.Conventions;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Provides a set of conventions that configures the MongoDb C# Driver to work appropriately with the EntityFrameworkCore.\n    /// </summary>\n    public class EntityFrameworkConventionPack : ConventionPack\n    {\n        /// <summary>\n        /// Registers the <see cref=\"EntityFrameworkConventionPack\"/>.\n        /// </summary>\n        /// <param name=\"typeFilter\"></param>\n        public static void Register(Func<Type, bool> typeFilter)\n        {\n            ConventionRegistry.Register(\n                \"Blueshift.EntityFrameworkCore.MongoDb.Conventions\",\n                Instance,\n                typeFilter);\n        }\n\n        /// <summary>\n        /// The singleton instance of <see cref=\"EntityFrameworkConventionPack\"/>.\n        /// </summary>\n        public static EntityFrameworkConventionPack Instance { get; } = new EntityFrameworkConventionPack();\n\n        private EntityFrameworkConventionPack()\n        {\n            AddRange(new IConvention[]\n            {\n                new AbstractBaseClassConvention(),\n                new KeyAttributeConvention(),\n                new NavigationSrializationMemberMapConvention(),\n                new NotMappedAttributeConvention()\n            });\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Serialization/BsonSerializerExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Serializers;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization\n{\n    /// <summary>\n    /// Provides extended functionality to <see cref=\"IBsonSerializer\"/>.\n    /// </summary>\n    public static class BsonSerializerExtensions\n    {\n        /// <summary>\n        /// Modifies an instance of <see cref=\"IBsonSerializer\"/> to only use the supplied members when serializing instances.\n        /// </summary>\n        /// <param name=\"bsonSerializer\">The <see cref=\"IBsonSerializer\"/> to modify.</param>\n        /// <param name=\"denormalizedMemberNames\">An <see cref=\"IEnumerable{T}\"/> of <see cref=\"string\"/> that lists the members\n        /// required for serialization.</param>\n        /// <returns>A new instance of <see cref=\"IBsonSerializer\"/> that serializes the information in <paramref name=\"denormalizedMemberNames\"/>.</returns>\n        public static IBsonSerializer AsDenormalizingBsonClassMapSerializer(\n            [NotNull] this IBsonSerializer bsonSerializer,\n            [CanBeNull] IEnumerable<string> denormalizedMemberNames = null)\n        {\n            TypeInfo typeInfo = Check.NotNull(bsonSerializer, nameof(bsonSerializer)).GetType().GetTypeInfo();\n\n            if (bsonSerializer is IChildSerializerConfigurable childSerializerConfigurable)\n            {\n                bsonSerializer = childSerializerConfigurable.WithChildSerializer(\n                    childSerializerConfigurable.ChildSerializer.AsDenormalizingBsonClassMapSerializer(denormalizedMemberNames));\n            }\n            else if (typeInfo.TryGetImplementationType(typeof(ReadOnlyCollectionSerializer<>),\n                         out Type readOnlyCollectionSerializerType)\n                     || typeInfo.TryGetImplementationType(typeof(ReadOnlyCollectionSubclassSerializer<,>),\n                         out readOnlyCollectionSerializerType))\n            {\n                bsonSerializer = (IBsonSerializer) Activator.CreateInstance(readOnlyCollectionSerializerType,\n                    ((IBsonSerializer) readOnlyCollectionSerializerType\n                        .GetProperty(nameof(EnumerableSerializerBase<object[]>.ItemSerializer))\n                        .GetValue(bsonSerializer))\n                    .AsDenormalizingBsonClassMapSerializer(denormalizedMemberNames));\n            }\n            else\n            {\n                BsonClassMap bsonClassMap = BsonClassMap.LookupClassMap(bsonSerializer.ValueType);\n                bsonSerializer = (IBsonSerializer) Activator.CreateInstance(\n                    typeof(DenormalizingBsonClassMapSerializer<>).MakeGenericType(bsonSerializer.ValueType),\n                    bsonClassMap,\n                    denormalizedMemberNames);\n            }\n\n            return bsonSerializer;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Serialization/DenormalizingBsonClassMapSerializer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing JetBrains.Annotations;\nusing MongoDB.Bson;\nusing MongoDB.Bson.IO;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\nusing MongoDB.Bson.Serialization.Serializers;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// A serializer for writing navigation properties used by MongoDB.\n    /// </summary>\n    public class DenormalizingBsonClassMapSerializer<TClass> : BsonClassMapSerializer<TClass>\n    {\n        private readonly BsonClassMap<TClass> _classMap;\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DenormalizingBsonClassMapSerializer{TClass}\"/> class.\n        /// </summary>\n        /// <param name=\"bsonClassMap\">The <see cref=\"BsonClassMap{TClass}\"/> to serialize.</param>\n        /// <param name=\"denormalizedMemberNames\">Optional. An <see cref=\"IEnumerable{T}\"/> of <see cref=\"string\"/> referencing the members\n        /// to be denormalized by this serializer.</param>\n        public DenormalizingBsonClassMapSerializer(\n            [NotNull] BsonClassMap<TClass> bsonClassMap,\n            [CanBeNull] IEnumerable<string> denormalizedMemberNames = null)\n            : base(bsonClassMap)\n        {\n            _classMap = bsonClassMap;\n            DenormalizedMemberMaps = (denormalizedMemberNames ?? new string[0])\n                .Select(bsonClassMap.GetMemberMap)\n                .Except(new[] { null, _classMap.IdMemberMap })\n                .OrderBy(bsonMemberMap => bsonMemberMap.MemberName)\n                .ToList();\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"IEnumerable{T}\"/> of <see cref=\"BsonMemberMap\"/> that this serializer is configured to denormalize.\n        /// </summary>\n        public IEnumerable<BsonMemberMap> DenormalizedMemberMaps { get; }\n\n        /// <inheritdoc />\n        public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TClass value)\n        {\n            IBsonWriter bsonWriter = context.Writer;\n\n            Type actualType = value?.GetType();\n            if (actualType == null)\n            {\n                bsonWriter.WriteNull();\n            }\n            else if (typeof(TClass).IsAssignableFrom(actualType))\n            {\n                SerializeClass(context, args, value);\n            }\n            else\n            {\n                throw new BsonSerializationException(\n                    $\"Expected an object derived from {typeof(TClass).FullName}, but received a value of type {actualType.FullName} instead.\");\n            }\n        }\n\n        private void SerializeClass(BsonSerializationContext context, BsonSerializationArgs args, TClass document)\n        {\n            IBsonWriter bsonWriter = context.Writer;\n\n            bsonWriter.WriteStartDocument();\n\n            SerializeMember(context, document, _classMap.IdMemberMap);\n\n            if (ShouldSerializeDiscriminator(args.NominalType))\n            {\n                SerializeDiscriminator(context, args.NominalType, document);\n            }\n\n            foreach (BsonMemberMap memberMap in DenormalizedMemberMaps)\n            {\n                SerializeMember(context, document, memberMap);\n            }\n\n            bsonWriter.WriteEndDocument();\n        }\n\n        private void SerializeMember(BsonSerializationContext context, TClass document, BsonMemberMap memberMap)\n        {\n            IBsonWriter bsonWriter = context.Writer;\n            object value = memberMap.Getter(document);\n\n            if (memberMap.ShouldSerialize(document, value))\n            {\n                bsonWriter.WriteName(memberMap.ElementName);\n                memberMap.GetSerializer().Serialize(context, value);\n            }\n        }\n\n        private bool ShouldSerializeDiscriminator(Type nominalType)\n            => (nominalType != _classMap.ClassType || _classMap.DiscriminatorIsRequired || _classMap.HasRootClass) && !_classMap.IsAnonymous;\n\n        private void SerializeDiscriminator(BsonSerializationContext context, Type nominalType, object obj)\n        {\n            IDiscriminatorConvention discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(_classMap.ClassType);\n            BsonValue discriminator = discriminatorConvention?.GetDiscriminator(nominalType, obj.GetType());\n            if (discriminator != null)\n            {\n                context.Writer.WriteName(discriminatorConvention.ElementName);\n                BsonValueSerializer.Instance.Serialize(context, discriminator);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Serialization/NavigationBsonMemberMapSerializer.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// A serializer for writing navigation properties used by MongoDB.\n    /// </summary>\n    /// <typeparam name=\"TClass\">The type of the member to be serialized by this <see cref=\"NavigationBsonMemberMapSerializer{TClass}\"/>.</typeparam>\n    public class NavigationBsonMemberMapSerializer<TClass> : IBsonSerializer<TClass>\n    {\n        private readonly Lazy<IBsonSerializer> _lazyBsonSerializer;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"NavigationBsonMemberMapSerializer{TClass}\"/> class.\n        /// </summary>\n        /// <param name=\"bsonMemberMap\">The <see cref=\"BsonMemberMap\"/> representing the member to serialize.</param>\n        public NavigationBsonMemberMapSerializer(BsonMemberMap bsonMemberMap)\n        {\n            MemberMap = Check.NotNull(bsonMemberMap, nameof(bsonMemberMap));\n\n            _lazyBsonSerializer = new Lazy<IBsonSerializer>(() =>\n            {\n                IEnumerable<string> denormalizedMemberNames\n                    = bsonMemberMap.MemberInfo\n                          .GetCustomAttribute<DenormalizeAttribute>()\n                          ?.MemberNames\n                      ?? new string[0];\n                return BsonSerializer.LookupSerializer(bsonMemberMap.MemberType)\n                    .AsDenormalizingBsonClassMapSerializer(denormalizedMemberNames);\n            });\n        }\n\n        /// <summary>\n        /// The <see cref=\"BsonMemberMap\"/> representing the member to serialize.\n        /// </summary>\n        public BsonMemberMap MemberMap { get; }\n\n        /// <inheritdoc />\n        TClass IBsonSerializer<TClass>.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)\n            => (TClass) Deserialize(context, args);\n\n        /// <inheritdoc />\n        public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TClass value)\n            => _lazyBsonSerializer.Value.Serialize(context, args, value);\n\n        /// <inheritdoc />\n        public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)\n            => _lazyBsonSerializer.Value.Deserialize(context, args);\n\n        /// <inheritdoc />\n        public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)\n            => _lazyBsonSerializer.Value.Serialize(context, args, value);\n\n        /// <inheritdoc />\n        public Type ValueType => MemberMap.MemberType;\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/DeleteOneModelFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Creates <see cref=\"DeleteOneModel{TEntity}\"/> from a given <see cref=\"IUpdateEntry\"/>.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of entity being added.</typeparam>\n    public class DeleteOneModelFactory<TEntity> : MongoDbWriteModelFactory<TEntity>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbWriteModelFactory{TEntity}\"/> class.\n        /// </summary>\n        /// <param name=\"valueGeneratorSelector\">The <see cref=\"IValueGeneratorSelector\"/> to use for populating concurrency tokens.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> for which this <see cref=\"MongoDbWriteModelFactory{TDocument}\"/> will be used.</param>\n        public DeleteOneModelFactory(\n            [NotNull] IValueGeneratorSelector valueGeneratorSelector,\n            [NotNull] IEntityType entityType)\n            : base(\n                  Check.NotNull(valueGeneratorSelector, nameof(valueGeneratorSelector)),\n                  Check.NotNull(entityType, nameof(entityType)))\n        {\n        }\n\n        /// <summary>\n        /// Creates an <see cref=\"DeleteOneModel{TEntity}\"/> that maps the given <paramref name=\"updateEntry\"/>.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> to map.</param>\n        /// <returns>A new <see cref=\"DeleteOneModel{TEntity}\"/> containing the inserted values represented\n        /// by <paramref name=\"updateEntry\"/>.</returns>\n        public override WriteModel<TEntity> CreateWriteModel(IUpdateEntry updateEntry)\n            => new DeleteOneModel<TEntity>(GetLookupFilter(updateEntry));\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/IMongoDbWriteModelFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Update;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Interface for generating <see cref=\"WriteModel{TEntity}\"/> instances from <see cref=\"IUpdateEntry\"/> instances.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of entity being updated</typeparam>\n    public interface IMongoDbWriteModelFactory<TEntity>\n    {\n        /// <summary>\n        /// Converts an <see cref=\"IUpdateEntry\"/> instance to a <see cref=\"WriteModel{TEntity}\"/> instance.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> entry to convert.</param>\n        /// <returns>A new <see cref=\"WriteModel{TEntity}\"/> that contains the updates in <see cref=\"IUpdateEntry\"/>.</returns>\n        WriteModel<TEntity> CreateWriteModel([NotNull] IUpdateEntry updateEntry);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/IMongoDbWriteModelFactoryCache.cs",
    "content": "﻿using System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Caches <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instances.\n    /// </summary>\n    public interface IMongoDbWriteModelFactoryCache\n    {\n        /// <summary>\n        /// Returns a cached or newly created instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> for the given \n        /// <paramref name=\"entityType\"/> and <paramref name=\"entityState\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">The type of entity being written.</typeparam>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> that contains the entity metadata.</param>\n        /// <param name=\"entityState\">The <see cref=\"EntityState\"/> describing the type of <see cref=\"WriteModel{TEntity}\"/>\n        /// that returned the factory will produce.</param>\n        /// <param name=\"factoryFunc\">A <see cref=\"Func{IEntityType, EntityState, IMongoDbWriteModelFactory}\"/> that can\n        /// be used to create a new factory instance if one has not previously been cached.</param>\n        /// <returns>A new or cached instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/>.</returns>\n        IMongoDbWriteModelFactory<TEntity> GetOrAdd<TEntity>(\n            IEntityType entityType,\n            EntityState entityState,\n            Func<IEntityType, EntityState, IMongoDbWriteModelFactory<TEntity>> factoryFunc);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/IMongoDbWriteModelFactorySelector.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Update;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Interface for selecting an instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/>.\n    /// </summary>\n    public interface IMongoDbWriteModelFactorySelector\n    {\n        /// <summary>\n        /// Select an <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instance for the given <paramref name=\"updateEntry\"/>.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> that the write model factory will be used to translate.</param>\n        /// <typeparam name=\"TEntity\">The type of entity for which to create a <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instance.</typeparam>\n        /// <returns>An instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> that can be used to convert <see cref=\"IUpdateEntry\"/>\n        /// instances to <see cref=\"WriteModel{TDocument}\"/> instances.</returns>\n        IMongoDbWriteModelFactory<TEntity> Select<TEntity>([NotNull] IUpdateEntry updateEntry);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/InsertOneModelFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Creates <see cref=\"T:MongoDB.Driver.InsertOneModel`1\" /> from a given <see cref=\"T:Microsoft.EntityFrameworkCore.Update.IUpdateEntry\" />.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of entity being added.</typeparam>\n    public class InsertOneModelFactory<TEntity> : MongoDbWriteModelFactory<TEntity>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update.MongoDbWriteModelFactory`1\" /> class.\n        /// </summary>\n        /// <param name=\"valueGeneratorSelector\">The <see cref=\"T:Microsoft.EntityFrameworkCore.ValueGeneration.IValueGeneratorSelector\" /> to use for populating concurrency tokens.</param>\n        /// <param name=\"entityType\">The <see cref=\"T:Microsoft.EntityFrameworkCore.Metadata.IEntityType\" /> for which this <see cref=\"T:Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update.MongoDbWriteModelFactory`1\" /> will be used.</param>\n        public InsertOneModelFactory(\n            [NotNull] IValueGeneratorSelector valueGeneratorSelector,\n            [NotNull] IEntityType entityType)\n            : base(\n                  Check.NotNull(valueGeneratorSelector, nameof(valueGeneratorSelector)),\n                  Check.NotNull(entityType, nameof(entityType)))\n        {\n        }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Creates an <see cref=\"T:MongoDB.Driver.InsertOneModel`1\" /> that maps the given <paramref name=\"updateEntry\" />.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"T:Microsoft.EntityFrameworkCore.Update.IUpdateEntry\" /> to map.</param>\n        /// <returns>A new <see cref=\"T:MongoDB.Driver.InsertOneModel`1\" /> containing the inserted values represented\n        /// by <paramref name=\"updateEntry\" />.</returns>\n        public override WriteModel<TEntity> CreateWriteModel(IUpdateEntry updateEntry)\n        {\n            InternalEntityEntry internalEntityEntry = Check.Is<InternalEntityEntry>(updateEntry, nameof(updateEntry));\n            UpdateDbGeneratedProperties(internalEntityEntry);\n            return new InsertOneModel<TEntity>((TEntity)internalEntityEntry.Entity);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/MongoDbWriteModelFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Base class for generating <see cref=\"WriteModel{TEntity}\"/> instances.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of entity to write.</typeparam>\n    public abstract class MongoDbWriteModelFactory<TEntity> : IMongoDbWriteModelFactory<TEntity>\n    {\n        private static readonly MethodInfo GenericEqMethodInfo = MethodHelper\n            .GetGenericMethodDefinition<FilterDefinitionBuilder<TEntity>, object>(\n                filterDefinitionBuilder => filterDefinitionBuilder.Eq(\n                    (Expression<Func<TEntity, object>>) null,\n                    null));\n\n        private readonly IValueGeneratorSelector _valueGeneratorSelector;\n        private readonly IEnumerable<IProperty> _keyProperties;\n        private readonly IEnumerable<IProperty> _dbGeneratedProperties;\n        private readonly IEnumerable<IProperty> _concurrencyProperties;\n        \n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbWriteModelFactory{TEntity}\"/> class.\n        /// </summary>\n        /// <param name=\"valueGeneratorSelector\">The <see cref=\"IValueGeneratorSelector\"/> to use for populating concurrency tokens.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> for which this <see cref=\"MongoDbWriteModelFactory{TDocument}\"/> will be used.</param>\n        protected MongoDbWriteModelFactory(\n            [NotNull] IValueGeneratorSelector valueGeneratorSelector,\n            [NotNull] IEntityType entityType)\n        {\n            _valueGeneratorSelector = Check.NotNull(valueGeneratorSelector, nameof(valueGeneratorSelector));\n            _keyProperties = Check.NotNull(entityType, nameof(entityType)).FindPrimaryKey().Properties;\n            _dbGeneratedProperties = entityType\n                .GetProperties()\n                .Where(property => property.ValueGenerated == ValueGenerated.OnAddOrUpdate)\n                .ToList();\n            _concurrencyProperties = _dbGeneratedProperties\n                .Where(property => property.IsConcurrencyToken)\n                .ToList();\n        }\n\n        /// <summary>\n        /// Converts an <see cref=\"IUpdateEntry\"/> instance to a <see cref=\"WriteModel{TEntity}\"/> instance.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> entry to convert.</param>\n        /// <returns>A new <see cref=\"WriteModel{TEntity}\"/> that contains the updates in <see cref=\"IUpdateEntry\"/>.</returns>\n        public abstract WriteModel<TEntity> CreateWriteModel(IUpdateEntry updateEntry);\n\n        /// <summary>\n        /// Generates a <see cref=\"FilterDefinition{TEntity}\"/> for <paramref name=\"updateEntry\"/>.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> for the document being updated.</param>\n        /// <returns>A new <see cref=\"FilterDefinition{TEntity}\"/> that can matches the document in <paramref name=\"updateEntry\"/>.</returns>\n        protected FilterDefinition<TEntity> GetLookupFilter([NotNull] IUpdateEntry updateEntry)\n        {\n            IEnumerable<IProperty> lookupProperties =\n                Check.NotNull(updateEntry, nameof(updateEntry)).EntityState == EntityState.Added\n                    ? _keyProperties\n                    : _keyProperties.Concat(_concurrencyProperties);\n            IList<FilterDefinition<TEntity>> filterDefinitions = lookupProperties\n                .Select(property => GetPropertyFilterDefinition(\n                    property,\n                    property.IsConcurrencyToken\n                        ? updateEntry.GetOriginalValue(property)\n                        : updateEntry.GetCurrentValue(property)))\n                .DefaultIfEmpty(Builders<TEntity>.Filter.Empty)\n                .ToList();\n            return filterDefinitions.Count > 1\n                ? Builders<TEntity>.Filter.And(filterDefinitions)\n                : filterDefinitions[0];\n        }\n\n        /// <summary>\n        /// Updates the database-generated properties for <paramref name=\"internalEntityEntry\"/>.\n        /// </summary>\n        /// <param name=\"internalEntityEntry\">The <see cref=\"IUpdateEntry\"/> the <see cref=\"IUpdateEntry\"/> representing the document being updated.</param>\n        protected void UpdateDbGeneratedProperties(InternalEntityEntry internalEntityEntry)\n        {\n            var entityEntry = internalEntityEntry.ToEntityEntry();\n            foreach (IProperty property in _dbGeneratedProperties)\n            {\n                ValueGenerator valueGenerator = _valueGeneratorSelector.Select(property, internalEntityEntry.EntityType);\n                object dbGeneratedValue = valueGenerator.Next(entityEntry);\n                internalEntityEntry.SetProperty(property, dbGeneratedValue, true);\n                property.GetSetter().SetClrValue(internalEntityEntry.Entity, dbGeneratedValue);\n            }\n        }\n\n        private FilterDefinition<TEntity> GetPropertyFilterDefinition(\n            IPropertyBase property,\n            object propertyValue)\n        {\n            ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), name: \"entity\");\n            LambdaExpression lambdaExpression = Expression.Lambda(\n                Expression.MakeMemberAccess(parameterExpression, property.PropertyInfo),\n                parameterExpression);\n            return (FilterDefinition<TEntity>)GenericEqMethodInfo\n                .MakeGenericMethod(property.ClrType)\n                .Invoke(Builders<TEntity>.Filter, new[] { lambdaExpression, propertyValue });\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/MongoDbWriteModelFactoryCache.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Caches <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instances.\n    /// </summary>\n    public class MongoDbWriteModelFactoryCache : IMongoDbWriteModelFactoryCache\n    {\n        private readonly ConcurrentDictionary<CacheKey, object> _cache\n            = new ConcurrentDictionary<CacheKey, object>();\n\n        /// <summary>\n        /// Returns a cached or newly created instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> for the given \n        /// <paramref name=\"entityType\"/> and <paramref name=\"entityState\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">The type of entity being written.</typeparam>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> that contains the entity metadata.</param>\n        /// <param name=\"entityState\">The <see cref=\"EntityState\"/> describing the type of <see cref=\"WriteModel{TEntity}\"/>\n        /// that returned the factory will produce.</param>\n        /// <param name=\"factoryFunc\">A <see cref=\"Func{IEntityType, EntityState, IMongoDbWriteModelFactory}\"/> that can\n        /// be used to create a new factory instance if one has not previously been cached.</param>\n        /// <returns>A new or cached instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/>.</returns>\n        public IMongoDbWriteModelFactory<TEntity> GetOrAdd<TEntity>(\n            IEntityType entityType,\n            EntityState entityState,\n            Func<IEntityType, EntityState, IMongoDbWriteModelFactory<TEntity>> factoryFunc)\n            => _cache.GetOrAdd(\n                    new CacheKey(\n                        Check.NotNull(entityType, nameof(entityType)),\n                        entityState,\n                        Check.NotNull(factoryFunc, nameof(factoryFunc))),\n                    cacheKey => cacheKey.FactoryFunc(entityType, entityState))\n                as IMongoDbWriteModelFactory<TEntity>;\n\n        private struct CacheKey : IEquatable<CacheKey>\n        {\n            private readonly IEntityType _entityType;\n            private readonly EntityState _entityState;\n\n            public CacheKey(\n                IEntityType entityType,\n                EntityState entityState,\n                Func<IEntityType, EntityState, object> factoryFunc)\n            {\n                _entityType = entityType;\n                _entityState = entityState;\n                FactoryFunc = factoryFunc;\n            }\n\n            public Func<IEntityType, EntityState, object> FactoryFunc { get; }\n\n            public override bool Equals(object obj)\n                => Equals((CacheKey)obj);\n\n            public bool Equals(CacheKey other)\n                => Equals(_entityType, other._entityType)\n                    && Equals(_entityState, other._entityState);\n\n            public override int GetHashCode()\n            {\n                unchecked\n                {\n                    return (_entityType.GetHashCode() * 492) ^ _entityState.GetHashCode();\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/MongoDbWriteModelFactorySelector.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <summary>\n    /// Selects an instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> for a given <see cref=\"EntityType\"/>.\n    /// </summary>\n    public class MongoDbWriteModelFactorySelector : IMongoDbWriteModelFactorySelector\n    {\n        private readonly IValueGeneratorSelector _valueGeneratorSelector;\n        private readonly IMongoDbWriteModelFactoryCache _mongoDbWriteModelFactoryCache;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IMongoDbWriteModelFactorySelector\"/> class.\n        /// </summary>\n        /// <param name=\"valueGeneratorSelector\">The <see cref=\"IValueGeneratorSelector\"/> to use for populating concurrency tokens.</param>\n        /// <param name=\"mongoDbWriteModelFactoryCache\">A <see cref=\"IMongoDbWriteModelFactoryCache\"/> that can be used to cache the\n        /// factory instances returned by this <see cref=\"IMongoDbWriteModelFactorySelector\"/>.</param>\n        public MongoDbWriteModelFactorySelector(\n            [NotNull] IValueGeneratorSelector valueGeneratorSelector,\n            [NotNull] IMongoDbWriteModelFactoryCache mongoDbWriteModelFactoryCache)\n        {\n            _valueGeneratorSelector = Check.NotNull(valueGeneratorSelector, nameof(valueGeneratorSelector));\n            _mongoDbWriteModelFactoryCache = Check.NotNull(mongoDbWriteModelFactoryCache, nameof(mongoDbWriteModelFactoryCache));\n        }\n\n        /// <summary>\n        /// Select an <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instance for the given <paramref name=\"updateEntry\"/>.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> that the write model factory will be used to translate.</param>\n        /// <typeparam name=\"TEntity\">The type of entity for which to create a <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instance.</typeparam>\n        /// <returns>An instance of <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> that can be used to convert <see cref=\"IUpdateEntry\"/>\n        /// instances to <see cref=\"WriteModel{TDocument}\"/> instances.</returns>\n        public IMongoDbWriteModelFactory<TEntity> Select<TEntity>(IUpdateEntry updateEntry)\n            => _mongoDbWriteModelFactoryCache.GetOrAdd(\n                Check.NotNull(updateEntry, nameof(updateEntry)).EntityType,\n                updateEntry.EntityState,\n                Create<TEntity>);\n\n        private IMongoDbWriteModelFactory<TEntity> Create<TEntity>(\n            [NotNull] IEntityType entityType,\n            EntityState entityState)\n        {\n            Check.NotNull(entityType, nameof(entityType));\n            if (entityState != EntityState.Added &&\n                entityState != EntityState.Modified &&\n                entityState != EntityState.Unchanged &&\n                entityState != EntityState.Deleted)\n            {\n                throw new InvalidOperationException($\"The value provided for entityState must be Added, Modified, Unchanged, or Deleted, but was {entityState}.\");\n            }\n\n            IMongoDbWriteModelFactory<TEntity> mongoDbWriteModelFactory;\n            switch (entityState)\n            {\n                case EntityState.Added:\n                    mongoDbWriteModelFactory = new InsertOneModelFactory<TEntity>(_valueGeneratorSelector, entityType);\n                    break;\n\n                case EntityState.Deleted:\n                    mongoDbWriteModelFactory = new DeleteOneModelFactory<TEntity>(_valueGeneratorSelector, entityType);\n                    break;\n\n                default:\n                    mongoDbWriteModelFactory = new ReplaceOneModelFactory<TEntity>(_valueGeneratorSelector, entityType);\n                    break;\n            }\n            return mongoDbWriteModelFactory;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Adapter/Update/ReplaceOneModelFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Creates <see cref=\"UpdateOneModel{TEntity}\"/> from a given <see cref=\"IUpdateEntry\"/>.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of entity being added.</typeparam>\n    public class ReplaceOneModelFactory<TEntity> : MongoDbWriteModelFactory<TEntity>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ReplaceOneModelFactory{TEntity}\" /> class.\n        /// </summary>\n        /// <param name=\"valueGeneratorSelector\">The <see cref=\"IValueGeneratorSelector\" /> to use for populating\n        /// concurrency tokens.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\" /> for which this\n        /// <see cref=\"ReplaceOneModelFactory{TEntity}\" /> will be used.</param>\n        public ReplaceOneModelFactory(\n            [NotNull] IValueGeneratorSelector valueGeneratorSelector,\n            [NotNull] IEntityType entityType)\n            : base(\n                  Check.NotNull(valueGeneratorSelector, nameof(valueGeneratorSelector)),\n                  Check.NotNull(entityType, nameof(entityType)))\n        {\n        }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Creates an <see cref=\"UpdateOneModel{TEntity}\"/> that maps the given <paramref name=\"updateEntry\"/>.\n        /// </summary>\n        /// <param name=\"updateEntry\">The <see cref=\"IUpdateEntry\"/> to map.</param>\n        /// <returns>A new <see cref=\"UpdateOneModel{TEntity}\"/> containing the inserted values represented\n        /// by <paramref name=\"updateEntry\"/>.</returns>\n        public override WriteModel<TEntity> CreateWriteModel(IUpdateEntry updateEntry)\n        {\n            InternalEntityEntry internalEntityEntry = Check.Is<InternalEntityEntry>(updateEntry, nameof(updateEntry));\n            UpdateDbGeneratedProperties(internalEntityEntry);\n\n            return new ReplaceOneModel<TEntity>(\n                GetLookupFilter(updateEntry),\n                (TEntity)internalEntityEntry.Entity);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Annotations/DenormalizeAttribute.cs",
    "content": "﻿using System;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Annotations\n{\n    /// <summary>\n    /// Declares that a member of a navigation property should be denormalized when serializing the property.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]\n    public class DenormalizeAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DenormalizeAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"memberNames\">The names of sub-document members to denormalize when serializing the parent document.</param>\n        public DenormalizeAttribute(params string[] memberNames)\n        {\n            MemberNames = memberNames ?? new string[0];\n        }\n\n        /// <summary>\n        /// The name of the member to denormalize.\n        /// </summary>\n        public string[] MemberNames { get; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Annotations/MongoCollectionAttribute.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Annotations\n{\n    /// <summary>\n    /// When applied to an entity class, sets the name of MongoDB collection name used to store instances of the entity.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public class MongoCollectionAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoCollectionAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"collectionName\">The MongoDb database name to use with the <see cref=\"Model\"/>.</param>\n        public MongoCollectionAttribute([NotNull] string collectionName)\n        {\n            CollectionName = Check.NotEmpty(collectionName, nameof(collectionName));\n        }\n\n        /// <summary>\n        /// The MongoDb database name to use with the <see cref=\"Model\"/>.\n        /// </summary>\n        public virtual string CollectionName { get; }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Annotations/MongoDatabaseAttribute.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Annotations\n{\n    /// <summary>\n    /// When applied to a <see cref=\"DbContext\"/>, sets the database name to use with the context's <see cref=\"Model\"/>.\n    /// </summary>\n    [AttributeUsage(AttributeTargets.Class)]\n    public class MongoDatabaseAttribute : Attribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDatabaseAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"database\">The MongoDb database name to use with the <see cref=\"Model\"/>.</param>\n        public MongoDatabaseAttribute([NotNull] string database)\n        {\n            Database = Check.NotEmpty(database, nameof(database));\n        }\n\n        /// <summary>\n        /// The MongoDb database name to use with the <see cref=\"Model\"/>.\n        /// </summary>\n        public virtual string Database { get; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Blueshift.EntityFrameworkCore.MongoDB.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  \n  <PropertyGroup>\n    <TargetFrameworks>$(BuildFrameworks)</TargetFrameworks>\n    <Product>Blueshift MongoDb Provider for EntityFrameworkCore</Product>\n    <Description>Blueshift Software MongoDb Provider for Microsoft EntityFramework Core</Description>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Check.cs\" Link=\"Check.cs\" />\n    <Compile Include=\"..\\Shared\\CodeAnnotations.cs\" Link=\"CodeAnnotations.cs\" />\n    <Compile Include=\"..\\Shared\\MemberInfoExtensions.cs\" Link=\"MemberInfoExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\PropertyInfoExtensions.cs\" Link=\"PropertyInfoExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\SharedTypeExtensions.cs\" Link=\"SharedTypeExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\StringBuilderExtensions.cs\" Link=\"StringBuilderExtensions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"$(MicrosoftEntityFrameworkCorePackageVersion)\" NoWarn=\"KRB4002\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration\" Version=\"$(MicrosoftExtensionsConfigurationPackageVersion)\" NoWarn=\"KRB4002\" />\n    <PackageReference Include=\"MongoDB.Driver\" Version=\"$(MongoDBDriverPackageVersion)\" NoWarn=\"KRB4002\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Compile Update=\"Properties\\DocumentDbStrings.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>DocumentDbStrings.tt</DependentUpon>\n    </Compile>\n    <Compile Update=\"Properties\\DocumentDbStrings.Designer.cs\">\n      <DesignTime>True</DesignTime>\n      <AutoGen>True</AutoGen>\n      <DependentUpon>DocumentDbStrings.resx</DependentUpon>\n    </Compile>\n  </ItemGroup>\n\n  <ItemGroup>\n    <EmbeddedResource Update=\"Properties\\DocumentDbStrings.resx\">\n      <Generator>ResXFileCodeGenerator</Generator>\n      <LastGenOutput>DocumentDbStrings.Designer.cs</LastGenOutput>\n    </EmbeddedResource>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"Properties\\DocumentDbStrings.tt\">\n      <Generator>TextTemplatingFileGenerator</Generator>\n      <LastGenOutput>DocumentDbStrings.cs</LastGenOutput>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <Service Include=\"{508349b6-6b84-4df5-91f0-309beebad82d}\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ChangeTracking/MongoDbInternalEntityEntryFactory.cs",
    "content": "﻿using System.Linq;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Storage;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.ChangeTracking\n{\n    /// <inheritdoc />\n    public class MongoDbInternalEntityEntryFactory : InternalEntityEntryFactory\n    {\n        /// <inheritdoc />\n        public override InternalEntityEntry Create(\n            IStateManager stateManager,\n            IEntityType entityType,\n            object entity,\n            in ValueBuffer valueBuffer)\n            => base.Create(\n                stateManager,\n                entityType,\n                entity,\n                valueBuffer.IsEmpty\n                    ? CreateValueBuffer(entityType, entity)\n                    : valueBuffer);\n\n        /// <inheritdoc />\n        public override InternalEntityEntry Create(\n            IStateManager stateManager,\n            IEntityType entityType,\n            object entity)\n            => Create(stateManager, entityType, entity, ValueBuffer.Empty);\n\n        private ValueBuffer CreateValueBuffer(IEntityType entityType, object entity)\n        {\n            object[] values = new object[entityType.PropertyCount()];\n\n            foreach (IProperty property in entityType.GetProperties())\n            {                \n                values[property.GetIndex()] = GetPropertyValue(entity, property);\n            }\n\n            return new ValueBuffer(values);\n        }\n\n        private object GetPropertyValue(object entity, IProperty property)\n        {\n            if (property.IsShadowProperty && property.IsForeignKey())\n            {\n                IForeignKey foreignKey = property.AsProperty().ForeignKeys.First();\n                INavigation navigationProperty = property.DeclaringEntityType == foreignKey.PrincipalEntityType\n                                                 && !foreignKey.IsSelfPrimaryKeyReferencing()\n                    ? foreignKey.PrincipalToDependent\n                    : foreignKey.DependentToPrincipal;\n\n                if (navigationProperty != null)\n                {\n                    entity = navigationProperty.GetGetter().GetClrValue(entity);\n\n                    IEntityType targetEntityType = navigationProperty.GetTargetType();\n                    property = targetEntityType.FindPrimaryKey().Properties.Single();\n                }\n                else\n                {\n                    entity = null;\n                }\n            }\n\n            return entity == null\n                ? null\n                : property.IsShadowProperty\n                    ? entity.GetHashCode()\n                    : property.GetGetter().GetClrValue(entity);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/DbContextOptionsExtensions.cs",
    "content": "﻿//using System;\n//using System.Collections.Generic;\n//using System.Linq;\n//using JetBrains.Annotations;\n//using Microsoft.EntityFrameworkCore.Infrastructure;\n//using Microsoft.EntityFrameworkCore.Utilities;\n\n//// ReSharper disable once CheckNamespace\n//namespace Blueshift.EntityFrameworkCore.MongoDB\n//{\n//    /// <summary>\n//    /// Provides a set of extension methods for instances of the <see cref=\"IDbContextOptions\"/> interface.\n//    /// </summary>\n//    public static class DbContextOptionsExtensions\n//    {\n//        /// <summary>\n//        /// Extracts a single instance of the <typeparamref name=\"TExtension\"/> from this <paramref name=\"dbContextOptions\"/>.\n//        /// </summary>\n//        /// <typeparam name=\"TExtension\">The type of <see cref=\"IDbContextOptionsExtension\"/> to be extracted.</typeparam>\n//        /// <param name=\"dbContextOptions\">An instance of <see cref=\"IDbContextOptions\"/> to search for the given extension.</param>\n//        /// <returns>The single instance of <typeparamref name=\"TExtension\"/> that was found.</returns>\n//        /// <exception cref=\"InvalidOperationException\">\n//        /// Thrown if no instance of the <typeparamref name=\"TExtension\"/> could be found, or if more than one was found.\n//        /// </exception>\n//        public static TExtension Extract<TExtension>([NotNull] this IDbContextOptions dbContextOptions)\n//            where TExtension : IDbContextOptionsExtension\n//        {\n//            Check.NotNull(dbContextOptions, nameof(dbContextOptions));\n\n//            IList<TExtension> extensions = dbContextOptions.Extensions\n//                .OfType<TExtension>()\n//                .ToList();\n\n//            if (extensions.Count == 0)\n//            {\n//                throw new InvalidOperationException($\"No provider has been configured with a {nameof(TExtension)} extension.\");\n//            }\n//            if (extensions.Count > 1)\n//            {\n//                throw new InvalidOperationException($\"Multiple providers have been configured with a {nameof(TExtension)} extension.\");\n//            }\n//            return extensions[index: 0];\n//        }\n//    }\n//}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/DependencyInjection/MongoDbEfServiceCollectionExtensions.cs",
    "content": "﻿using System.ComponentModel;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Bson;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.DependencyInjection\n{\n    /// <summary>\n    /// Extends <see cref=\"IServiceCollection\"/> with methods for use with the MongoDb EntityFrameworkCore provider.\n    /// </summary>\n    public static class MongoDbEfServiceCollectionExtensions\n    {\n        static MongoDbEfServiceCollectionExtensions()\n        {\n            if (!typeof(ObjectId).GetTypeInfo().IsDefined(typeof(TypeConverterAttribute)))\n            {\n                TypeDescriptor.AddAttributes(typeof(ObjectId), new TypeConverterAttribute(typeof(ObjectIdTypeConverter)));\n            }\n\n            EntityFrameworkConventionPack.Register(type => true);\n        }\n\n        /// <summary>\n        /// Populates the given <paramref name=\"serviceCollection\"/> instance with the service dependencies for\n        /// the MongoDb provider for EntityFrameworkCore.\n        /// </summary>\n        /// <param name=\"serviceCollection\">The <see cref=\"IServiceCollection\"/> instance of populate.</param>\n        /// <returns>The <paramref name=\"serviceCollection\"/> populated with the MongoDb EntityFrameworkCore dependencies.</returns>\n        public static IServiceCollection AddEntityFrameworkMongoDb([NotNull] this IServiceCollection serviceCollection)\n        {\n            Check.NotNull(serviceCollection, nameof(serviceCollection));\n\n            var entityFrameworkServicesBuilder = new EntityFrameworkMongoDbServicesBuilder(serviceCollection);\n            entityFrameworkServicesBuilder.TryAddCoreServices();\n            return serviceCollection;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Infrastructure/EntityFrameworkMongoDbServicesBuilder.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Infrastructure\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     A builder API that populates an <see cref=\"IServiceCollection\" /> with a set of EntityFrameworkCore\n    ///     provider dependencies for MongoDb.\n    /// </summary>\n    public class EntityFrameworkMongoDbServicesBuilder : EntityFrameworkServicesBuilder\n    {\n        private static readonly IDictionary<Type, ServiceCharacteristics> RelationalServices\n            = new Dictionary<Type, ServiceCharacteristics>\n            {\n                { typeof(IMongoClient), new ServiceCharacteristics(ServiceLifetime.Scoped) },\n                { typeof(IMongoDbConnection), new ServiceCharacteristics(ServiceLifetime.Scoped) },\n                { typeof(IMongoDbTypeMappingSource), new ServiceCharacteristics(ServiceLifetime.Singleton) },\n                { typeof(MongoDbEntityQueryModelVisitorDependencies), new ServiceCharacteristics(ServiceLifetime.Scoped) },\n                { typeof(MongoDbConventionSetBuilderDependencies), new ServiceCharacteristics(ServiceLifetime.Scoped) }\n            };\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EntityFrameworkMongoDbServicesBuilder\"/> class.\n        /// </summary>\n        /// <param name=\"serviceCollection\">The <see cref=\"IServiceCollection\"/> instance to populate.</param>\n        public EntityFrameworkMongoDbServicesBuilder([NotNull] IServiceCollection serviceCollection) : base(serviceCollection)\n        {\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used directly from your code.\n        /// This API may change or be removed in future releases.\n        /// </summary>\n        protected override ServiceCharacteristics GetServiceCharacteristics(Type serviceType)\n            => RelationalServices.TryGetValue(serviceType, out ServiceCharacteristics characteristics)\n                ? characteristics\n                : base.GetServiceCharacteristics(serviceType);\n\n        /// <summary>\n        /// Registers default implementations of all services not already registered by the provider. Database providers must call\n        /// this method as the last step of service registration--that is, after all provider services have been registered.\n        /// </summary>\n        /// <returns>This builder, such that further calls can be chained.</returns>\n        public override EntityFrameworkServicesBuilder TryAddCoreServices()\n        {\n            TryAdd<IDatabaseProvider, DatabaseProvider<MongoDbOptionsExtension>>();\n            TryAdd<IModelValidator, MongoDbModelValidator>();\n            TryAdd<ITypeMappingSource>(serviceProvider => serviceProvider.GetRequiredService<IMongoDbTypeMappingSource>());\n            TryAdd<IMongoDbTypeMappingSource, MongoDbTypeMappingSource>();\n            TryAdd<IDatabase, MongoDbDatabase>();\n            TryAdd<IDatabaseCreator, MongoDbDatabaseCreator>();\n            TryAdd<IValueGeneratorSelector, MongoDbValueGeneratorSelector>();\n            TryAdd<IConventionSetBuilder, MongoDbConventionSetBuilder>();\n            TryAdd<IQueryContextFactory, MongoDbQueryContextFactory>();\n            TryAdd<IEntityQueryableExpressionVisitorFactory, MongoDbEntityQueryableExpressionVisitorFactory>();\n            TryAdd<IEntityQueryModelVisitorFactory, MongoDbEntityQueryModelVisitorFactory>();\n            TryAdd<IMemberAccessBindingExpressionVisitorFactory, MongoDbMemberAccessBindingExpressionVisitorFactory>();\n            TryAdd<INavigationRewritingExpressionVisitorFactory, DocumentNavigationRewritingExpressionVisitorFactory>();\n\n            TryAddProviderSpecificServices(serviceCollectionMap =>\n            {\n                serviceCollectionMap.TryAddScoped(serviceProvider =>\n                {\n                    MongoDbOptionsExtension extension = serviceProvider\n                        .GetRequiredService<IDbContextOptions>()\n                        .FindExtension<MongoDbOptionsExtension>();\n                    return extension?.MongoClient ?? new MongoClient();\n                });\n                serviceCollectionMap.TryAddScoped<IMongoDbConnection, MongoDbConnection>();\n                serviceCollectionMap.TryAddScoped<IMongoDbDenormalizedCollectionCompensatingVisitorFactory, MongoDbDenormalizedCollectionCompensatingVisitorFactory>();\n                serviceCollectionMap.TryAddScoped<IDocumentQueryExpressionFactory, MongoDbDocumentQueryExpressionFactory>();\n                serviceCollectionMap.TryAddScoped<IMongoDbWriteModelFactoryCache, MongoDbWriteModelFactoryCache>();\n                serviceCollectionMap.TryAddScoped<IMongoDbWriteModelFactorySelector, MongoDbWriteModelFactorySelector>();\n                serviceCollectionMap.TryAddScoped<IEntityLoadInfoFactory, EntityLoadInfoFactory>();\n                serviceCollectionMap.TryAddScoped<IValueBufferFactory, ValueBufferFactory>();\n            });\n\n            ServiceCollectionMap.GetInfrastructure()\n                .AddDependencyScoped<MongoDbConventionSetBuilderDependencies>()\n                .AddDependencyScoped<MongoDbEntityQueryModelVisitorDependencies>();\n\n            return base.TryAddCoreServices();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Infrastructure/MongoDbContextOptionsBuilder.cs",
    "content": "using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Infrastructure\n{\n    /// <summary>\n    ///     <para>\n    ///         Allows MongoDb-specific configuration to be performed on <see cref=\"DbContextOptions\" />.\n    ///     </para>\n    ///     <para>\n    ///         Instances of this class are returned from a call to\n    ///         <see cref=\"MongoDbContextOptionsBuilderExtensions.UseMongoDb(DbContextOptionsBuilder, string, System.Action{MongoDbContextOptionsBuilder})\" />\n    ///         and it is not designed to be directly constructed in your application code.\n    ///     </para>\n    /// </summary>\n    public class MongoDbContextOptionsBuilder\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbContextOptionsBuilder\"/> class.\n        /// </summary>\n        /// <param name=\"optionsBuilder\">The core <see cref=\"DbContextOptionsBuilder\"/> class.</param>\n        public MongoDbContextOptionsBuilder([NotNull] DbContextOptionsBuilder optionsBuilder)\n        {\n            OptionsBuilder = Check.NotNull(optionsBuilder, nameof(optionsBuilder));\n        }\n\n        /// <summary>\n        /// Gets the core <see cref=\"DbContextOptionsBuilder\"/> that supplied to the constructor.\n        /// </summary>\n        protected virtual DbContextOptionsBuilder OptionsBuilder { get; }\n\n        /// <summary>\n        /// Sets the name of the MongoDB database to use with the <see cref=\"DbContext\"/> being configured.\n        /// </summary>\n        /// <param name=\"databaseName\">The name of the MongoDB database instance to use with the current <see cref=\"DbContext\"/>.</param>\n        /// <returns>This <see cref=\"MongoDbOptionsExtension\"/>, so that calls can be chained.</returns>\n        public MongoDbContextOptionsBuilder UseDatabase([NotNull] string databaseName)\n        {\n            Check.NotEmpty(databaseName, nameof(databaseName));\n            MongoDbOptionsExtension extension = CloneExtension();\n            extension.DatabaseName = databaseName;\n            ((IDbContextOptionsBuilderInfrastructure)OptionsBuilder).AddOrUpdateExtension(extension);\n            return this;\n        }\n\n        /// <summary>\n        ///     Clones the <see cref=\"MongoDbOptionsExtension\"/> used to configure this builder.\n        /// </summary>\n        /// <returns>A cloned instance of this builder's <see cref=\"MongoDbOptionsExtension\"/>.</returns>\n        protected virtual MongoDbOptionsExtension CloneExtension()\n            => new MongoDbOptionsExtension(OptionsBuilder.Options.GetExtension<MongoDbOptionsExtension>());\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Infrastructure/MongoDbContextOptionsBuilderExtensions.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Infrastructure\n{\n    /// <summary>\n    /// MongoDb-specific extension methods for <see cref=\"DbContextOptionsBuilder\" />.\n    /// </summary>\n    public static class MongoDbContextOptionsBuilderExtensions\n    {\n        /// <summary>\n        ///     Configures the context to connect to a MongoDb instance.\n        /// </summary>\n        /// <param name=\"optionsBuilder\">The builder being used to configure the context.</param>\n        /// <param name=\"connectionString\">The connection string of the MongoDb instance to connect to.</param>\n        /// <param name=\"mongoDbOptionsAction\">An optional action to allow additional MongoDb-specific configuration.</param>\n        /// <returns> The options builder so that further configuration can be chained. </returns>\n        public static DbContextOptionsBuilder UseMongoDb(\n            [NotNull] this DbContextOptionsBuilder optionsBuilder,\n            [NotNull] string connectionString,\n            [CanBeNull] Action<MongoDbContextOptionsBuilder> mongoDbOptionsAction = null)\n        {\n            Check.NotEmpty(connectionString, nameof(connectionString));\n            return SetupMongoDb(Check.NotNull(optionsBuilder, nameof(optionsBuilder)),\n                extension => extension.ConnectionString = connectionString,\n                mongoDbOptionsAction);\n        }\n\n        /// <summary>\n        ///     Configures the context to connect to a MongoDb instance.\n        /// </summary>\n        /// <param name=\"optionsBuilder\">The builder being used to configure the context.</param>\n        /// <param name=\"mongoClient\">The <see cref=\"IMongoClient\"/> to use when connecting to MongoDb.</param>\n        /// <param name=\"mongoDbOptionsAction\">An optional action to allow additional MongoDb-specific configuration.</param>\n        /// <returns> The options builder so that further configuration can be chained. </returns>\n        public static DbContextOptionsBuilder UseMongoDb(\n            [NotNull] this DbContextOptionsBuilder optionsBuilder,\n            [NotNull] IMongoClient mongoClient,\n            [CanBeNull] Action<MongoDbContextOptionsBuilder> mongoDbOptionsAction = null)\n        {\n            Check.NotNull(mongoClient, nameof(mongoClient));\n            return SetupMongoDb(Check.NotNull(optionsBuilder, nameof(optionsBuilder)),\n                extension => extension.MongoClient = mongoClient,\n                mongoDbOptionsAction);\n        }\n\n        /// <summary>\n        ///     Configures the context to connect to a MongoDb instance.\n        /// </summary>\n        /// <param name=\"optionsBuilder\">The builder being used to configure the context.</param>\n        /// <param name=\"mongoClientSettings\">The <see cref=\"MongoClientSettings\"/> to use when connecting to MongoDb.</param>\n        /// <param name=\"mongoDbOptionsAction\">An optional action to allow additional MongoDb-specific configuration.</param>\n        /// <returns> The options builder so that further configuration can be chained. </returns>\n        public static DbContextOptionsBuilder UseMongoDb(\n            [NotNull] this DbContextOptionsBuilder optionsBuilder,\n            [NotNull] MongoClientSettings mongoClientSettings,\n            [CanBeNull] Action<MongoDbContextOptionsBuilder> mongoDbOptionsAction = null)\n        {\n            Check.NotNull(mongoClientSettings, nameof(mongoClientSettings));\n            return SetupMongoDb(Check.NotNull(optionsBuilder, nameof(optionsBuilder)),\n                extension => extension.MongoClientSettings = mongoClientSettings,\n                mongoDbOptionsAction);\n        }\n\n        /// <summary>\n        ///     Configures the context to connect to a MongoDb instance.\n        /// </summary>\n        /// <param name=\"optionsBuilder\">The builder being used to configure the context.</param>\n        /// <param name=\"mongoUrl\">The <see cref=\"MongoUrl\"/> to use to connect to MongoDb.</param>\n        /// <param name=\"mongoDbOptionsAction\">An optional action to allow additional MongoDb-specific configuration.</param>\n        /// <returns> The options builder so that further configuration can be chained. </returns>\n        public static DbContextOptionsBuilder UseMongoDb(\n            [NotNull] this DbContextOptionsBuilder optionsBuilder,\n            [NotNull] MongoUrl mongoUrl,\n            [CanBeNull] Action<MongoDbContextOptionsBuilder> mongoDbOptionsAction = null)\n        {\n            Check.NotNull(mongoUrl, nameof(mongoUrl));\n            return SetupMongoDb(Check.NotNull(optionsBuilder, nameof(optionsBuilder)),\n                extension => extension.MongoUrl = mongoUrl,\n                mongoDbOptionsAction);\n        }\n\n        private static DbContextOptionsBuilder SetupMongoDb(\n            [NotNull] DbContextOptionsBuilder optionsBuilder,\n            [NotNull] Action<MongoDbOptionsExtension> mongoDbOptionsExtensionAction,\n            [CanBeNull] Action<MongoDbContextOptionsBuilder> mongoDbOptionsAction)\n        {\n            MongoDbOptionsExtension extension = GetOrCreateExtension(optionsBuilder);\n            mongoDbOptionsExtensionAction(extension);\n            ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);\n\n            ConfigureWarnings(optionsBuilder);\n\n            mongoDbOptionsAction?.Invoke(new MongoDbContextOptionsBuilder(optionsBuilder));\n\n            return optionsBuilder;\n        }\n\n        private static MongoDbOptionsExtension GetOrCreateExtension([NotNull] DbContextOptionsBuilder optionsBuilder)\n        {\n            var existing = optionsBuilder.Options.FindExtension<MongoDbOptionsExtension>();\n            return existing != null\n                ? new MongoDbOptionsExtension(existing)\n                : new MongoDbOptionsExtension();\n        }\n\n        private static void ConfigureWarnings([NotNull] DbContextOptionsBuilder optionsBuilder)\n            => Check.NotNull(optionsBuilder, nameof(optionsBuilder))\n                .ConfigureWarnings(warningsConfigurationBuilder =>\n                {\n                    warningsConfigurationBuilder.Default(WarningBehavior.Log);\n                });\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Infrastructure/MongoDbModelValidator.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Infrastructure\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     A validator that enforces rules for all MongoDb provider.\n    /// </summary>\n    public class MongoDbModelValidator : ModelValidator\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbModelValidator\"/> class.\n        /// </summary>\n        /// <param name=\"modelValidatorDependencies\">Parameter object containing dependencies for this service.</param>\n        public MongoDbModelValidator(\n            [NotNull] ModelValidatorDependencies modelValidatorDependencies)\n            : base(Check.NotNull(modelValidatorDependencies, nameof(modelValidatorDependencies)))\n        {\n        }\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     Validates a model, throwing an exception if any errors are found.\n        /// </summary>\n        /// <param name=\"model\">The <see cref=\"Model\"/> to validate.</param>\n        public override void Validate(IModel model)\n        {\n            base.Validate(Check.NotNull(model, nameof(model)));\n\n            EnsureDistinctCollectionNames(model);\n            ValidateDerivedTypes(model);\n        }\n\n        /// <inheritdoc />\n        protected override void ValidateNoShadowKeys(IModel model)\n        {\n            Check.NotNull(model, nameof(model));\n\n            IEnumerable<IEntityType> nonComplexEntityTypes = model\n                .GetEntityTypes()\n                .Where(entityType => entityType.ClrType != null && !entityType.IsOwned());\n\n            foreach (var entityType in nonComplexEntityTypes)\n            {\n                foreach (var key in entityType.GetDeclaredKeys())\n                {\n                    if (key.Properties.Any(p => p.IsShadowProperty)\n                        && key is Key concreteKey\n                        && ConfigurationSource.Convention.Overrides(concreteKey.GetConfigurationSource())\n                        && !key.IsPrimaryKey())\n                    {\n                        var referencingFk = key.GetReferencingForeignKeys().FirstOrDefault();\n\n                        if (referencingFk != null)\n                        {\n                            throw new InvalidOperationException(\n                                CoreStrings.ReferencedShadowKey(\n                                    referencingFk.DeclaringEntityType.DisplayName() +\n                                    (referencingFk.DependentToPrincipal == null\n                                        ? \"\"\n                                        : \".\" + referencingFk.DependentToPrincipal.Name),\n                                    entityType.DisplayName() +\n                                    (referencingFk.PrincipalToDependent == null\n                                        ? \"\"\n                                        : \".\" + referencingFk.PrincipalToDependent.Name),\n                                    Property.Format(referencingFk.Properties, includeTypes: true),\n                                    Property.Format(entityType.FindPrimaryKey().Properties, includeTypes: true)));\n                        }\n                    }\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        protected override void ValidateOwnership(IModel model)\n        {\n            Check.NotNull(model, nameof(model));\n\n            IList<IEntityType> ownedEntityTypes = model\n                .GetEntityTypes()\n                .Where(entityType => entityType.HasClrType()\n                    ? model.ShouldBeOwnedType(entityType.ClrType)\n                    : model.ShouldBeOwnedType(entityType.Name))\n                .ToList();\n\n            foreach (IEntityType entityType in ownedEntityTypes)\n            {\n                List<IForeignKey> ownerships = entityType\n                    .GetForeignKeys()\n                    .Where(fk => fk.IsOwnership)\n                    .ToList();\n\n                foreach (IForeignKey ownership in ownerships)\n                {\n                    IForeignKey principalToDependentForeignKey = entityType\n                        .GetDeclaredForeignKeys()\n                        .FirstOrDefault(foreignKey => !foreignKey.IsOwnership\n                                                      && foreignKey.PrincipalToDependent != null);\n\n                    if (principalToDependentForeignKey != null)\n                    {\n                        throw new InvalidOperationException(\n                            CoreStrings.InverseToOwnedType(\n                                principalToDependentForeignKey.PrincipalEntityType.DisplayName(),\n                                principalToDependentForeignKey.PrincipalToDependent.Name,\n                                entityType.DisplayName(),\n                                ownership.PrincipalEntityType.DisplayName()));\n                    }\n                }\n            }\n        }\n\n        /// <summary>\n        /// Ensures that each <see cref=\"EntityType\"/> in the given <paramref name=\"model\"/> has a unique collection name.\n        /// </summary>\n        /// <param name=\"model\">The <see cref=\"Model\"/> to validate.</param>\n        protected virtual void EnsureDistinctCollectionNames([NotNull] IModel model)\n        {\n            Check.NotNull(model, nameof(model));\n            var tables = new HashSet<string>();\n            var duplicateCollectionNames = model\n                .GetEntityTypes()\n                .Where(et => et.BaseType == null)\n                .Select(entityType => new\n                {\n                    new MongoDbEntityTypeAnnotations(entityType).CollectionName,\n                    DisplayName = entityType.DisplayName()\n                })\n                .Where(tuple => !tables.Add(tuple.CollectionName));\n            foreach (var tuple in duplicateCollectionNames)\n            {\n                throw new InvalidOperationException($\"Duplicate collection name \\\"{tuple.CollectionName}\\\" defined on entity type \\\"{tuple.DisplayName}\\\".\");\n            }\n        }\n\n        /// <summary>\n        /// Ensures that all entities in the given <paramref name=\"model\"/> have unique discriminators.\n        /// </summary>\n        /// <param name=\"model\">The <see cref=\"Model\"/> to validate.</param>\n        protected virtual void ValidateDerivedTypes([NotNull] IModel model)\n        {\n            IEnumerable<IEntityType> derivedTypes = Check.NotNull(model, nameof(model))\n                .GetEntityTypes()\n                .Where(entityType => entityType.BaseType != null && entityType.ClrType.IsInstantiable());\n            var discriminatorSet = new HashSet<Tuple<IEntityType, string>>();\n            foreach (IEntityType entityType in derivedTypes)\n            {\n                ValidateDiscriminator(entityType, discriminatorSet);\n            }\n        }\n\n        private void ValidateDiscriminator(IEntityType entityType, ISet<Tuple<IEntityType,string>> discriminatorSet)\n        {\n            var annotations = new MongoDbEntityTypeAnnotations(entityType);\n            if (string.IsNullOrWhiteSpace(annotations.Discriminator))\n            {\n                throw new InvalidOperationException($\"Missing discriminator value for entity type {entityType.DisplayName()}.\");\n            }\n            if (!discriminatorSet.Add(Tuple.Create(entityType.RootType(), annotations.Discriminator)))\n            {\n                throw new InvalidOperationException($\"Duplicate discriminator value {annotations.Discriminator} for root entity type {entityType.RootType().DisplayName()} (defined on {entityType.DisplayName()}).\");\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Infrastructure/MongoDbOptionsExtension.cs",
    "content": "using System.Linq;\nusing System.Text;\nusing Blueshift.EntityFrameworkCore.MongoDB.DependencyInjection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Driver;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Infrastructure\n{\n    /// <summary>\n    /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n    /// directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbOptionsExtension : IDbContextOptionsExtension\n    {\n        private IMongoClient _mongoClient;\n        private string _databaseName;\n        private string _logFragment;\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public MongoDbOptionsExtension([CanBeNull]MongoDbOptionsExtension existing = null)\n        {\n            if (existing != null)\n            {\n                _mongoClient = existing.MongoClient;\n                _databaseName = existing.DatabaseName;\n            }\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual string ConnectionString\n        {\n            get => MongoUrl?.ToString();\n            [param: NotNull] set\n                => MongoUrl = MongoUrl.Create(Check.NotEmpty(value, nameof(ConnectionString)));\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual IMongoClient MongoClient\n        {\n            get => _mongoClient;\n            [param: NotNull] set\n                => _mongoClient = Check.NotNull(value, nameof(MongoClient));\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual MongoClientSettings MongoClientSettings\n        {\n            get => _mongoClient?.Settings;\n            [param: NotNull] set\n                => _mongoClient = new MongoClient(Check.NotNull(value, nameof(MongoClientSettings)).Clone());\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual MongoUrl MongoUrl\n        {\n            get => _mongoClient == null\n                ? null\n                : MongoUrl.Create($\"mongodb://{string.Join(\",\", _mongoClient.Settings.Servers.Select(server => $\"{server.Host}:{server.Port}\"))}\");\n            [param: NotNull] set\n                => MongoClientSettings = MongoClientSettings.FromUrl(Check.NotNull(value, nameof(MongoUrl)));\n        }\n\n        /// <summary>\n        /// Gets or sets the name of the database that the <see cref=\"DbContext\"/> being configured should use.\n        /// </summary>\n        public string DatabaseName\n        {\n            get => _databaseName;\n            [param: NotNull] set => _databaseName = Check.NotEmpty(value, nameof(value));\n        }\n\n        /// <inheritdoc/>\n        public string LogFragment\n        {\n            get\n            {\n                if (_logFragment == null)\n                {\n                    var logBuilder = new StringBuilder();\n\n                    if (_mongoClient?.Settings != null)\n                    {\n                        logBuilder.Append(\"MongoClient.Settings=\").Append(_mongoClient.Settings.ToString());\n                    }\n\n                    if (!string.IsNullOrEmpty(DatabaseName))\n                    {\n                        logBuilder.Append(\"DatabaseName=\").Append(DatabaseName);\n                    }\n\n                    _logFragment = logBuilder.ToString();\n                }\n                return _logFragment;\n            }\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool ApplyServices(IServiceCollection services)\n        {\n            Check.NotNull(services, nameof(services)).AddEntityFrameworkMongoDb();\n            return true;\n        }\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual long GetServiceProviderHashCode() => 0;\n\n        /// <summary>\n        /// This API supports the Entity Framework Core infrastructure and is not intended to be used\n        /// directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual void Validate(IDbContextOptions options)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ListExtensions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB\n{\n    /// <summary>\n    /// Provides a set of extensions for <see cref=\"IList{T}\"/>.\n    /// </summary>\n    public static class ListExtensions\n    {\n        /// <summary>\n        /// Inserts the given <paramref name=\"item\"/> before the first instance of <typeparamref name=\"TExisting\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of items contained in the list.</typeparam>\n        /// <typeparam name=\"TExisting\">The type of the existing item.</typeparam>\n        /// <param name=\"list\">An <see cref=\"IList{TBase}\"/> whose values will be replaced.</param>\n        /// <param name=\"item\">The new value to be inserted in <paramref name=\"list\"/>.</param>\n        /// <returns>The modified <paramref name=\"list\"/>, such that calls can be chained.</returns>\n        public static IList<T> InsertBefore<T, TExisting>([NotNull] this IList<T> list,\n            [NotNull] T item)\n            where TExisting : T\n        {\n            Check.NotNull(list, nameof(list));\n            Check.NotNull(item, nameof(item));\n            TExisting existing = list.OfType<TExisting>().FirstOrDefault();\n            int index = existing != null\n                ? list.IndexOf(existing)\n                : list.Count;\n            list.Insert(index, item);\n            return list;\n        }\n\n        /// <summary>\n        /// Replaces instances of <typeparamref name=\"TBase\"/> in <paramref name=\"replacement\"/> with the\n        /// given <paramref name=\"replacement\"/>.\n        /// </summary>\n        /// <typeparam name=\"TBase\">The base type of instances to be replaced.</typeparam>\n        /// <typeparam name=\"TReplacement\">The type of the replacement.</typeparam>\n        /// <param name=\"list\">An <see cref=\"IList{TBase}\"/> whose values will be replaced.</param>\n        /// <param name=\"replacement\">The new value to be inserted in <paramref name=\"list\"/>.</param>\n        /// <returns>The modified <paramref name=\"list\"/>, such that calls can be chained.</returns>\n        public static IList<TBase> Replace<TBase, TReplacement>([NotNull] this IList<TBase> list,\n            [NotNull] TReplacement replacement)\n            where TReplacement : TBase\n        {\n            Check.NotNull(list, nameof(list));\n            Check.NotNull(replacement, nameof(replacement));\n            list\n                .OfType<TReplacement>()\n                .Select(item => list.IndexOf(item))\n                .ToList()\n                .ForEach(index => list[index] = replacement);\n            return list;\n        }\n\n        /// <summary>\n        /// Adds an <paramref name=\"item\"/> to the given <paramref name=\"list\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of items contained in <paramref name=\"list\"/>.</typeparam>\n        /// <param name=\"list\">The <see cref=\"IList{T}\"/> to which <paramref name=\"item\"/> will be added.</param>\n        /// <param name=\"item\">The instance of <typeparamref name=\"T\"/> to add to <paramref name=\"list\"/>.</param>\n        /// <returns>The modified <paramref name=\"list\"/>, such that calls can be chained.</returns>\n        public static IList<T> With<T>([NotNull] this IList<T> list,\n            [NotNull] T item)\n        {\n            Check.NotNull(list, nameof(list));\n            Check.NotNull(item, nameof(item));\n            list.Add(item);\n            return list;\n        }\n\n        /// <summary>\n        /// Removes all items that match <paramref name=\"predicate\"/> from the given <paramref name=\"list\"/>.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of items contained in <paramref name=\"list\"/>.</typeparam>\n        /// <param name=\"list\">The <see cref=\"IList{T}\"/> from which items will be removed.</param>\n        /// <param name=\"predicate\">A <see cref=\"Func{T1,T2}\"/> to test for elements to remove.</param>\n        /// <returns>The modified <paramref name=\"list\"/>, such that calls can be chained.</returns>\n        public static IList<T> Without<T>([NotNull] this IList<T> list, Func<T, bool> predicate)\n        {\n            Check.NotNull(list, nameof(list))\n                .Where(predicate)\n                .ToList()\n                .ForEach(item => list.Remove(item));\n            return list;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/DocumentDbInternalMetadataBuilderExtensions.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public static class DocumentInternalMetadataBuilderExtensions\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentEntityTypeAnnotations Document([NotNull] this InternalEntityTypeBuilder internalEntityTypeBuilder)\n            => Check.NotNull(internalEntityTypeBuilder, nameof(internalEntityTypeBuilder)).Metadata.Document();\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentEntityTypeAnnotations Document([NotNull] this EntityTypeBuilder entityTypeBuilder)\n            => Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)).Metadata.Document();\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentEntityTypeAnnotations Document([NotNull] this EntityType entityType)\n            => Check.NotNull<IEntityType>(entityType, nameof(entityType)).Document();\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentEntityTypeAnnotations Document([NotNull] this IEntityType entityType)\n            => new DocumentEntityTypeAnnotations(Check.NotNull(entityType, nameof(entityType)));\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentKeyAnnotations Document([NotNull] this InternalKeyBuilder internalKeyBuilder)\n            => Check.NotNull(internalKeyBuilder, nameof(internalKeyBuilder)).Metadata.Document();\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentKeyAnnotations Document([NotNull] this Key key)\n            => Check.NotNull<IKey>(key, nameof(key)).Document();\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static DocumentKeyAnnotations Document([NotNull] this IKey key)\n            => new DocumentKeyAnnotations(Check.NotNull(key, nameof(key)));\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/DocumentEntityTypeBuilderExtensions.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     Provides a set of MongoDB-specific extension methods for <see cref=\"EntityTypeBuilder\"/>.\n    /// </summary>\n    public static class DocumentEntityTypeBuilderExtensions\n    {\n        /// <summary>\n        ///     Sets whether the <see cref=\"IEntityType\"/> is a complex type (i.e.: not a valid queryable root document entity).\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"isDocumentComplexType\">\n        ///     <code>true</code> if the <see cref=\"IEntityType\"/> is a complex type;\n        ///     otherwise <code>false</code>.\n        /// </param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder IsDocumentComplexType(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            bool isDocumentComplexType)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            entityTypeBuilder.Document().IsComplexType = isDocumentComplexType;\n            return entityTypeBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/DocumentInternalKeyBuilderExtensions.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public static class DocumentInternalKeyBuilderExtensions\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static InternalKeyBuilder IsDocumentOwnershipKey(\n            [NotNull] this InternalKeyBuilder internalKeyBuilder,\n            bool isDocumentOwnershipKey)\n        {\n            DocumentKeyAnnotations documentKeyAnnotations =\n                Check.NotNull(internalKeyBuilder, nameof(internalKeyBuilder)).Document();\n\n            documentKeyAnnotations.IsOwnershipKey = isDocumentOwnershipKey;\n\n            return internalKeyBuilder;\n        }\n            \n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/MongoDbConventionSetBuilder.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbConventionSetBuilder : IConventionSetBuilder\n    {\n        private readonly MongoDbConventionSetBuilderDependencies _mongoDbConventionSetBuilderDependencies;\n\n        /// <summary>\n        ///     Initializes a new instance of the <see cref=\"MongoDbConventionSetBuilder\" /> class.\n        /// </summary>\n        /// <param name=\"mongoDbConventionSetBuilderDependencies\">Parameter object containing dependencies for this service.</param>\n        public MongoDbConventionSetBuilder(\n            [NotNull] MongoDbConventionSetBuilderDependencies mongoDbConventionSetBuilderDependencies)\n        {\n            _mongoDbConventionSetBuilderDependencies\n                = Check.NotNull(mongoDbConventionSetBuilderDependencies, nameof(mongoDbConventionSetBuilderDependencies));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual ConventionSet AddConventions(ConventionSet conventionSet)\n        {\n            Check.NotNull(conventionSet, nameof(conventionSet));\n\n            var mongoDbRelationshipDiscoveryConvention\n                = new MongoDbRelationshipDiscoveryConvention(\n                    _mongoDbConventionSetBuilderDependencies.MemberClassifier,\n                    _mongoDbConventionSetBuilderDependencies.ModelLogger);\n            RelationshipDiscoveryConvention relationshipDiscoveryConvention = mongoDbRelationshipDiscoveryConvention;\n\n            var ownedDocumentConvention = new OwnedDocumentConvention();\n\n            DatabaseGeneratedAttributeConvention databaseGeneratedAttributeConvention\n                = new MongoDbDatabaseGeneratedAttributeConvention();\n\n            KeyAttributeConvention keyAttributeConvention = new MongoDbKeyAttributeConvention();\n\n            var mongoDatabaseConvention\n                = new MongoDatabaseConvention(_mongoDbConventionSetBuilderDependencies.CurrentDbContext.Context);\n\n            var bsonRequiredAttributeConvention\n                = new BsonRequiredAttributeConvention();\n\n            PropertyMappingValidationConvention propertyMappingValidationConvention\n                = new DocumentPropertyMappingValidationConvention(\n                    _mongoDbConventionSetBuilderDependencies.MongoDbTypeMapperSource,\n                    _mongoDbConventionSetBuilderDependencies.MemberClassifier);\n            \n            conventionSet.ModelInitializedConventions\n                .With(mongoDatabaseConvention);\n\n            conventionSet.EntityTypeAddedConventions\n                .Replace(relationshipDiscoveryConvention)\n                .With(ownedDocumentConvention)\n                .With(new MongoCollectionAttributeConvention())\n                .With(new BsonDiscriminatorAttributeConvention())\n                .With(new BsonIgnoreAttributeConvention())\n                .With(new BsonKnownTypesAttributeConvention());\n\n            conventionSet.BaseEntityTypeChangedConventions\n                .Replace(relationshipDiscoveryConvention)\n                .With(ownedDocumentConvention);\n\n            conventionSet.EntityTypeMemberIgnoredConventions\n                .Replace(relationshipDiscoveryConvention);\n\n            conventionSet.KeyAddedConventions\n                .With(ownedDocumentConvention);\n\n            conventionSet.KeyRemovedConventions\n                .With(ownedDocumentConvention);\n\n            conventionSet.ForeignKeyAddedConventions\n                .With(ownedDocumentConvention);\n\n            conventionSet.ForeignKeyOwnershipChangedConventions\n                .With(mongoDbRelationshipDiscoveryConvention)\n                .Without(item => item is NavigationEagerLoadingConvention);\n\n            conventionSet.PropertyAddedConventions\n                .Replace(databaseGeneratedAttributeConvention)\n                .Replace(keyAttributeConvention)\n                .With(bsonRequiredAttributeConvention);\n\n            conventionSet.PropertyFieldChangedConventions\n                .Replace(databaseGeneratedAttributeConvention)\n                .Replace(keyAttributeConvention)\n                .With(bsonRequiredAttributeConvention);\n\n            conventionSet.NavigationAddedConventions\n                .Replace(relationshipDiscoveryConvention);\n\n            conventionSet.NavigationRemovedConventions\n                .Replace(relationshipDiscoveryConvention);\n\n            conventionSet.ModelBuiltConventions\n                .Replace(keyAttributeConvention)\n                .Replace(propertyMappingValidationConvention)\n                .With(ownedDocumentConvention);\n\n            return conventionSet;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/MongoDbConventionSetBuilderDependencies.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     <para>\n    ///         Service dependencies parameter class for <see cref=\"MongoDbConventionSetBuilder\" />\n    ///     </para>\n    ///     <para>\n    ///         This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///         directly from your code. This API may change or be removed in future releases.\n    ///     </para>\n    ///     <para>\n    ///         Do not construct instances of this class directly from either provider or application code as the\n    ///         constructor signature may change as new dependencies are added. Instead, use this type in \n    ///         your constructor so that an instance will be created and injected automatically by the \n    ///         dependency injection container. To create an instance with some dependent services replaced, \n    ///         first resolve the object from the dependency injection container, then replace selected \n    ///         services using the 'With...' methods. Do not call the constructor at any point in this process.\n    ///     </para>\n    /// </summary>\n    public class MongoDbConventionSetBuilderDependencies\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbConventionSetBuilderDependencies\"/> class.\n        /// </summary>\n        /// <param name=\"currentDbContext\">Indirection to the current <see cref=\"DbContext\" /> instance.</param>\n        /// <param name=\"mongoDbTypeMappingSource\">Maps .NET types to their corresponding database provider types.</param>\n        /// <param name=\"memberClassifier\">Determines the property types for candidate navigation properties.</param>\n        /// <param name=\"modelLogger\">Traces the process of building a <see cref=\"Model\"/>.</param>\n        public MongoDbConventionSetBuilderDependencies(\n            [NotNull] ICurrentDbContext currentDbContext,\n            [NotNull] IMongoDbTypeMappingSource mongoDbTypeMappingSource,\n            [NotNull] IMemberClassifier memberClassifier,\n            [NotNull] IDiagnosticsLogger<DbLoggerCategory.Model> modelLogger)\n        {\n            CurrentDbContext = Check.NotNull(currentDbContext, nameof(currentDbContext));\n            MongoDbTypeMapperSource = Check.NotNull(mongoDbTypeMappingSource, nameof(mongoDbTypeMappingSource));\n            MemberClassifier = Check.NotNull(memberClassifier, nameof(memberClassifier));\n            ModelLogger = Check.NotNull(modelLogger, nameof(modelLogger));\n        }\n\n        /// <summary>\n        ///     Indirection to the current <see cref=\"DbContext\" /> instance.\n        /// </summary>\n        public ICurrentDbContext CurrentDbContext { get; }\n\n        /// <summary>\n        /// Maps .NET types to their corresponding database provider types.\n        /// </summary>\n        public IMongoDbTypeMappingSource MongoDbTypeMapperSource { get; }\n\n        /// <summary>\n        /// The <see cref=\"IMemberClassifier\"/> to use to determine the property types for candidate navigation properties.\n        /// </summary>\n        public IMemberClassifier MemberClassifier { get; set; }\n\n        /// <summary>\n        /// The <see cref=\"IDiagnosticsLogger{TLoggerCategory}\"/> used for tracing the process of building a <see cref=\"Model\"/>.\n        /// </summary>\n        public IDiagnosticsLogger<DbLoggerCategory.Model> ModelLogger { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/MongoDbEntityTypeBuilderExtensions.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     Provides a set of MongoDB-specific extension methods for <see cref=\"EntityTypeBuilder\"/>.\n    /// </summary>\n    public static class MongoDbEntityTypeBuilderExtensions\n    {\n        /// <summary>\n        ///     Sets the name of the MongoDB collection used to store the <see cref=\"IEntityType\"/> being built.\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"collectionName\">The name of the MongoDB collection.</param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder ForMongoDbFromCollection(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            [NotNull] string collectionName)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n            Check.NotEmpty(collectionName, nameof(collectionName));\n\n            entityTypeBuilder.MongoDb().CollectionName = collectionName;\n            return entityTypeBuilder;\n        }\n\n        /// <summary>\n        ///     Sets the discriminator used to query instances of the <see cref=\"IEntityType\"/> being built.\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"discriminator\">The discriminator for the <see cref=\"IEntityType\"/>.</param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder ForMongoDbHasDiscriminator(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            [NotNull] string discriminator)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n            Check.NotEmpty(discriminator, nameof(discriminator));\n\n            entityTypeBuilder.MongoDb().Discriminator = discriminator;\n            return entityTypeBuilder;\n        }\n\n        /// <summary>\n        ///     Sets the whether or not a discriminator is required to query instances of the <see cref=\"IEntityType\"/> being built.\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"discriminatorIsRequired\">\n        ///     <code>true</code> if a discriminator is required to query instances of the entity; otherwise <code>false</code>.\n        /// </param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder ForMongoDbDiscriminatorIsRequired(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            bool discriminatorIsRequired)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            entityTypeBuilder.MongoDb().DiscriminatorIsRequired = discriminatorIsRequired;\n            return entityTypeBuilder;\n        }\n\n        /// <summary>\n        ///     Sets whether the <see cref=\"IEntityType\"/> being built is a root type of a polymorphic hierarchy.\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"isRootType\">\n        ///     <code>true</code> if the <see cref=\"IEntityType\"/> is the root entity type; otherwise <code>false</code>.\n        /// </param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder ForMongoDbIsRootType(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            bool isRootType)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            entityTypeBuilder.MongoDb().IsRootType = isRootType;\n            return entityTypeBuilder;\n        }\n\n        /// <summary>\n        ///     Sets whether the identity of the <see cref=\"IEntityType\"/> being built should be assigned by MongoDb on insert.\n        /// </summary>\n        /// <param name=\"entityTypeBuilder\">The <see cref=\"EntityTypeBuilder\"/> to annotate.</param>\n        /// <param name=\"assignIdOnInsert\">\n        ///     <code>true</code> if the identity of the <see cref=\"IEntityType\"/> is assigned on insert;\n        ///     otherwise <code>false</code>.\n        /// </param>\n        /// <returns>The <paramref name=\"entityTypeBuilder\"/>, such that calls be chained.</returns>\n        public static EntityTypeBuilder ForMongoDbAssignIdOnInsert(\n            [NotNull] this EntityTypeBuilder entityTypeBuilder,\n            bool assignIdOnInsert)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            entityTypeBuilder.MongoDb().AssignIdOnInsert = assignIdOnInsert;\n            return entityTypeBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/MongoDbInternalMetadataBuilderExtensions.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public static class MongoDbInternalMetadataBuilderExtensions\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbEntityTypeAnnotations MongoDb([NotNull] this InternalEntityTypeBuilder internalEntityTypeBuilder)\n            => MongoDb(Check.NotNull(internalEntityTypeBuilder, nameof(internalEntityTypeBuilder)).Metadata);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbEntityTypeAnnotations MongoDb([NotNull] this EntityTypeBuilder entityTypeBuilder)\n            => MongoDb(Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)).Metadata);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbEntityTypeAnnotations MongoDb([NotNull] this IEntityType entityType)\n            => MongoDb(Check.Is<IMutableEntityType>(entityType, nameof(entityType)));\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbEntityTypeAnnotations MongoDb([NotNull] this IMutableEntityType mutableEntityType)\n            => new MongoDbEntityTypeAnnotations(Check.NotNull(mutableEntityType, nameof(mutableEntityType)));\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbModelAnnotations MongoDb([NotNull] this InternalModelBuilder internalModelBuilder)\n            => MongoDb(Check.NotNull(internalModelBuilder, nameof(internalModelBuilder)).Metadata);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbModelAnnotations MongoDb([NotNull] this ModelBuilder modelBuilder)\n            => MongoDb(Check.NotNull(modelBuilder, nameof(modelBuilder)).Model);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbModelAnnotations MongoDb([NotNull] this IModel model)\n            => MongoDb(Check.Is<IMutableModel>(model, nameof(model)));\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public static MongoDbModelAnnotations MongoDb([NotNull] this IMutableModel mutableModel)\n            => new MongoDbModelAnnotations(Check.NotNull(mutableModel, nameof(mutableModel)));\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Builders/MongoDbModelBuilderExtensions.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders\n{\n    /// <summary>\n    ///     MongoDb-specific extension methods for <see cref=\"ModelBuilder\" />.\n    /// </summary>\n    public static class MongoDbModelBuilderExtensions\n    {\n        /// <summary>\n        ///     Configures the database to use when connecting to MongoDb.\n        /// </summary>\n        /// <param name=\"modelBuilder\">The <see cref=\"ModelBuilder\"/> to configure.</param>\n        /// <param name=\"database\">The name of the database.</param>\n        /// <returns>This <see cref=\"ModelBuilder\"/>, such that calls can be chained.</returns>\n        public static ModelBuilder ForMongoDbFromDatabase(this ModelBuilder modelBuilder, string database)\n        {\n            Check.NotNull(modelBuilder, nameof(modelBuilder));\n            modelBuilder.Model.MongoDb().Database = database;\n            return modelBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/BsonDiscriminatorAttributeConvention.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    public class BsonDiscriminatorAttributeConvention : EntityTypeAttributeConvention<BsonDiscriminatorAttribute>\n    {\n        /// <inheritdoc />\n        public override InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder,\n            BsonDiscriminatorAttribute attribute)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n            Check.NotNull(attribute, nameof(attribute));\n            MongoDbEntityTypeAnnotations annotations = entityTypeBuilder.MongoDb();\n            if (!string.IsNullOrWhiteSpace(attribute.Discriminator))\n            {\n                annotations.Discriminator = attribute.Discriminator;\n            }\n\n            if (!annotations.DiscriminatorIsRequired)\n            {\n                annotations.DiscriminatorIsRequired = attribute.Required;\n            }\n\n            annotations.IsRootType = attribute.RootClass;\n            return entityTypeBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/BsonIgnoreAttributeConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class BsonIgnoreAttributeConvention : IEntityTypeAddedConvention\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            Type clrType = entityTypeBuilder.Metadata.ClrType;\n            if (clrType == null)\n            {\n                return entityTypeBuilder;\n            }\n\n            IEnumerable<MemberInfo> members = clrType.GetRuntimeProperties()\n                .Cast<MemberInfo>()\n                .Concat(clrType.GetRuntimeFields())\n                .Where(memberInfo => memberInfo.IsDefined(typeof(BsonIgnoreAttribute), true));\n\n            foreach (MemberInfo member in members)\n            {\n                entityTypeBuilder.Ignore(member.Name, ConfigurationSource.DataAnnotation);\n            }\n\n            return entityTypeBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/BsonKnownTypesAttributeConvention.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    public class BsonKnownTypesAttributeConvention : EntityTypeAttributeConvention<BsonKnownTypesAttribute>\n    {\n        /// <inheritdoc />\n        public override InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            var type = entityTypeBuilder.Metadata.ClrType;\n            if (type == null || !Attribute.IsDefined(type, typeof(BsonKnownTypesAttribute), inherit: false))\n            {\n                return entityTypeBuilder;\n            }\n\n            var attributes = type.GetTypeInfo().GetCustomAttributes<BsonKnownTypesAttribute>(false);\n\n            foreach (var attribute in attributes)\n            {\n                entityTypeBuilder = Apply(entityTypeBuilder, attribute);\n                if (entityTypeBuilder == null)\n                {\n                    break;\n                }\n            }\n\n            return entityTypeBuilder;\n        }\n\n        /// <inheritdoc />\n        public override InternalEntityTypeBuilder Apply(\n            InternalEntityTypeBuilder entityTypeBuilder,\n            BsonKnownTypesAttribute bsonKnownTypesAttribute)\n        {\n            MongoDbEntityTypeAnnotations annotations = entityTypeBuilder.MongoDb();\n            if (!annotations.DiscriminatorIsRequired)\n            {\n                annotations.DiscriminatorIsRequired = entityTypeBuilder.Metadata.IsAbstract();\n            }\n\n            if (bsonKnownTypesAttribute.KnownTypes != null)\n            {\n                InternalModelBuilder modelBuilder = entityTypeBuilder.ModelBuilder;\n                Type baseType = entityTypeBuilder.Metadata.ClrType;\n\n                foreach (Type derivedType in bsonKnownTypesAttribute.KnownTypes)\n                {\n                    if (!baseType.IsAssignableFrom(derivedType))\n                    {\n                        throw new InvalidOperationException($\"Known type {derivedType} declared on base type {baseType} does not inherit from base type.\");\n                    }\n\n                    modelBuilder\n                        .Entity(derivedType, ConfigurationSource.DataAnnotation)\n                        .MongoDb()\n                        .IsDerivedType = true;\n                }\n            }\n\n            return entityTypeBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/BsonRequiredAttributeConvention.cs",
    "content": "﻿using System.Reflection;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class BsonRequiredAttributeConvention : PropertyAttributeConvention<BsonRequiredAttribute>\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder,\n            BsonRequiredAttribute attribute,\n            MemberInfo clrMember)\n        {\n            Check.NotNull(propertyBuilder, nameof(propertyBuilder));\n            Check.NotNull(attribute, nameof(attribute));\n            Check.NotNull(clrMember, nameof(clrMember));\n\n            propertyBuilder.IsRequired(true, ConfigurationSource.DataAnnotation);\n\n            return propertyBuilder;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/DocumentPropertyMappingValidationConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Text;\nusing System.Threading.Tasks;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    public class DocumentPropertyMappingValidationConvention : PropertyMappingValidationConvention\n    {\n        private readonly ITypeMappingSource _typeMappingSource;\n        private readonly IMemberClassifier _memberClassifier;\n\n        /// <inheritdoc />\n        public DocumentPropertyMappingValidationConvention(\n            [NotNull] ITypeMappingSource typeMappingSource,\n            [NotNull] IMemberClassifier memberClassifier)\n            : base(\n                Check.NotNull(typeMappingSource, nameof(typeMappingSource)),\n                Check.NotNull(memberClassifier, nameof(memberClassifier)))\n        {\n            _typeMappingSource = typeMappingSource;\n            _memberClassifier = memberClassifier;\n        }\n\n        /// <inheritdoc />\n        public override InternalModelBuilder Apply(InternalModelBuilder modelBuilder)\n        {\n            foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())\n            {\n                var unmappedProperty = entityType.GetProperties().FirstOrDefault(p =>\n                    (!ConfigurationSource.Convention.Overrides(p.GetConfigurationSource()) || !p.IsShadowProperty)\n                    && !IsMappedPrimitiveProperty(p));\n\n                if (unmappedProperty != null)\n                {\n                    throw new InvalidOperationException(\n                        CoreStrings.PropertyNotMapped(\n                            entityType.DisplayName(), unmappedProperty.Name, unmappedProperty.ClrType.ShortDisplayName()));\n                }\n\n                if (!entityType.HasClrType())\n                {\n                    continue;\n                }\n\n                var clrProperties = new HashSet<string>();\n\n                clrProperties.UnionWith(\n                    entityType.GetRuntimeProperties().Values\n                        .Where(pi => pi.IsCandidateProperty())\n                        .Select(pi => pi.Name));\n\n                clrProperties.ExceptWith(entityType.GetProperties().Select(p => p.Name));\n                clrProperties.ExceptWith(entityType.GetNavigations().Select(p => p.Name));\n                clrProperties.ExceptWith(entityType.GetServiceProperties().Select(p => p.Name));\n                clrProperties.RemoveWhere(p => entityType.Builder.IsIgnored(p, ConfigurationSource.Convention));\n\n                if (clrProperties.Count <= 0)\n                {\n                    continue;\n                }\n\n                foreach (var clrProperty in clrProperties)\n                {\n                    var actualProperty = entityType.GetRuntimeProperties()[clrProperty];\n                    var propertyType = actualProperty.PropertyType;\n                    var targetSequenceType = propertyType.TryGetSequenceType();\n\n                    if (modelBuilder.IsIgnored(modelBuilder.Metadata.GetDisplayName(propertyType),\n                        ConfigurationSource.Convention)\n                        || (targetSequenceType != null\n                            && modelBuilder.IsIgnored(modelBuilder.Metadata.GetDisplayName(targetSequenceType),\n                                ConfigurationSource.Convention)))\n                    {\n                        continue;\n                    }\n\n                    var targetType = base.FindCandidateNavigationPropertyType(actualProperty);\n\n                    var isTargetWeakOrOwned\n                        = targetType != null\n                          && (modelBuilder.Metadata.HasEntityTypeWithDefiningNavigation(targetType)\n                              || modelBuilder.Metadata.ShouldBeOwnedType(targetType));\n\n                    if (targetType != null\n                        && targetType.IsValidEntityType()\n                        && (isTargetWeakOrOwned\n                            || modelBuilder.Metadata.FindEntityType(targetType) != null\n                            || targetType.GetRuntimeProperties().Any(p => p.IsCandidateProperty())))\n                    {\n                        if ((!isTargetWeakOrOwned\n                             || !targetType.GetTypeInfo().Equals(entityType.ClrType.GetTypeInfo()))\n                            && entityType.GetDerivedTypes().All(\n                                dt => dt.FindDeclaredNavigation(actualProperty.Name) == null)\n                            && !entityType.IsInDefinitionPath(targetType))\n                        {\n                            throw new InvalidOperationException(\n                                CoreStrings.NavigationNotAdded(\n                                    entityType.DisplayName(), actualProperty.Name, propertyType.ShortDisplayName()));\n                        }\n                    }\n                    else if (targetSequenceType == null && propertyType.GetTypeInfo().IsInterface\n                             || targetSequenceType != null && targetSequenceType.GetTypeInfo().IsInterface)\n                    {\n                        throw new InvalidOperationException(\n                            CoreStrings.InterfacePropertyNotAdded(\n                                entityType.DisplayName(), actualProperty.Name, propertyType.ShortDisplayName()));\n                    }\n                    else\n                    {\n                        throw new InvalidOperationException(\n                            CoreStrings.PropertyNotAdded(\n                                entityType.DisplayName(), actualProperty.Name, propertyType.ShortDisplayName()));\n                    }\n                }\n            }\n\n            return modelBuilder;\n        }\n\n        /// <inheritdoc />\n        protected override bool IsMappedPrimitiveProperty([NotNull] IProperty property)\n            => _typeMappingSource.FindMapping(property) != null;\n\n        /// <inheritdoc />\n        protected override Type FindCandidateNavigationPropertyType([NotNull] PropertyInfo propertyInfo)\n            => _memberClassifier.FindCandidateNavigationPropertyType(propertyInfo);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/MongoCollectionAttributeConvention.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoCollectionAttributeConvention : EntityTypeAttributeConvention<MongoCollectionAttribute>\n    {\n        /// <inheritdoc />\n        public override InternalEntityTypeBuilder Apply(\n            InternalEntityTypeBuilder entityTypeBuilder,\n            MongoCollectionAttribute mongoCollectionAttribute)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n            Check.NotNull(mongoCollectionAttribute, nameof(mongoCollectionAttribute));\n            entityTypeBuilder.MongoDb().CollectionName = mongoCollectionAttribute.CollectionName;\n            return entityTypeBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/MongoDatabaseConvention.cs",
    "content": "﻿using System.Reflection;\nusing System.Text.RegularExpressions;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDatabaseConvention : IModelInitializedConvention\n    {\n        private readonly DbContext _dbContext;\n        private readonly MongoDbOptionsExtension _mongoDbOptionsExtension;\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public MongoDatabaseConvention([NotNull] DbContext dbContext)\n        {\n            _dbContext = Check.NotNull(dbContext, nameof(dbContext));\n            _mongoDbOptionsExtension = _dbContext\n                .GetService<IDbContextServices>()\n                .ContextOptions\n                .FindExtension<MongoDbOptionsExtension>();\n        }\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public InternalModelBuilder Apply(InternalModelBuilder modelBuilder)\n        {\n            Check.NotNull(modelBuilder, nameof(modelBuilder));\n\n            MongoDatabaseAttribute mongoDatabaseAttribute = _dbContext.GetType()\n                .GetTypeInfo()\n                .GetCustomAttribute<MongoDatabaseAttribute>();\n\n            string databaseName = _mongoDbOptionsExtension.DatabaseName\n                                  ?? mongoDatabaseAttribute?.Database\n                                  ?? GetDefaultDatabaseName();\n\n            Check.NotNull(modelBuilder, nameof(modelBuilder))\n                .MongoDb()\n                .Database = databaseName;\n            return modelBuilder;\n        }\n\n        private string GetDefaultDatabaseName()\n            => MongoDbUtilities.ToLowerCamelCase(Regex.Replace(_dbContext.GetType().Name, \"(?:Mongo)?(?:Db)?(?:Context)?$\", \"\"));\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/MongoDbDatabaseGeneratedAttributeConvention.cs",
    "content": "﻿using System.ComponentModel.DataAnnotations.Schema;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    public class MongoDbDatabaseGeneratedAttributeConvention : DatabaseGeneratedAttributeConvention\n    {\n        /// <inheritdoc />\n        public override InternalPropertyBuilder Apply(\n            InternalPropertyBuilder propertyBuilder,\n            DatabaseGeneratedAttribute attribute,\n            MemberInfo clrMember)\n        {\n            if (attribute.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity)\n            {\n                propertyBuilder.Metadata\n                    .DeclaringEntityType\n                    .MongoDb()\n                    .AssignIdOnInsert = true;\n            }\n            return base.Apply(propertyBuilder, attribute, clrMember);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/MongoDbKeyAttributeConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.Linq;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc />\n    public class MongoDbKeyAttributeConvention : KeyAttributeConvention\n    {\n        private static readonly KeyAttribute KeyAttribute = new KeyAttribute();\n\n        /// <inheritdoc />\n        public override InternalPropertyBuilder Apply(InternalPropertyBuilder propertyBuilder)\n        {\n            Check.NotNull(propertyBuilder, nameof(propertyBuilder));\n\n            MemberInfo memberInfo = propertyBuilder.Metadata.GetIdentifyingMemberInfo();\n            return (memberInfo?.IsDefined(typeof(BsonIdAttribute), true) ?? false)\n                ? Apply(propertyBuilder, KeyAttribute, memberInfo)\n                : base.Apply(propertyBuilder);\n        }\n\n        /// <inheritdoc />\n        public override InternalModelBuilder Apply(InternalModelBuilder modelBuilder)\n        {\n            IEnumerable<EntityType> entityTypes = modelBuilder.Metadata\n                .GetEntityTypes()\n                .Where(entityType => entityType.MongoDb().IsDerivedType);\n\n            foreach (EntityType entityType in entityTypes)\n            {\n                foreach (Property declaredProperty in entityType.GetDeclaredProperties())\n                {\n                    if (declaredProperty.GetIdentifyingMemberInfo()?.IsDefined(typeof(BsonIdAttribute), true) ?? false)\n                    {\n                        throw new InvalidOperationException(\n                            CoreStrings.KeyAttributeOnDerivedEntity(entityType.DisplayName(), declaredProperty.Name));\n                    }\n                }\n            }\n            return base.Apply(modelBuilder);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/MongoDbRelationshipDiscoveryConvention.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc cref=\"RelationshipDiscoveryConvention\"/>\n    /// <inheritdoc cref=\"IForeignKeyOwnershipChangedConvention\"/>\n    public class MongoDbRelationshipDiscoveryConvention : RelationshipDiscoveryConvention, IForeignKeyOwnershipChangedConvention\n    {\n        /// <inheritdoc />\n        public MongoDbRelationshipDiscoveryConvention(\n            [NotNull] IMemberClassifier memberClassifier,\n            [NotNull] IDiagnosticsLogger<DbLoggerCategory.Model> logger)\n            : base(memberClassifier, logger)\n        {\n        }\n\n        /// <inheritdoc />\n        InternalRelationshipBuilder IForeignKeyOwnershipChangedConvention.Apply(InternalRelationshipBuilder relationshipBuilder)\n        {\n            Apply(relationshipBuilder.Metadata.DeclaringEntityType.Builder);\n            return relationshipBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/Conventions/OwnedDocumentConvention.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata.Conventions\n{\n    /// <inheritdoc cref=\"IBaseTypeChangedConvention\"/>\n    /// <inheritdoc cref=\"IEntityTypeAddedConvention\"/>\n    /// <inheritdoc cref=\"IForeignKeyAddedConvention\"/>\n    /// <inheritdoc cref=\"IKeyAddedConvention\"/>\n    /// <inheritdoc cref=\"IKeyRemovedConvention\"/>\n    /// <inheritdoc cref=\"IModelBuiltConvention\"/>\n    public class OwnedDocumentConvention :\n        IBaseTypeChangedConvention,\n        IEntityTypeAddedConvention,\n        IForeignKeyAddedConvention,\n        IKeyAddedConvention,\n        IKeyRemovedConvention,\n        IModelBuiltConvention\n    {\n        /// <inheritdoc />\n        public InternalEntityTypeBuilder Apply(InternalEntityTypeBuilder entityTypeBuilder)\n        {\n            Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder));\n\n            EntityType entityType = entityTypeBuilder.Metadata;\n            Key primaryKey = entityType.FindPrimaryKey();\n\n            bool isComplexType = primaryKey == null\n                                 || primaryKey.Document().IsOwnershipKey;\n\n            entityTypeBuilder.Document().IsComplexType = isComplexType;\n\n            return entityTypeBuilder;\n        }\n\n        /// <inheritdoc />\n        public bool Apply(\n            InternalEntityTypeBuilder entityTypeBuilder,\n            EntityType oldBaseType)\n        {\n            Apply(entityTypeBuilder);\n\n            return true;\n        }\n\n        /// <inheritdoc />\n        public InternalKeyBuilder Apply(InternalKeyBuilder keyBuilder)\n        {\n            Apply(Check.NotNull(keyBuilder, nameof(keyBuilder)).Metadata.DeclaringEntityType.Builder);\n\n            return keyBuilder;\n        }\n\n        /// <inheritdoc />\n        public void Apply(InternalEntityTypeBuilder entityTypeBuilder, Key key)\n        {\n            Apply(entityTypeBuilder);\n        }\n\n        /// <inheritdoc />\n        public InternalRelationshipBuilder Apply(InternalRelationshipBuilder relationshipBuilder)\n        {\n            Check.NotNull(relationshipBuilder, nameof(relationshipBuilder));\n\n            IEntityType principalEntityType = relationshipBuilder.Metadata.PrincipalEntityType;\n\n            bool principalIsOwned = principalEntityType.IsOwned()\n                                    || principalEntityType.MongoDb().IsComplexType;\n\n            if (principalIsOwned)\n            {\n                relationshipBuilder.IsOwnership(true, ConfigurationSource.Explicit);\n            }\n\n            return relationshipBuilder;\n        }\n\n        /// <inheritdoc />\n        public InternalModelBuilder Apply(InternalModelBuilder modelBuilder)\n        {\n            IModel model = Check.NotNull(modelBuilder, nameof(modelBuilder)).Metadata;\n\n            IEnumerable<EntityType> ownedEntityTypes = model\n                .GetEntityTypes()\n                .Where(entityType => entityType.IsOwned()\n                                     || entityType.MongoDb().IsComplexType)\n                .Select(entityType => entityType.AsEntityType())\n                .ToList();\n\n            foreach (EntityType ownedEntityType in ownedEntityTypes)\n            {\n                bool isOwnedType = ownedEntityType.HasClrType()\n                    ? model.ShouldBeOwnedType(ownedEntityType.ClrType)\n                    : model.ShouldBeOwnedType(ownedEntityType.Name);\n\n                if (!isOwnedType)\n                {\n                    if (ownedEntityType.HasClrType())\n                    {\n                        modelBuilder.Owned(ownedEntityType.ClrType, ConfigurationSource.Convention);\n                    }\n                    else\n                    {\n                        modelBuilder.Owned(ownedEntityType.Name, ConfigurationSource.Convention);\n                    }\n                }\n\n                if (ownedEntityType.BaseType == null)\n                {\n                    IKey primaryKey = ownedEntityType.FindPrimaryKey();\n                    string ownershipKeyName = $\"{ownedEntityType.ShortName()}Id\";\n\n                    if (primaryKey != null && primaryKey.Properties.Any(property => !property.IsShadowProperty))\n                    {\n                        throw new InvalidOperationException(\n                            $\"Owned entity type {ownedEntityType.Name} has a non-shadow primary key defined.\");\n                    }\n\n                    if (primaryKey == null || !string.Equals(ownershipKeyName, primaryKey.Properties.First().Name))\n                    {\n                        ownedEntityType.Builder\n                            .Property(\n                                ownershipKeyName,\n                                typeof(int?),\n                                ConfigurationSource.Convention)\n                            .HasValueGenerator(\n                                typeof(HashCodeValueGenerator),\n                                ConfigurationSource.Convention);\n\n                        ownedEntityType.Builder\n                            .PrimaryKey(\n                                new[] { ownershipKeyName },\n                                ConfigurationSource.Convention)\n                            .IsDocumentOwnershipKey(true);\n                    }\n                }\n            }\n\n            return modelBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/DocumentAnnotationNames.cs",
    "content": "﻿namespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class DocumentAnnotationNames\n    {\n        private const string Prefix = \"Document:\";\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string IsComplexType = Prefix + nameof(IsComplexType);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string IsOwnershipKey = Prefix + nameof(IsOwnershipKey);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/DocumentAnnotations.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class DocumentAnnotations<TAnnotatable>\n        where TAnnotatable : IAnnotatable\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected DocumentAnnotations([NotNull] TAnnotatable metadata)\n        {\n            Annotatable = Check.Is<IMutableAnnotatable>(metadata, nameof(metadata));\n            Metadata = Check.NotNull(metadata, nameof(metadata));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual TAnnotatable Metadata { get; }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected virtual IMutableAnnotatable Annotatable { get; }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual T GetAnnotation<T>([CanBeNull] string annotationName)\n            => (T)Annotatable[Check.NullButNotEmpty(annotationName, nameof(annotationName))];\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool SetAnnotation<T>([NotNull] string annotationName, [CanBeNull] T value)\n        {\n            Check.NotEmpty(annotationName, nameof(annotationName));\n            Annotatable[annotationName] = value;\n            return true;\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool CanSetAnnotation([NotNull] string annotationName, [CanBeNull] object value)\n            => true;\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/DocumentEntityTypeAnnotations.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class DocumentEntityTypeAnnotations : DocumentAnnotations<IEntityType>\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public DocumentEntityTypeAnnotations([NotNull] IEntityType entityType)\n            : base(entityType)\n        {\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool IsComplexType\n        {\n            get => GetAnnotation<bool?>(DocumentAnnotationNames.IsComplexType) ?? false;\n            set => SetAnnotation(DocumentAnnotationNames.IsComplexType, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/DocumentKeyAnnotations.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class DocumentKeyAnnotations : DocumentAnnotations<IKey>\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public DocumentKeyAnnotations([NotNull] IKey key)\n            : base(key)\n        {\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool IsOwnershipKey\n        {\n            get => GetAnnotation<bool?>(DocumentAnnotationNames.IsOwnershipKey) ?? false;\n            set => SetAnnotation(DocumentAnnotationNames.IsOwnershipKey, value);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/MongoDbAnnotationNames.cs",
    "content": "﻿namespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbAnnotationNames\n    {\n        private const string Prefix = \"MongoDb:\";\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string CollectionName = Prefix + nameof(CollectionName);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string CollectionSettings = Prefix + nameof(CollectionSettings);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string Database = Prefix + nameof(Database);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string DatabaseSettings = Prefix + nameof(DatabaseSettings);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string Discriminator = Prefix + nameof(Discriminator);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string DiscriminatorIsRequired = Prefix + nameof(DiscriminatorIsRequired);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string IsDerivedType = Prefix + nameof(IsDerivedType);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string IsRootType = Prefix + nameof(IsRootType);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string Namespace = Prefix + nameof(Namespace);\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public const string NavigationName = Prefix + nameof(NavigationName);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/MongoDbEntityTypeAnnotations.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <inheritdoc />\n    public class MongoDbEntityTypeAnnotations : DocumentEntityTypeAnnotations\n    {\n        /// <inheritdoc />\n        public MongoDbEntityTypeAnnotations([NotNull] IEntityType entityType)\n            : base(entityType)\n        {\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool AssignIdOnInsert\n        {\n            get => CollectionSettings?.AssignIdOnInsert ?? false;\n            set => GetOrCreateCollectionSettings().AssignIdOnInsert = value;\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual string CollectionName\n        {\n            get => GetAnnotation<string>(MongoDbAnnotationNames.CollectionName)\n                   ?? MongoDbUtilities.Pluralize(MongoDbUtilities.ToLowerCamelCase(Metadata.ClrType.Name));\n            [param: NotNull]\n            set => SetAnnotation(MongoDbAnnotationNames.CollectionName, Check.NotEmpty(value, nameof(CollectionName)));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual MongoCollectionSettings CollectionSettings\n        {\n            get => GetAnnotation<MongoCollectionSettings>(MongoDbAnnotationNames.CollectionSettings);\n            [param: NotNull]\n            set => SetAnnotation(MongoDbAnnotationNames.CollectionSettings, Check.NotNull(value, nameof(CollectionSettings)));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual string Discriminator\n        {\n            get => GetAnnotation<string>(MongoDbAnnotationNames.Discriminator) ?? Metadata.ClrType.Name;\n            [param: NotNull]\n            set => SetAnnotation(MongoDbAnnotationNames.Discriminator, Check.NotEmpty(value, nameof(Discriminator)));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool DiscriminatorIsRequired\n        {\n            get => GetAnnotation<bool?>(MongoDbAnnotationNames.DiscriminatorIsRequired) ?? false;\n            set => SetAnnotation(MongoDbAnnotationNames.DiscriminatorIsRequired, value);\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool IsDerivedType\n        {\n            get => GetAnnotation<bool?>(MongoDbAnnotationNames.IsDerivedType) ?? false;\n            set => SetAnnotation(MongoDbAnnotationNames.IsDerivedType, value);\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual bool IsRootType\n        {\n            get => GetAnnotation<bool?>(MongoDbAnnotationNames.IsRootType) ?? false;\n            set => SetAnnotation(MongoDbAnnotationNames.IsRootType, value);\n        }\n\n        private MongoCollectionSettings GetOrCreateCollectionSettings()\n            => CollectionSettings ?? (CollectionSettings = new MongoCollectionSettings());\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Metadata/MongoDbModelAnnotations.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Metadata\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbModelAnnotations : DocumentAnnotations<IModel>\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public MongoDbModelAnnotations([NotNull] IModel model)\n            : base(model)\n        {\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual string Database\n        {\n            get => GetAnnotation<string>(MongoDbAnnotationNames.Database);\n\n            [param: NotNull]\n            set => SetAnnotation(MongoDbAnnotationNames.Database, Check.NotEmpty(value, nameof(Database)));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual MongoDatabaseSettings DatabaseSettings\n        {\n            get => GetAnnotation<MongoDatabaseSettings>(MongoDbAnnotationNames.DatabaseSettings);\n\n            [param: NotNull]\n            set => SetAnnotation(MongoDbAnnotationNames.DatabaseSettings, Check.NotNull(value, nameof(DatabaseSettings)));\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/MethodHelper.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB\n{\n    /// <summary>\n    /// Provides utility methods for retrieving method info.\n    /// </summary>\n    public static class MethodHelper\n    {\n        /// <summary>\n        /// Gets a generic method definition from a given delegate.\n        /// </summary>\n        /// <param name=\"delegateExpression\">An expression representing a given method call.</param>\n        /// <returns>The generic method definition for the method in <paramref name=\"delegateExpression\"/></returns>\n        public static MethodInfo GetMethodInfo(Expression<Action> delegateExpression)\n            => ((MethodCallExpression)delegateExpression.Body)\n                .Method;\n\n        /// <summary>\n        /// Gets a generic method definition from a given delegate.\n        /// </summary>\n        /// <typeparam name=\"TInstance\">The type of the delegate's target.</typeparam>\n        /// <param name=\"delegateExpression\">An expression representing a given method call.</param>\n        /// <returns>The generic method definition for the method in <paramref name=\"delegateExpression\"/></returns>\n        public static MethodInfo GetMethodInfo<TInstance>(Expression<Action<TInstance>> delegateExpression)\n            => ((MethodCallExpression)delegateExpression.Body)\n                .Method;\n\n        /// <summary>\n        /// Gets a generic method definition from a given delegate.\n        /// </summary>\n        /// <param name=\"delegateExpression\">An expression representing a given method call.</param>\n        /// <returns>The generic method definition for the method in <paramref name=\"delegateExpression\"/></returns>\n        public static MethodInfo GetGenericMethodDefinition(Expression<Action> delegateExpression)\n            => ((MethodCallExpression)delegateExpression.Body)\n                .Method\n                .GetGenericMethodDefinition();\n\n        /// <summary>\n        /// Gets a generic method definition from a given delegate.\n        /// </summary>\n        /// <typeparam name=\"T\">The type of the delegate's return value.</typeparam>\n        /// <param name=\"delegateExpression\">An expression representing a given method call.</param>\n        /// <returns>The generic method definition for the method in <paramref name=\"delegateExpression\"/></returns>\n        public static MethodInfo GetGenericMethodDefinition<T>(Expression<Func<T>> delegateExpression)\n            => ((MethodCallExpression)delegateExpression.Body)\n                .Method\n                .GetGenericMethodDefinition();\n\n        /// <summary>\n        /// Gets a generic method definition from a given delegate.\n        /// </summary>\n        /// <typeparam name=\"TIn\">The type of item on which the delegate is called.</typeparam>\n        /// <typeparam name=\"TOut\">The type of the delegate's return value.</typeparam>\n        /// <param name=\"delegateExpression\">An expression representing a given method call.</param>\n        /// <returns>The generic method definition for the method in <paramref name=\"delegateExpression\"/></returns>\n        public static MethodInfo GetGenericMethodDefinition<TIn, TOut>(Expression<Func<TIn, TOut>> delegateExpression)\n            => ((MethodCallExpression)delegateExpression.Body)\n                .Method\n                .GetGenericMethodDefinition();\n\n        /// <summary>\n        /// Gets a constructor from a given delegate expression.\n        /// </summary>\n        /// <param name=\"newExpression\">An <see cref=\"Expression\"/> for a delegate that returns a new object.</param>\n        /// <typeparam name=\"T\">The type of item being constructed.</typeparam>\n        /// <returns>The <see cref=\"ConstructorInfo\"/> for the constructor referenced in <paramref name=\"newExpression\"/></returns>\n        public static ConstructorInfo GetConstructor<T>(Expression<Func<T>> newExpression)\n            => Check.Is<NewExpression>(newExpression?.Body, nameof(newExpression)).Constructor;\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/MongoDbUtilities.cs",
    "content": "﻿using System;\nusing System.Text.RegularExpressions;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\n// ReSharper disable once CheckNamespace\nnamespace Blueshift.EntityFrameworkCore.MongoDB\n{\n    /// <summary>\n    /// A set of utilities to assist with MongoDb values.\n    /// </summary>\n    public static class MongoDbUtilities\n    {\n        private static readonly Regex LeadingUppercaseRegex\n            = new Regex(pattern: \"^(([A-Z](?![a-z]))+|([A-Z](?=[a-z])))\", options: RegexOptions.Compiled);\n        private static readonly Regex SingularRegex\n            = new Regex(pattern: \"(ey|.)(?<!s)$\", options: RegexOptions.IgnoreCase | RegexOptions.Compiled);\n\n        /// <summary>\n        /// Converts the first character or group of capital characters of a string to lower camel case.\n        /// </summary>\n        /// <param name=\"value\">The string to convert to lower camel case.</param>\n        /// <returns>A string containing a lower camel case version of the original <paramref name=\"value\"/>.</returns>\n        public static string ToLowerCamelCase([NotNull] string value)\n            => LeadingUppercaseRegex.Replace(\n                Check.NotNull(value, nameof(value)), match => match.Value.ToLower());\n\n        /// <summary>\n        /// Pluralizes a string by replacing any trailing 'y' with 'ies'.\n        /// </summary>\n        /// <param name=\"value\">The string to pluralize.</param>\n        /// <returns>A pluralized version of the original <paramref name=\"value\"/>.</returns>\n        public static string Pluralize([NotNull] string value)\n            => SingularRegex.Replace(\n                Check.NotNull(value, nameof(value)),\n                match => string.Equals(a: \"y\", b: match.Value, comparisonType: StringComparison.OrdinalIgnoreCase)\n                    ? \"ies\"\n                    : $\"{match.Value}s\");\n\n        /// <summary>\n        /// Determines whether or not the current <see cref=\"IEntityType\"/> represents a MongoDB root document.\n        /// </summary>\n        /// <param name=\"entityType\">The current <see cref=\"IEntityType\"/>.</param>\n        /// <returns><c>true</c> if <paramref name=\"entityType\"/> represents a root document; or <c>false</c>.</returns>\n        public static bool IsDocumentRootEntityType(this IEntityType entityType)\n        {\n            Check.NotNull(entityType, nameof(entityType));\n            while (entityType.MongoDb().IsDerivedType && entityType.BaseType != null)\n            {\n                entityType = entityType.BaseType;\n            }\n            return !entityType.IsOwned();\n        }\n\n        /// <summary>\n        /// Gets the <see cref=\"IEntityType\"/> that represents the least-derived, non-abstract base representation of a given class.\n        /// </summary>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> to start from.</param>\n        /// <returns>The least-derived, non-abstract root document type for <paramref name=\"entityType\"/>.</returns>\n        public static IEntityType GetMongoDbCollectionEntityType(this IEntityType entityType)\n        {\n            Check.NotOwned(entityType, nameof(entityType));\n\n            while (entityType.MongoDb().IsDerivedType && entityType.BaseType != null)\n            {\n                entityType = entityType.BaseType;\n            }\n\n            return entityType;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ObjectIdTypeConverter.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Globalization;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB\n{\n    /// <summary>\n    /// Provides methods for converting <see cref=\"ObjectId\"/> instances to other types.\n    /// </summary>\n    public class ObjectIdTypeConverter : TypeConverter\n    {\n        /// <summary>\n        /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context.\n        /// </summary>\n        /// <param name=\"context\">An <see cref=\"ITypeDescriptorContext\"/> that provides a format context.</param>\n        /// <param name=\"sourceType\">A <see cref=\"Type\"/> that represents the type you want to convert from.</param>\n        /// <returns><code>true</code> if the value can be converted; otherwise <code>false</code>.</returns>\n        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)\n            => (sourceType == typeof(string) || base.CanConvertFrom(context, sourceType));\n\n        /// <summary>\n        /// Converts the given object to the type of this converter, using the specified context and culture information.\n        /// </summary>\n        /// <param name=\"context\">An <see cref=\"ITypeDescriptorContext\"/> that provides a format context.</param>\n        /// <param name=\"culture\">The <see cref=\"CultureInfo\"/> to use as the current culture.</param>\n        /// <param name=\"value\">The object to convert.</param>\n        /// <returns>A new <see cref=\"ObjectId\"/> represented by <paramref name=\"value\"/>.</returns>\n        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)\n        {\n            if (!CanConvertFrom(context, Check.NotNull(value, nameof(value)).GetType()))\n            {\n                throw new InvalidOperationException($\"Cannot convert {value} to {typeof(ObjectId)}.\");\n            }\n            return ObjectId.Parse(value as string);\n        }\n\n        /// <summary>\n        /// Returns whether this converter can convert the object to the specified type, using the specified context.\n        /// </summary>\n        /// <param name=\"context\">An <see cref=\"ITypeDescriptorContext\"/> that provides a format context.</param>\n        /// <param name=\"destinationType\">A <see cref=\"Type\"/> that represents the type you want to convert to.</param>\n        /// <returns><code>true</code> if the value can be converted; otherwise <code>false</code>.</returns>\n        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)\n            => (destinationType == typeof(string)) || base.CanConvertTo(context, destinationType);\n\n        /// <summary>\n        /// Converts the given value object to the specified type, using the specified context and culture info.\n        /// </summary>\n        /// <param name=\"context\">An <see cref=\"ITypeDescriptorContext\"/> that provides a format context.</param>\n        /// <param name=\"culture\">The <see cref=\"CultureInfo\"/> to use as the current culture.</param>\n        /// <param name=\"value\">The object to convert.</param>\n        /// <param name=\"destinationType\">The type to convert the value parameter to.</param>\n        /// <returns>A new instance of the specified <paramref name=\"destinationType\"/> that represents <paramref name=\"value\"/>.</returns>\n        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)\n        {\n            if (!CanConvertTo(context, destinationType))\n            {\n                throw new InvalidOperationException($\"Cannot convert {value} to {destinationType}.\");\n            }\n            return value.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/AssemblyInfo.cs",
    "content": "﻿// Copyright (c) Blueshift Software, LLC. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Reflection;\nusing System.Resources;\n\n[assembly: NeutralResourcesLanguage(\"en-US\")]\n[assembly: AssemblyMetadata(\"Serviceable\", \"True\")]"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/Blueshift.EntityFrameworkCore.MongoDB.rd.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<Directives xmlns=\"http://schemas.microsoft.com/netfx/2013/01/metadata\">\n  <Library>\n    <Assembly Name=\"Blueshift.EntityFrameworkCore.MongoDB\" Dynamic=\"Required All\" />\n    <!-- TODO optimize this for types that actually need reflection -->\n  </Library>\n</Directives>"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/DocumentDbStrings.Designer.cs",
    "content": "﻿// <auto-generated />\n\nusing System.Reflection;\nusing System.Resources;\nusing JetBrains.Annotations;\n\nnamespace Microsoft.EntityFrameworkCore.Cosmos.Internal\n{\n    /// <summary>\n    ///\t\tThis API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public static class DocumentDbStrings\n    {\n        private static readonly ResourceManager _resourceManager\n            = new ResourceManager(\n                \"Blueshift.EntityFrameworkCore.MongoDb.Properties.CosmosStrings\",\n                typeof(DocumentDbStrings).GetTypeInfo().Assembly);\n\n        /// <summary>\n        ///     The entity of type '{entityType}' is mapped as a part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the corresponding key value. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the key values.\n        /// </summary>\n        public static string OrphanedNestedDocument(\n            [CanBeNull] object entityType,\n            [CanBeNull] object missingEntityType)\n            => string.Format(\n                GetString(\"OrphanedNestedDocument\", nameof(entityType), nameof(missingEntityType)),\n                entityType, missingEntityType);\n\n        /// <summary>\n        ///     The entity of type '{entityType}' is mapped as a part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the key value '{keyValue}'.\n        /// </summary>\n        public static string OrphanedNestedDocumentSensitive(\n            [CanBeNull] object entityType,\n            [CanBeNull] object missingEntityType,\n            [CanBeNull] object keyValue)\n            => string.Format(\n                GetString(\"OrphanedNestedDocumentSensitive\", nameof(entityType), nameof(missingEntityType), nameof(keyValue)),\n                entityType, missingEntityType, keyValue);\n\n        /// <summary>\n        ///     The entity of type '{entityType}' cannot be queried directly because it is mapped as a part of the document mapped to '{principalEntityType}'. Rewrite the query to start with '{principalEntityType}'.\n        /// </summary>\n        public static string QueryRootNestedEntityType(\n            [CanBeNull] object entityType,\n            [CanBeNull] object principalEntityType)\n            => string.Format(\n                GetString(\"QueryRootNestedEntityType\", nameof(entityType), nameof(principalEntityType)),\n                entityType, principalEntityType);\n\n        /// <summary>\n        ///     No matching discriminator values where found for this instance of '{entityType}'.\n        /// </summary>\n        public static string UnableToDiscriminate([CanBeNull] object entityType)\n            => string.Format(\n                GetString(\"UnableToDiscriminate\", nameof(entityType)),\n                entityType);\n\n        private static string GetString(string name, params string[] formatterNames)\n        {\n            var value = _resourceManager.GetString(name);\n            for (var i = 0; i < formatterNames.Length; i++)\n            {\n                value = value.Replace(\"{\" + formatterNames[i] + \"}\", \"{\" + i + \"}\");\n            }\n\n            return value;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/DocumentDbStrings.cs",
    "content": "﻿"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/DocumentDbStrings.resx",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n  <!-- \n    Microsoft ResX Schema \n    \n    Version 2.0\n    \n    The primary goals of this format is to allow a simple XML format \n    that is mostly human readable. The generation and parsing of the \n    various data types are done through the TypeConverter classes \n    associated with the data types.\n    \n    Example:\n    \n    ... ado.net/XML headers & schema ...\n    <resheader name=\"resmimetype\">text/microsoft-resx</resheader>\n    <resheader name=\"version\">2.0</resheader>\n    <resheader name=\"reader\">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\n    <resheader name=\"writer\">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\n    <data name=\"Name1\"><value>this is my long string</value><comment>this is a comment</comment></data>\n    <data name=\"Color1\" type=\"System.Drawing.Color, System.Drawing\">Blue</data>\n    <data name=\"Bitmap1\" mimetype=\"application/x-microsoft.net.object.binary.base64\">\n        <value>[base64 mime encoded serialized .NET Framework object]</value>\n    </data>\n    <data name=\"Icon1\" type=\"System.Drawing.Icon, System.Drawing\" mimetype=\"application/x-microsoft.net.object.bytearray.base64\">\n        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\n        <comment>This is a comment</comment>\n    </data>\n                \n    There are any number of \"resheader\" rows that contain simple \n    name/value pairs.\n    \n    Each data row contains a name, and value. The row also contains a \n    type or mimetype. Type corresponds to a .NET class that support \n    text/value conversion through the TypeConverter architecture. \n    Classes that don't support this are serialized and stored with the \n    mimetype set.\n    \n    The mimetype is used for serialized objects, and tells the \n    ResXResourceReader how to depersist the object. This is currently not \n    extensible. For a given mimetype the value must be set accordingly:\n    \n    Note - application/x-microsoft.net.object.binary.base64 is the format \n    that the ResXResourceWriter will generate, however the reader can \n    read any of the formats listed below.\n    \n    mimetype: application/x-microsoft.net.object.binary.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter\n            : and then encoded with base64 encoding.\n    \n    mimetype: application/x-microsoft.net.object.soap.base64\n    value   : The object must be serialized with \n            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\n            : and then encoded with base64 encoding.\n    mimetype: application/x-microsoft.net.object.bytearray.base64\n    value   : The object must be serialized into a byte array \n            : using a System.ComponentModel.TypeConverter\n            : and then encoded with base64 encoding.\n    -->\n  <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">\n    <xsd:import namespace=\"http://www.w3.org/XML/1998/namespace\" />\n    <xsd:element name=\"root\" msdata:IsDataSet=\"true\">\n      <xsd:complexType>\n        <xsd:choice maxOccurs=\"unbounded\">\n          <xsd:element name=\"metadata\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" use=\"required\" type=\"xsd:string\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"assembly\">\n            <xsd:complexType>\n              <xsd:attribute name=\"alias\" type=\"xsd:string\" />\n              <xsd:attribute name=\"name\" type=\"xsd:string\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"data\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n                <xsd:element name=\"comment\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"2\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" msdata:Ordinal=\"1\" />\n              <xsd:attribute name=\"type\" type=\"xsd:string\" msdata:Ordinal=\"3\" />\n              <xsd:attribute name=\"mimetype\" type=\"xsd:string\" msdata:Ordinal=\"4\" />\n              <xsd:attribute ref=\"xml:space\" />\n            </xsd:complexType>\n          </xsd:element>\n          <xsd:element name=\"resheader\">\n            <xsd:complexType>\n              <xsd:sequence>\n                <xsd:element name=\"value\" type=\"xsd:string\" minOccurs=\"0\" msdata:Ordinal=\"1\" />\n              </xsd:sequence>\n              <xsd:attribute name=\"name\" type=\"xsd:string\" use=\"required\" />\n            </xsd:complexType>\n          </xsd:element>\n        </xsd:choice>\n      </xsd:complexType>\n    </xsd:element>\n  </xsd:schema>\n  <resheader name=\"resmimetype\">\n    <value>text/microsoft-resx</value>\n  </resheader>\n  <resheader name=\"version\">\n    <value>2.0</value>\n  </resheader>\n  <resheader name=\"reader\">\n    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <resheader name=\"writer\">\n    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\n  </resheader>\n  <data name=\"OrphanedNestedDocument\" xml:space=\"preserve\">\n    <value>The entity of type '{entityType}' is mapped as a part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the corresponding key value. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the key values.</value>\n  </data>\n  <data name=\"OrphanedNestedDocumentSensitive\" xml:space=\"preserve\">\n    <value>The entity of type '{entityType}' is mapped as a part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the key value '{keyValue}'.</value>\n  </data>\n  <data name=\"QueryRootNestedEntityType\" xml:space=\"preserve\">\n    <value>The entity of type '{entityType}' cannot be queried directly because it is mapped as a part of the document mapped to '{principalEntityType}'. Rewrite the query to start with '{principalEntityType}'.</value>\n  </data>\n  <data name=\"UnableToDiscriminate\" xml:space=\"preserve\">\n    <value>No matching discriminator values where found for this instance of '{entityType}'.</value>\n  </data>\n</root>"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Properties/DocumentDbStrings.tt",
    "content": "﻿﻿<#\n    Session[\"ResourceFile\"] = \"DocumentDbStrings.resx\";\n    Session[\"NoDiagnostics\"] = true;\n#>\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/EntityLoadInfoFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class EntityLoadInfoFactory : IEntityLoadInfoFactory\n    {\n        [NotNull] private readonly ICurrentDbContext _currentDbContext;\n        [NotNull] private readonly IValueBufferFactory _valueBufferFactory;\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"EntityLoadInfoFactory\"/>.\n        /// </summary>\n        /// <param name=\"currentDbContext\">Used to get the current <see cref=\"DbContext\"/> instance.</param>\n        /// <param name=\"valueBufferFactory\">An <see cref=\"IValueBufferFactory\"/> that can be used to create <see cref=\"ValueBuffer\"/>\n        /// for loading documents.</param>\n        public EntityLoadInfoFactory(\n            [NotNull] ICurrentDbContext currentDbContext,\n            [NotNull] IValueBufferFactory valueBufferFactory)\n        {\n            _currentDbContext = Check.NotNull(currentDbContext, nameof(currentDbContext));\n            _valueBufferFactory = Check.NotNull(valueBufferFactory, nameof(valueBufferFactory));\n        }\n\n        /// <inheritdoc />\n        public EntityLoadInfo Create(object document, IEntityType entityType, object owner, INavigation owningNavigation)\n        {\n            Check.NotNull(document, nameof(document));\n            Check.NotNull(entityType, nameof(entityType));\n\n            if (document.GetType() != entityType.ClrType)\n            {\n                Check.IsInstanceOfType(document, entityType.ClrType, nameof(document));\n\n                entityType = entityType.Model.FindEntityType(document.GetType());\n            }\n\n            return new EntityLoadInfo(\n                new MaterializationContext(\n                    _valueBufferFactory.CreateFromInstance(\n                        document,\n                        entityType,\n                        owner,\n                        owningNavigation),\n                    _currentDbContext.Context),\n                materializationContext => document,\n                null);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/DocumentNavigationRewritingExpressionVisitor.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Extensions.Internal;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.Expressions.Internal;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Microsoft.EntityFrameworkCore.Query.ResultOperators.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Remotion.Linq;\nusing Remotion.Linq.Clauses;\nusing Remotion.Linq.Clauses.Expressions;\nusing Remotion.Linq.Clauses.ExpressionVisitors;\nusing Remotion.Linq.Clauses.ResultOperators;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class DocumentNavigationRewritingExpressionVisitor : NavigationRewritingExpressionVisitor\n    {\n        private readonly EntityQueryModelVisitor _queryModelVisitor;\n        private readonly NavigationJoins _navigationJoins = new NavigationJoins();\n        private readonly DocumentNavigationRewritingQueryModelVisitor _documentNavigationRewritingQueryModelVisitor;\n        private QueryModel _queryModel;\n        private QueryModel _parentQueryModel;\n\n        private bool _insideInnerKeySelector;\n        private bool _insideOrderBy;\n        private bool _insideMaterializeCollectionNavigation;\n\n        private class NavigationJoins : IEnumerable<NavigationJoin>\n        {\n            private readonly Dictionary<NavigationJoin, int> _navigationJoins = new Dictionary<NavigationJoin, int>();\n\n            public void Add(NavigationJoin navigationJoin)\n            {\n                _navigationJoins.TryGetValue(navigationJoin, out int count);\n                _navigationJoins[navigationJoin] = ++count;\n            }\n\n            public bool Remove(NavigationJoin navigationJoin)\n            {\n                if (_navigationJoins.TryGetValue(navigationJoin, out int count))\n                {\n                    if (count > 1)\n                    {\n                        _navigationJoins[navigationJoin] = --count;\n                    }\n                    else\n                    {\n                        _navigationJoins.Remove(navigationJoin);\n                    }\n\n                    return true;\n                }\n\n                return false;\n            }\n\n            public IEnumerator<NavigationJoin> GetEnumerator() => _navigationJoins.Keys.GetEnumerator();\n\n            IEnumerator IEnumerable.GetEnumerator() => _navigationJoins.Keys.GetEnumerator();\n        }\n\n        private class NavigationJoin\n        {\n            public static void RemoveNavigationJoin(\n                NavigationJoins navigationJoins, NavigationJoin navigationJoin)\n            {\n                if (!navigationJoins.Remove(navigationJoin))\n                {\n                    foreach (NavigationJoin nj in navigationJoins)\n                    {\n                        nj.Children.Remove(navigationJoin);\n                    }\n                }\n            }\n\n            public NavigationJoin(\n                IQuerySource querySource,\n                INavigation navigation,\n                JoinClause joinClause,\n                IEnumerable<IBodyClause> additionalBodyClauses,\n                bool dependentToPrincipal,\n                QuerySourceReferenceExpression querySourceReferenceExpression)\n                : this(\n                    querySource,\n                    navigation,\n                    joinClause,\n                    null,\n                    additionalBodyClauses,\n                    dependentToPrincipal,\n                    querySourceReferenceExpression)\n            {\n            }\n\n            public NavigationJoin(\n                IQuerySource querySource,\n                INavigation navigation,\n                GroupJoinClause groupJoinClause,\n                IEnumerable<IBodyClause> additionalBodyClauses,\n                bool dependentToPrincipal,\n                QuerySourceReferenceExpression querySourceReferenceExpression)\n                : this(\n                    querySource,\n                    navigation,\n                    null,\n                    groupJoinClause,\n                    additionalBodyClauses,\n                    dependentToPrincipal,\n                    querySourceReferenceExpression)\n            {\n            }\n\n            private NavigationJoin(\n                IQuerySource querySource,\n                INavigation navigation,\n                JoinClause joinClause,\n                GroupJoinClause groupJoinClause,\n                IEnumerable<IBodyClause> additionalBodyClauses,\n                bool dependentToPrincipal,\n                QuerySourceReferenceExpression querySourceReferenceExpression)\n            {\n                QuerySource = querySource;\n                Navigation = navigation;\n                JoinClause = joinClause;\n                GroupJoinClause = groupJoinClause;\n                AdditionalBodyClauses = additionalBodyClauses;\n                DependentToPrincipal = dependentToPrincipal;\n                QuerySourceReferenceExpression = querySourceReferenceExpression;\n            }\n\n            public IQuerySource QuerySource { get; }\n            public INavigation Navigation { get; }\n            public JoinClause JoinClause { get; }\n            public GroupJoinClause GroupJoinClause { get; }\n            public bool DependentToPrincipal { get; }\n            public QuerySourceReferenceExpression QuerySourceReferenceExpression { get; }\n            public readonly NavigationJoins Children = new NavigationJoins();\n\n            private IEnumerable<IBodyClause> AdditionalBodyClauses { get; }\n\n            private bool IsInserted { get; set; }\n\n            public IEnumerable<NavigationJoin> Iterate()\n            {\n                yield return this;\n\n                foreach (NavigationJoin navigationJoin in Children.SelectMany(nj => nj.Iterate()))\n                {\n                    yield return navigationJoin;\n                }\n            }\n\n            public void Insert(QueryModel queryModel)\n            {\n                int insertionIndex = 0;\n\n                if (QuerySource is IBodyClause bodyClause)\n                {\n                    insertionIndex = queryModel.BodyClauses.IndexOf(bodyClause) + 1;\n                }\n\n                if (queryModel.MainFromClause == QuerySource\n                    || insertionIndex > 0)\n                {\n                    foreach (NavigationJoin nj in Iterate())\n                    {\n                        nj.Insert(queryModel, ref insertionIndex);\n                    }\n                }\n            }\n\n            private void Insert(QueryModel queryModel, ref int insertionIndex)\n            {\n                if (IsInserted)\n                {\n                    return;\n                }\n\n                queryModel.BodyClauses.Insert(insertionIndex++, JoinClause ?? (IBodyClause)GroupJoinClause);\n\n                foreach (IBodyClause additionalBodyClause in AdditionalBodyClauses)\n                {\n                    queryModel.BodyClauses.Insert(insertionIndex++, additionalBodyClause);\n                }\n\n                IsInserted = true;\n            }\n        }\n\n        /// <inheritdoc />\n        public DocumentNavigationRewritingExpressionVisitor([NotNull] EntityQueryModelVisitor queryModelVisitor)\n            : this(queryModelVisitor, navigationExpansionSubquery: false)\n        {\n        }\n\n        /// <inheritdoc />\n        public DocumentNavigationRewritingExpressionVisitor(\n            [NotNull] EntityQueryModelVisitor queryModelVisitor,\n            bool navigationExpansionSubquery)\n            : base(\n                Check.NotNull(queryModelVisitor, nameof(queryModelVisitor)),\n                navigationExpansionSubquery)\n        {\n            Check.NotNull(queryModelVisitor, nameof(queryModelVisitor));\n\n            _queryModelVisitor = queryModelVisitor;\n            _documentNavigationRewritingQueryModelVisitor = new DocumentNavigationRewritingQueryModelVisitor(this, _queryModelVisitor, navigationExpansionSubquery);\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected virtual bool ShouldRewrite(INavigation navigation)\n            => !navigation.ForeignKey.IsOwnership;\n\n        /// <inheritdoc />\n        public override void Rewrite(QueryModel queryModel, QueryModel parentQueryModel)\n        {\n            _queryModel = queryModel;\n            _parentQueryModel = parentQueryModel;\n\n            _documentNavigationRewritingQueryModelVisitor.VisitQueryModel(_queryModel);\n\n            foreach (NavigationJoin navigationJoin in _navigationJoins)\n            {\n                navigationJoin.Insert(_queryModel);\n            }\n\n            if (parentQueryModel != null)\n            {\n                _queryModel = parentQueryModel;\n            }\n        }\n\n        /// <inheritdoc />\n        protected override Expression VisitUnary(UnaryExpression node)\n        {\n            Expression newOperand = Visit(node.Operand);\n\n            return node.NodeType == ExpressionType.Convert && newOperand.Type == node.Type\n                ? newOperand\n                : node.Update(newOperand);\n        }\n\n        /// <inheritdoc />\n        protected override Expression VisitSubQuery(SubQueryExpression expression)\n        {\n            bool oldInsideInnerKeySelector = _insideInnerKeySelector;\n            _insideInnerKeySelector = false;\n\n            Rewrite(expression.QueryModel, _queryModel);\n\n            _insideInnerKeySelector = oldInsideInnerKeySelector;\n\n            return expression;\n        }\n\n        /// <inheritdoc />\n        protected override Expression VisitBinary(BinaryExpression node)\n        {\n            Expression newLeft = Visit(node.Left);\n            Expression newRight = Visit(node.Right);\n\n            if (newLeft == node.Left\n                && newRight == node.Right)\n            {\n                return node;\n            }\n\n            NavigationJoin leftNavigationJoin\n                = _navigationJoins\n                    .SelectMany(nj => nj.Iterate())\n                    .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newLeft));\n\n            NavigationJoin rightNavigationJoin\n                = _navigationJoins\n                    .SelectMany(nj => nj.Iterate())\n                    .FirstOrDefault(nj => ReferenceEquals(nj.QuerySourceReferenceExpression, newRight));\n\n            JoinClause leftJoin = leftNavigationJoin?.JoinClause ?? leftNavigationJoin?.GroupJoinClause?.JoinClause;\n            JoinClause rightJoin = rightNavigationJoin?.JoinClause ?? rightNavigationJoin?.GroupJoinClause?.JoinClause;\n\n            if (leftNavigationJoin?.Navigation.GetTargetType().IsOwned() == false)\n            {\n                if (newRight.IsNullConstantExpression())\n                {\n                    if (leftNavigationJoin.DependentToPrincipal)\n                    {\n                        newLeft = leftJoin?.OuterKeySelector;\n\n                        NavigationJoin.RemoveNavigationJoin(_navigationJoins, leftNavigationJoin);\n\n                        if (newLeft != null\n                            && IsCompositeKey(newLeft.Type))\n                        {\n                            newRight = CreateNullCompositeKey(newLeft);\n                        }\n                    }\n                }\n                else\n                {\n                    newLeft = leftJoin?.InnerKeySelector;\n                }\n            }\n\n            if (rightNavigationJoin?.Navigation.GetTargetType().IsOwned() == false)\n            {\n                if (newLeft.IsNullConstantExpression())\n                {\n                    if (rightNavigationJoin.DependentToPrincipal)\n                    {\n                        newRight = rightJoin?.OuterKeySelector;\n\n                        NavigationJoin.RemoveNavigationJoin(_navigationJoins, rightNavigationJoin);\n\n                        if (newRight != null\n                            && IsCompositeKey(newRight.Type))\n                        {\n                            newLeft = CreateNullCompositeKey(newRight);\n                        }\n                    }\n                }\n                else\n                {\n                    newRight = rightJoin?.InnerKeySelector;\n                }\n            }\n\n            if (node.NodeType != ExpressionType.ArrayIndex\n                && node.NodeType != ExpressionType.Coalesce\n                && newLeft != null\n                && newRight != null\n                && newLeft.Type != newRight.Type)\n            {\n                if (newLeft.Type.IsNullableType()\n                    && !newRight.Type.IsNullableType())\n                {\n                    newRight = Expression.Convert(newRight, newLeft.Type);\n                }\n                else if (!newLeft.Type.IsNullableType()\n                         && newRight.Type.IsNullableType())\n                {\n                    newLeft = Expression.Convert(newLeft, newRight.Type);\n                }\n            }\n\n            return Expression.MakeBinary(node.NodeType, newLeft, newRight, node.IsLiftedToNull, node.Method);\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected override Expression VisitConditional(ConditionalExpression node)\n        {\n            Expression test = Visit(node.Test);\n            if (test.Type == typeof(bool?))\n            {\n                test = Expression.Equal(test, Expression.Constant(true, typeof(bool?)));\n            }\n\n            Expression ifTrue = Visit(node.IfTrue);\n            Expression ifFalse = Visit(node.IfFalse);\n\n            if (ifTrue.Type.IsNullableType()\n                && !ifFalse.Type.IsNullableType())\n            {\n                ifFalse = Expression.Convert(ifFalse, ifTrue.Type);\n            }\n\n            if (ifFalse.Type.IsNullableType()\n                && !ifTrue.Type.IsNullableType())\n            {\n                ifTrue = Expression.Convert(ifTrue, ifFalse.Type);\n            }\n\n            return test != node.Test || ifTrue != node.IfTrue || ifFalse != node.IfFalse\n                ? Expression.Condition(test, ifTrue, ifFalse)\n                : node;\n        }\n\n        private static NewExpression CreateNullCompositeKey(Expression otherExpression)\n            => Expression.New(\n                AnonymousObject.AnonymousObjectCtor,\n                Expression.NewArrayInit(\n                    typeof(object),\n                    Enumerable.Repeat(\n                        Expression.Constant(null),\n                        ((NewArrayExpression)((NewExpression)otherExpression).Arguments.Single()).Expressions.Count)));\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected override Expression VisitMember(MemberExpression node)\n        {\n            Check.NotNull(node, nameof(node));\n\n            Expression result = _queryModelVisitor.BindNavigationPathPropertyExpression(\n                node,\n                (ps, qs) =>\n                {\n                    return qs != null\n                        ? RewriteNavigationProperties(\n                            ps,\n                            qs,\n                            node,\n                            node.Expression,\n                            node.Member.Name,\n                            node.Type,\n                            e => e.MakeMemberAccess(node.Member),\n                            e => new NullConditionalExpression(e, e.MakeMemberAccess(node.Member)))\n                        : null;\n                });\n\n            if (result != null)\n            {\n                return result;\n            }\n\n            Expression newExpression = Visit(node.Expression);\n\n            MemberExpression newMemberExpression = newExpression != node.Expression\n                ? newExpression.MakeMemberAccess(node.Member)\n                : node;\n\n            result = NeedsNullCompensation(newExpression)\n                ? (Expression)new NullConditionalExpression(\n                    newExpression,\n                    newMemberExpression)\n                : newMemberExpression;\n\n            return result.Type == typeof(bool?) && node.Type == typeof(bool)\n                ? Expression.Equal(result, Expression.Constant(true, typeof(bool?)))\n                : result;\n        }\n\n        private readonly Dictionary<QuerySourceReferenceExpression, bool> _nullCompensationNecessityMap\n            = new Dictionary<QuerySourceReferenceExpression, bool>();\n\n        private bool NeedsNullCompensation(Expression expression)\n        {\n            if (expression is QuerySourceReferenceExpression qsre)\n            {\n                if (_nullCompensationNecessityMap.TryGetValue(qsre, out bool result))\n                {\n                    return result;\n                }\n\n                SubQueryExpression subQuery = (qsre.ReferencedQuerySource as FromClauseBase)?.FromExpression as SubQueryExpression\n                               ?? (qsre.ReferencedQuerySource as JoinClause)?.InnerSequence as SubQueryExpression;\n\n                // if qsre is pointing to a subquery, look for DefaulIfEmpty result operators inside\n                // if such operator is found then we need to add null-compensation logic\n                // unless the query model has a GroupBy operator - qsre coming from groupby can never be null\n                if (subQuery != null\n                    && !(subQuery.QueryModel.ResultOperators.LastOrDefault() is GroupResultOperator))\n                {\n                    ContainsDefaultIfEmptyCheckingVisitor containsDefaultIfEmptyChecker = new ContainsDefaultIfEmptyCheckingVisitor();\n                    containsDefaultIfEmptyChecker.VisitQueryModel(subQuery.QueryModel);\n                    if (!containsDefaultIfEmptyChecker.ContainsDefaultIfEmpty)\n                    {\n                        subQuery.QueryModel.TransformExpressions(\n                            e => new TransformingQueryModelExpressionVisitor<ContainsDefaultIfEmptyCheckingVisitor>(containsDefaultIfEmptyChecker).Visit(e));\n                    }\n\n                    _nullCompensationNecessityMap[qsre] = containsDefaultIfEmptyChecker.ContainsDefaultIfEmpty;\n\n                    return containsDefaultIfEmptyChecker.ContainsDefaultIfEmpty;\n                }\n\n                _nullCompensationNecessityMap[qsre] = false;\n            }\n\n            return false;\n        }\n\n        private class ContainsDefaultIfEmptyCheckingVisitor : QueryModelVisitorBase\n        {\n            public bool ContainsDefaultIfEmpty { get; private set; }\n\n            public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index)\n            {\n                if (resultOperator is DefaultIfEmptyResultOperator)\n                {\n                    ContainsDefaultIfEmpty = true;\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)\n        {\n            Expression newExpression = CompensateForNullabilityDifference(\n                Visit(node.Expression),\n                node.Expression.Type);\n\n            return node.Update(newExpression);\n        }\n\n        /// <inheritdoc />\n        protected override ElementInit VisitElementInit(ElementInit node)\n        {\n            List<Type> originalArgumentTypes = node.Arguments.Select(a => a.Type).ToList();\n            List<Expression> newArguments = VisitAndConvert(node.Arguments, nameof(VisitElementInit)).ToList();\n\n            for (int i = 0; i < newArguments.Count; i++)\n            {\n                newArguments[i] = CompensateForNullabilityDifference(newArguments[i], originalArgumentTypes[i]);\n            }\n\n            return node.Update(newArguments);\n        }\n\n        /// <inheritdoc />\n        protected override Expression VisitNewArray(NewArrayExpression node)\n        {\n            List<Type> originalExpressionTypes = node.Expressions.Select(e => e.Type).ToList();\n            List<Expression> newExpressions = VisitAndConvert(node.Expressions, nameof(VisitNewArray)).ToList();\n\n            for (int i = 0; i < newExpressions.Count; i++)\n            {\n                newExpressions[i] = CompensateForNullabilityDifference(newExpressions[i], originalExpressionTypes[i]);\n            }\n\n            return node.Update(newExpressions);\n        }\n\n        /// <inheritdoc />\n        protected override Expression VisitMethodCall(MethodCallExpression node)\n        {\n            Check.NotNull(node, nameof(node));\n\n            if (node.Method.IsEFPropertyMethod())\n            {\n                Expression result = _queryModelVisitor.BindNavigationPathPropertyExpression(\n                    node,\n                    (ps, qs) =>\n                    {\n                        return qs != null\n                            ? RewriteNavigationProperties(\n                                ps,\n                                qs,\n                                node,\n                                node.Arguments[0],\n                                (string)((ConstantExpression)node.Arguments[1]).Value,\n                                node.Type,\n                                e => node.Arguments[0].Type != e.Type\n                                    ? Expression.Call(node.Method, Expression.Convert(e, node.Arguments[0].Type), node.Arguments[1])\n                                    : Expression.Call(node.Method, e, node.Arguments[1]),\n                                e => node.Arguments[0].Type != e.Type\n                                    ? new NullConditionalExpression(\n                                        Expression.Convert(e, node.Arguments[0].Type),\n                                        Expression.Call(node.Method, Expression.Convert(e, node.Arguments[0].Type), node.Arguments[1]))\n                                    : new NullConditionalExpression(e, Expression.Call(node.Method, e, node.Arguments[1])))\n                            : null;\n                    });\n\n                if (result != null)\n                {\n                    return result;\n                }\n\n                List<Expression> propertyArguments = VisitAndConvert(node.Arguments, nameof(VisitMethodCall)).ToList();\n\n                MethodCallExpression newPropertyExpression = propertyArguments[0] != node.Arguments[0] || propertyArguments[1] != node.Arguments[1]\n                    ? Expression.Call(node.Method, propertyArguments[0], node.Arguments[1])\n                    : node;\n\n                result = NeedsNullCompensation(propertyArguments[0])\n                    ? (Expression)new NullConditionalExpression(propertyArguments[0], newPropertyExpression)\n                    : newPropertyExpression;\n\n                return result.Type == typeof(bool?) && node.Type == typeof(bool)\n                    ? Expression.Equal(result, Expression.Constant(true, typeof(bool?)))\n                    : result;\n            }\n\n            bool insideMaterializeCollectionNavigation = _insideMaterializeCollectionNavigation;\n            if (node.Method.MethodIsClosedFormOf(CollectionNavigationSubqueryInjector.MaterializeCollectionNavigationMethodInfo))\n            {\n                _insideMaterializeCollectionNavigation = true;\n            }\n\n            Expression newObject = Visit(node.Object);\n            List<Expression> newArguments = VisitAndConvert(node.Arguments, nameof(VisitMethodCall)).ToList();\n\n            for (int i = 0; i < newArguments.Count; i++)\n            {\n                if (newArguments[i].Type != node.Arguments[i].Type)\n                {\n                    if (newArguments[i] is NullConditionalExpression nullConditionalArgument)\n                    {\n                        newArguments[i] = nullConditionalArgument.AccessOperation;\n                    }\n\n                    if (newArguments[i].Type != node.Arguments[i].Type)\n                    {\n                        newArguments[i] = Expression.Convert(newArguments[i], node.Arguments[i].Type);\n                    }\n                }\n            }\n\n            if (newObject != node.Object)\n            {\n                if (newObject is NullConditionalExpression nullConditionalExpression)\n                {\n                    MethodCallExpression newMethodCallExpression = node.Update(nullConditionalExpression.AccessOperation, newArguments);\n\n                    return new NullConditionalExpression(newObject, newMethodCallExpression);\n                }\n            }\n\n            MethodCallExpression newExpression = node.Update(newObject, newArguments);\n\n            if (node.Method.MethodIsClosedFormOf(CollectionNavigationSubqueryInjector.MaterializeCollectionNavigationMethodInfo))\n            {\n                _insideMaterializeCollectionNavigation = insideMaterializeCollectionNavigation;\n            }\n\n            return newExpression;\n        }\n\n        private Expression RewriteNavigationProperties(\n            IReadOnlyList<IPropertyBase> properties,\n            IQuerySource querySource,\n            Expression expression,\n            Expression declaringExpression,\n            string propertyName,\n            Type propertyType,\n            Func<Expression, Expression> propertyCreator,\n            Func<Expression, Expression> conditionalAccessPropertyCreator)\n        {\n            List<INavigation> navigations = properties.OfType<INavigation>().ToList();\n\n            if (navigations.Count > 0)\n            {\n                QuerySourceReferenceExpression outerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(querySource);\n\n                AdditionalFromClause additionalFromClauseBeingProcessed = _documentNavigationRewritingQueryModelVisitor.AdditionalFromClauseBeingProcessed;\n                if (additionalFromClauseBeingProcessed != null\n                    && navigations.Last().IsCollection()\n                    && !_insideMaterializeCollectionNavigation)\n                {\n                    if (additionalFromClauseBeingProcessed.FromExpression is SubQueryExpression fromSubqueryExpression)\n                    {\n                        if (fromSubqueryExpression.QueryModel.SelectClause.Selector is QuerySourceReferenceExpression)\n                        {\n                            return RewriteSelectManyInsideSubqueryIntoJoins(\n                                fromSubqueryExpression,\n                                outerQuerySourceReferenceExpression,\n                                navigations,\n                                additionalFromClauseBeingProcessed);\n                        }\n                    }\n                    else\n                    {\n                        return RewriteSelectManyNavigationsIntoJoins(\n                            outerQuerySourceReferenceExpression,\n                            navigations,\n                            additionalFromClauseBeingProcessed);\n                    }\n                }\n\n                if (navigations.Count == 1\n                    && navigations[0].IsDependentToPrincipal())\n                {\n                    Expression foreignKeyMemberAccess = TryCreateForeignKeyMemberAccess(propertyName, declaringExpression, navigations[0]);\n                    if (foreignKeyMemberAccess != null)\n                    {\n                        return foreignKeyMemberAccess;\n                    }\n                }\n\n                if (_insideInnerKeySelector && !_insideMaterializeCollectionNavigation)\n                {\n                    return CreateSubqueryForNavigations(\n                        outerQuerySourceReferenceExpression,\n                        properties,\n                        propertyCreator);\n                }\n\n                Expression navigationResultExpression = RewriteNavigationsIntoJoins(\n                    outerQuerySourceReferenceExpression,\n                    navigations,\n                    properties.Count == navigations.Count ? null : propertyType,\n                    propertyCreator,\n                    conditionalAccessPropertyCreator);\n\n                if (navigationResultExpression is QuerySourceReferenceExpression resultQsre)\n                {\n                    foreach (IncludeResultOperator includeResultOperator in _queryModelVisitor.QueryCompilationContext.QueryAnnotations\n                        .OfType<IncludeResultOperator>()\n                        .Where(o => ExpressionEqualityComparer.Instance.Equals(o.PathFromQuerySource, expression)))\n                    {\n                        includeResultOperator.PathFromQuerySource = resultQsre;\n                        includeResultOperator.QuerySource = resultQsre.ReferencedQuerySource;\n                    }\n                }\n\n                return navigationResultExpression;\n            }\n\n            return default;\n        }\n\n        private class QsreWithNavigationFindingExpressionVisitor : ExpressionVisitorBase\n        {\n            private readonly QuerySourceReferenceExpression _searchedQsre;\n            private readonly INavigation _navigation;\n            private bool _navigationFound;\n\n            public QsreWithNavigationFindingExpressionVisitor([NotNull] QuerySourceReferenceExpression searchedQsre, [NotNull] INavigation navigation)\n            {\n                _searchedQsre = searchedQsre;\n                _navigation = navigation;\n                _navigationFound = false;\n                SearchedQsreFound = false;\n            }\n\n            public bool SearchedQsreFound { get; private set; }\n\n            protected override Expression VisitMember(MemberExpression node)\n            {\n                if (!_navigationFound\n                    && node.Member.Name == _navigation.Name)\n                {\n                    _navigationFound = true;\n\n                    return base.VisitMember(node);\n                }\n\n                _navigationFound = false;\n\n                return node;\n            }\n\n            protected override Expression VisitMethodCall(MethodCallExpression node)\n            {\n                if (node.Method.IsEFPropertyMethod()\n                    && !_navigationFound\n                    && (string)((ConstantExpression)node.Arguments[1]).Value == _navigation.Name)\n                {\n                    _navigationFound = true;\n\n                    return base.VisitMethodCall(node);\n                }\n\n                _navigationFound = false;\n\n                return node;\n            }\n\n            protected override Expression VisitQuerySourceReference(QuerySourceReferenceExpression expression)\n            {\n                if (_navigationFound && expression.ReferencedQuerySource == _searchedQsre.ReferencedQuerySource)\n                {\n                    SearchedQsreFound = true;\n                }\n                else\n                {\n                    _navigationFound = false;\n                }\n\n                return expression;\n            }\n        }\n\n        private Expression TryCreateForeignKeyMemberAccess(string propertyName, Expression declaringExpression, INavigation navigation)\n        {\n            bool canPerformOptimization = true;\n            if (_insideOrderBy)\n            {\n                QuerySourceReferenceExpression qsre = (declaringExpression as MemberExpression)?.Expression as QuerySourceReferenceExpression;\n                if (qsre == null)\n                {\n                    if (declaringExpression is MethodCallExpression methodCallExpression\n                        && methodCallExpression.Method.IsEFPropertyMethod())\n                    {\n                        qsre = methodCallExpression.Arguments[0] as QuerySourceReferenceExpression;\n                    }\n                }\n\n                if (qsre != null)\n                {\n                    QsreWithNavigationFindingExpressionVisitor qsreFindingVisitor = new QsreWithNavigationFindingExpressionVisitor(qsre, navigation);\n                    qsreFindingVisitor.Visit(_queryModel.SelectClause.Selector);\n\n                    if (qsreFindingVisitor.SearchedQsreFound)\n                    {\n                        canPerformOptimization = false;\n                    }\n                }\n            }\n\n            if (canPerformOptimization)\n            {\n                Expression foreignKeyMemberAccess = CreateForeignKeyMemberAccess(propertyName, declaringExpression, navigation);\n                if (foreignKeyMemberAccess != null)\n                {\n                    return foreignKeyMemberAccess;\n                }\n            }\n\n            return null;\n        }\n\n        private static Expression CreateForeignKeyMemberAccess(string propertyName, Expression declaringExpression, INavigation navigation)\n        {\n            IKey principalKey = navigation.ForeignKey.PrincipalKey;\n            if (principalKey.Properties.Count == 1)\n            {\n                Debug.Assert(navigation.ForeignKey.Properties.Count == 1);\n\n                IProperty principalKeyProperty = principalKey.Properties[0];\n                if (principalKeyProperty.Name == propertyName\n                    && principalKeyProperty.ClrType == navigation.ForeignKey.Properties[0].ClrType.UnwrapNullableType())\n                {\n                    Expression parentDeclaringExpression\n                        = declaringExpression is MethodCallExpression declaringMethodCallExpression\n                          && declaringMethodCallExpression.Method.IsEFPropertyMethod()\n                            ? declaringMethodCallExpression.Arguments[0]\n                            : (declaringExpression as MemberExpression)?.Expression;\n\n                    if (parentDeclaringExpression != null)\n                    {\n                        Expression foreignKeyPropertyExpression = CreateKeyAccessExpression(parentDeclaringExpression, navigation.ForeignKey.Properties);\n\n                        return foreignKeyPropertyExpression;\n                    }\n                }\n            }\n\n            return null;\n        }\n\n        private Expression CreateSubqueryForNavigations(\n            Expression outerQuerySourceReferenceExpression,\n            IReadOnlyList<IPropertyBase> properties,\n            Func<Expression, Expression> propertyCreator)\n        {\n            List<INavigation> navigations = properties.OfType<INavigation>().ToList();\n            INavigation firstNavigation = navigations.First();\n            IEntityType targetEntityType = firstNavigation.GetTargetType();\n\n            MainFromClause mainFromClause\n                = new MainFromClause(\n                    \"subQuery\",\n                    targetEntityType.ClrType,\n                    NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(targetEntityType.ClrType));\n\n            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(mainFromClause, targetEntityType);\n            QuerySourceReferenceExpression querySourceReference = new QuerySourceReferenceExpression(mainFromClause);\n            QueryModel subQueryModel = new QueryModel(mainFromClause, new SelectClause(querySourceReference));\n\n            Expression leftKeyAccess = CreateKeyAccessExpression(\n                querySourceReference,\n                firstNavigation.IsDependentToPrincipal()\n                    ? firstNavigation.ForeignKey.PrincipalKey.Properties\n                    : firstNavigation.ForeignKey.Properties);\n\n            Expression rightKeyAccess = CreateKeyAccessExpression(\n                outerQuerySourceReferenceExpression,\n                firstNavigation.IsDependentToPrincipal()\n                    ? firstNavigation.ForeignKey.Properties\n                    : firstNavigation.ForeignKey.PrincipalKey.Properties);\n\n            subQueryModel.BodyClauses.Add(\n                new WhereClause(\n                    CreateKeyComparisonExpressionForCollectionNavigationSubquery(\n                        leftKeyAccess,\n                        rightKeyAccess,\n                        querySourceReference)));\n\n            subQueryModel.ResultOperators.Add(new FirstResultOperator(returnDefaultWhenEmpty: true));\n\n            Expression selectClauseExpression = (Expression)querySourceReference;\n\n            selectClauseExpression\n                = navigations\n                    .Skip(1)\n                    .Aggregate(\n                        selectClauseExpression,\n                        (current, navigation) => Expression.Property(current, navigation.Name));\n\n            subQueryModel.SelectClause = new SelectClause(selectClauseExpression);\n\n            if (properties.Count > navigations.Count)\n            {\n                subQueryModel.SelectClause = new SelectClause(propertyCreator(subQueryModel.SelectClause.Selector));\n            }\n\n            if (navigations.Count > 1)\n            {\n                NavigationRewritingExpressionVisitor subQueryVisitor = CreateVisitorForSubQuery(navigationExpansionSubquery: true);\n                subQueryVisitor.Rewrite(subQueryModel, parentQueryModel: null);\n            }\n\n            return new SubQueryExpression(subQueryModel);\n        }\n\n        /// <inheritdoc />\n        public override NavigationRewritingExpressionVisitor CreateVisitorForSubQuery(bool navigationExpansionSubquery)\n            => new NavigationRewritingExpressionVisitor(\n                _queryModelVisitor,\n                navigationExpansionSubquery);\n\n        private static Expression CreateKeyComparisonExpressionForCollectionNavigationSubquery(\n            Expression leftExpression,\n            Expression rightExpression,\n            Expression leftQsre)\n        {\n            if (leftExpression.Type != rightExpression.Type)\n            {\n                if (leftExpression.Type.IsNullableType())\n                {\n                    Debug.Assert(leftExpression.Type.UnwrapNullableType() == rightExpression.Type);\n\n                    rightExpression = Expression.Convert(rightExpression, leftExpression.Type);\n                }\n                else\n                {\n                    Debug.Assert(rightExpression.Type.IsNullableType());\n                    Debug.Assert(rightExpression.Type.UnwrapNullableType() == leftExpression.Type);\n\n                    leftExpression = Expression.Convert(leftExpression, rightExpression.Type);\n                }\n            }\n\n            BinaryExpression outerNullProtection\n                = Expression.NotEqual(\n                    leftQsre,\n                    Expression.Constant(null, leftQsre.Type));\n\n            return new NullSafeEqualExpression(outerNullProtection, Expression.Equal(leftExpression, rightExpression));\n        }\n\n        private Expression RewriteNavigationsIntoJoins(\n            QuerySourceReferenceExpression outerQuerySourceReferenceExpression,\n            IEnumerable<INavigation> navigations,\n            Type propertyType,\n            Func<Expression, Expression> propertyCreator,\n            Func<Expression, Expression> conditionalAccessPropertyCreator)\n        {\n            QuerySourceReferenceExpression sourceQsre = outerQuerySourceReferenceExpression;\n            Expression sourceExpression = outerQuerySourceReferenceExpression;\n            NavigationJoins navigationJoins = _navigationJoins;\n\n            bool optionalNavigationInChain\n                = NeedsNullCompensation(outerQuerySourceReferenceExpression);\n\n            foreach (INavigation navigation in navigations)\n            {\n                bool addNullCheckToOuterKeySelector = optionalNavigationInChain;\n\n                if (!navigation.ForeignKey.IsRequired\n                    || !navigation.IsDependentToPrincipal()\n                    || (navigation.DeclaringEntityType.ClrType != sourceExpression.Type\n                        && navigation.DeclaringEntityType.GetAllBaseTypes().Any(t => t.ClrType == sourceExpression.Type)))\n                {\n                    optionalNavigationInChain = true;\n                }\n\n                if (!ShouldRewrite(navigation))\n                {\n                    if (sourceExpression.Type != navigation.DeclaringEntityType.ClrType)\n                    {\n                        sourceExpression = Expression.Condition(\n                            Expression.TypeIs(sourceExpression, navigation.DeclaringEntityType.ClrType),\n                            Expression.Convert(sourceExpression, navigation.DeclaringEntityType.ClrType),\n                            Expression.Constant(null, navigation.DeclaringEntityType.ClrType));\n                    }\n\n                    sourceExpression = new NullConditionalExpression(sourceExpression, Expression.Property(sourceExpression, navigation.PropertyInfo));\n\n                    continue;\n                }\n\n                IEntityType targetEntityType = navigation.GetTargetType();\n\n                if (navigation.IsCollection())\n                {\n                    _queryModel.MainFromClause.FromExpression\n                        = NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(targetEntityType.ClrType);\n\n                    QuerySourceReferenceExpression innerQuerySourceReferenceExpression\n                        = new QuerySourceReferenceExpression(_queryModel.MainFromClause);\n                    _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(_queryModel.MainFromClause, targetEntityType);\n\n                    Expression leftKeyAccess = CreateKeyAccessExpression(\n                        sourceExpression,\n                        navigation.IsDependentToPrincipal()\n                            ? navigation.ForeignKey.Properties\n                            : navigation.ForeignKey.PrincipalKey.Properties);\n\n                    Expression rightKeyAccess = CreateKeyAccessExpression(\n                        innerQuerySourceReferenceExpression,\n                        navigation.IsDependentToPrincipal()\n                            ? navigation.ForeignKey.PrincipalKey.Properties\n                            : navigation.ForeignKey.Properties);\n\n                    _queryModel.BodyClauses.Add(\n                        new WhereClause(\n                            CreateKeyComparisonExpressionForCollectionNavigationSubquery(\n                                leftKeyAccess,\n                                rightKeyAccess,\n                                sourceExpression)));\n\n                    return _queryModel.MainFromClause.FromExpression;\n                }\n\n                NavigationJoin navigationJoin\n                    = navigationJoins\n                        .FirstOrDefault(nj =>\n                            nj.QuerySource == (sourceExpression as QuerySourceReferenceExpression ?? sourceQsre).ReferencedQuerySource\n                            && nj.Navigation == navigation);\n\n                if (navigationJoin == null)\n                {\n                    JoinClause joinClause = BuildJoinFromNavigation(\n                        sourceExpression,\n                        navigation,\n                        targetEntityType,\n                        addNullCheckToOuterKeySelector,\n                        out QuerySourceReferenceExpression innerQuerySourceReferenceExpression);\n\n                    if (optionalNavigationInChain)\n                    {\n                        RewriteNavigationIntoGroupJoin(\n                            joinClause,\n                            navigation,\n                            targetEntityType,\n                            sourceExpression as QuerySourceReferenceExpression ?? sourceQsre,\n                            null,\n                            new List<IBodyClause>(),\n                            new List<ResultOperatorBase>\n                            {\n                                new DefaultIfEmptyResultOperator(null)\n                            },\n                            out navigationJoin);\n                    }\n                    else\n                    {\n                        navigationJoin\n                            = new NavigationJoin(\n                                (sourceExpression as QuerySourceReferenceExpression ?? sourceQsre).ReferencedQuerySource,\n                                navigation,\n                                joinClause,\n                                new List<IBodyClause>(),\n                                navigation.IsDependentToPrincipal(),\n                                innerQuerySourceReferenceExpression);\n                    }\n                }\n\n                navigationJoins.Add(navigationJoin);\n\n                sourceExpression = navigationJoin.QuerySourceReferenceExpression;\n                sourceQsre = navigationJoin.QuerySourceReferenceExpression;\n                navigationJoins = navigationJoin.Children;\n            }\n\n            return propertyType == null\n                ? sourceExpression\n                : optionalNavigationInChain\n                ? conditionalAccessPropertyCreator(sourceExpression)\n                : propertyCreator(sourceExpression);\n        }\n\n        private void RewriteNavigationIntoGroupJoin(\n            JoinClause joinClause,\n            INavigation navigation,\n            IEntityType targetEntityType,\n            QuerySourceReferenceExpression querySourceReferenceExpression,\n            MainFromClause groupJoinSubqueryMainFromClause,\n            ICollection<IBodyClause> groupJoinSubqueryBodyClauses,\n            ICollection<ResultOperatorBase> groupJoinSubqueryResultOperators,\n            out NavigationJoin navigationJoin)\n        {\n            GroupJoinClause groupJoinClause\n                = new GroupJoinClause(\n                    joinClause.ItemName + \"_group\",\n                    typeof(IEnumerable<>).MakeGenericType(targetEntityType.ClrType),\n                    joinClause);\n\n            QuerySourceReferenceExpression groupReferenceExpression = new QuerySourceReferenceExpression(groupJoinClause);\n\n            MainFromClause groupJoinSubqueryModelMainFromClause = new MainFromClause(joinClause.ItemName + \"_groupItem\", joinClause.ItemType, groupReferenceExpression);\n            QuerySourceReferenceExpression newQuerySourceReferenceExpression = new QuerySourceReferenceExpression(groupJoinSubqueryModelMainFromClause);\n            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(groupJoinSubqueryModelMainFromClause, targetEntityType);\n\n            QueryModel groupJoinSubqueryModel = new QueryModel(\n                groupJoinSubqueryModelMainFromClause,\n                new SelectClause(newQuerySourceReferenceExpression));\n\n            foreach (IBodyClause groupJoinSubqueryBodyClause in groupJoinSubqueryBodyClauses)\n            {\n                groupJoinSubqueryModel.BodyClauses.Add(groupJoinSubqueryBodyClause);\n            }\n\n            foreach (ResultOperatorBase groupJoinSubqueryResultOperator in groupJoinSubqueryResultOperators)\n            {\n                groupJoinSubqueryModel.ResultOperators.Add(groupJoinSubqueryResultOperator);\n            }\n\n            if (groupJoinSubqueryMainFromClause != null\n                && (groupJoinSubqueryBodyClauses.Any() || groupJoinSubqueryResultOperators.Any()))\n            {\n                QuerySourceMapping querySourceMapping = new QuerySourceMapping();\n                querySourceMapping.AddMapping(groupJoinSubqueryMainFromClause, newQuerySourceReferenceExpression);\n\n                groupJoinSubqueryModel.TransformExpressions(\n                    e => ReferenceReplacingExpressionVisitor\n                        .ReplaceClauseReferences(e, querySourceMapping, throwOnUnmappedReferences: false));\n            }\n\n            SubQueryExpression defaultIfEmptySubquery = new SubQueryExpression(groupJoinSubqueryModel);\n            AdditionalFromClause defaultIfEmptyAdditionalFromClause = new AdditionalFromClause(joinClause.ItemName, joinClause.ItemType, defaultIfEmptySubquery);\n\n            navigationJoin = new NavigationJoin(\n                querySourceReferenceExpression.ReferencedQuerySource,\n                navigation,\n                groupJoinClause,\n                new[] { defaultIfEmptyAdditionalFromClause },\n                navigation.IsDependentToPrincipal(),\n                new QuerySourceReferenceExpression(defaultIfEmptyAdditionalFromClause));\n\n            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(defaultIfEmptyAdditionalFromClause, targetEntityType);\n        }\n\n        private Expression RewriteSelectManyNavigationsIntoJoins(\n            QuerySourceReferenceExpression outerQuerySourceReferenceExpression,\n            IEnumerable<INavigation> navigations,\n            AdditionalFromClause additionalFromClauseBeingProcessed)\n        {\n            Expression sourceExpression = outerQuerySourceReferenceExpression;\n            QuerySourceReferenceExpression querySourceReferenceExpression = outerQuerySourceReferenceExpression;\n            int additionalJoinIndex = _queryModel.BodyClauses.IndexOf(additionalFromClauseBeingProcessed);\n            List<JoinClause> joinClauses = new List<JoinClause>();\n\n            foreach (INavigation navigation in navigations)\n            {\n                IEntityType targetEntityType = navigation.GetTargetType();\n\n                if (!ShouldRewrite(navigation))\n                {\n                    sourceExpression = Expression.Property(sourceExpression, navigation.PropertyInfo);\n\n                    continue;\n                }\n\n                JoinClause joinClause = BuildJoinFromNavigation(\n                    sourceExpression,\n                    navigation,\n                    targetEntityType,\n                    false,\n                    out QuerySourceReferenceExpression innerQuerySourceReferenceExpression);\n\n                joinClauses.Add(joinClause);\n\n                querySourceReferenceExpression = innerQuerySourceReferenceExpression;\n                sourceExpression = innerQuerySourceReferenceExpression;\n            }\n\n            if (ShouldRewrite(navigations.Last()))\n            {\n                _queryModel.BodyClauses.RemoveAt(additionalJoinIndex);\n            }\n            else\n            {\n                ((AdditionalFromClause)_queryModel.BodyClauses[additionalJoinIndex]).FromExpression = sourceExpression;\n            }\n\n            for (int i = 0; i < joinClauses.Count; i++)\n            {\n                _queryModel.BodyClauses.Insert(additionalJoinIndex + i, joinClauses[i]);\n            }\n\n            if (ShouldRewrite(navigations.Last()))\n            {\n                QuerySourceMapping querySourceMapping = new QuerySourceMapping();\n                querySourceMapping.AddMapping(additionalFromClauseBeingProcessed, querySourceReferenceExpression);\n\n                _queryModel.TransformExpressions(\n                    e => ReferenceReplacingExpressionVisitor\n                        .ReplaceClauseReferences(e, querySourceMapping, throwOnUnmappedReferences: false));\n\n                AdjustQueryCompilationContextStateAfterSelectMany(\n                    querySourceMapping,\n                    additionalFromClauseBeingProcessed,\n                    querySourceReferenceExpression.ReferencedQuerySource);\n            }\n\n            return ShouldRewrite(navigations.Last())\n                ? querySourceReferenceExpression\n                : sourceExpression;\n        }\n\n        private Expression RewriteSelectManyInsideSubqueryIntoJoins(\n            SubQueryExpression fromSubqueryExpression,\n            QuerySourceReferenceExpression outerQuerySourceReferenceExpression,\n            ICollection<INavigation> navigations,\n            AdditionalFromClause additionalFromClauseBeingProcessed)\n        {\n            INavigation collectionNavigation = navigations.Last();\n            List<IBodyClause> adddedJoinClauses = new List<IBodyClause>();\n\n            foreach (INavigation navigation in navigations)\n            {\n                IEntityType targetEntityType = navigation.GetTargetType();\n\n                JoinClause joinClause = BuildJoinFromNavigation(\n                    outerQuerySourceReferenceExpression,\n                    navigation,\n                    targetEntityType,\n                    false,\n                    out QuerySourceReferenceExpression innerQuerySourceReferenceExpression);\n\n                if (navigation == collectionNavigation)\n                {\n                    RewriteNavigationIntoGroupJoin(\n                        joinClause,\n                        navigations.Last(),\n                        targetEntityType,\n                        outerQuerySourceReferenceExpression,\n                        fromSubqueryExpression.QueryModel.MainFromClause,\n                        fromSubqueryExpression.QueryModel.BodyClauses,\n                        fromSubqueryExpression.QueryModel.ResultOperators,\n                        out NavigationJoin navigationJoin);\n\n                    _navigationJoins.Add(navigationJoin);\n\n                    int additionalFromClauseIndex = _parentQueryModel.BodyClauses.IndexOf(additionalFromClauseBeingProcessed);\n                    _parentQueryModel.BodyClauses.Remove(additionalFromClauseBeingProcessed);\n\n                    int i = additionalFromClauseIndex;\n                    foreach (IBodyClause addedJoinClause in adddedJoinClauses)\n                    {\n                        _parentQueryModel.BodyClauses.Insert(i++, addedJoinClause);\n                    }\n\n                    QuerySourceMapping querySourceMapping = new QuerySourceMapping();\n                    querySourceMapping.AddMapping(additionalFromClauseBeingProcessed, navigationJoin.QuerySourceReferenceExpression);\n\n                    _parentQueryModel.TransformExpressions(\n                        e => ReferenceReplacingExpressionVisitor\n                            .ReplaceClauseReferences(e, querySourceMapping, throwOnUnmappedReferences: false));\n\n                    AdjustQueryCompilationContextStateAfterSelectMany(\n                        querySourceMapping,\n                        additionalFromClauseBeingProcessed,\n                        navigationJoin.QuerySourceReferenceExpression.ReferencedQuerySource);\n\n                    return navigationJoin.QuerySourceReferenceExpression;\n                }\n\n                DefaultIfEmptyResultOperator defaultIfEmptyOperator = fromSubqueryExpression.QueryModel.ResultOperators.OfType<DefaultIfEmptyResultOperator>().FirstOrDefault();\n                if (defaultIfEmptyOperator != null)\n                {\n                    RewriteNavigationIntoGroupJoin(\n                        joinClause,\n                        navigation,\n                        targetEntityType,\n                        outerQuerySourceReferenceExpression,\n                        null,\n                        new List<IBodyClause>(),\n                        new List<ResultOperatorBase>\n                        {\n                            defaultIfEmptyOperator\n                        },\n                        out NavigationJoin navigationJoin);\n\n                    _navigationJoins.Add(navigationJoin);\n                    outerQuerySourceReferenceExpression = navigationJoin.QuerySourceReferenceExpression;\n                }\n                else\n                {\n                    adddedJoinClauses.Add(joinClause);\n                    outerQuerySourceReferenceExpression = innerQuerySourceReferenceExpression;\n                }\n            }\n\n            return outerQuerySourceReferenceExpression;\n        }\n\n        private void AdjustQueryCompilationContextStateAfterSelectMany(QuerySourceMapping querySourceMapping, IQuerySource querySourceBeingProcessed, IQuerySource resultQuerySource)\n        {\n            foreach (IncludeResultOperator includeResultOperator in _queryModelVisitor.QueryCompilationContext.QueryAnnotations.OfType<IncludeResultOperator>())\n            {\n                includeResultOperator.PathFromQuerySource\n                    = ReferenceReplacingExpressionVisitor.ReplaceClauseReferences(\n                        includeResultOperator.PathFromQuerySource,\n                        querySourceMapping,\n                        throwOnUnmappedReferences: false);\n\n                if (includeResultOperator.QuerySource == querySourceBeingProcessed)\n                {\n                    includeResultOperator.QuerySource = resultQuerySource;\n                }\n            }\n        }\n\n        private JoinClause BuildJoinFromNavigation(\n            Expression sourceExpression,\n            INavigation navigation,\n            IEntityType targetEntityType,\n            bool addNullCheckToOuterKeySelector,\n            out QuerySourceReferenceExpression innerQuerySourceReferenceExpression)\n        {\n            Expression outerKeySelector =\n                CreateKeyAccessExpression(\n                    sourceExpression,\n                    navigation.IsDependentToPrincipal()\n                        ? navigation.ForeignKey.Properties\n                        : navigation.ForeignKey.PrincipalKey.Properties,\n                    addNullCheckToOuterKeySelector);\n\n            string itemName = sourceExpression is QuerySourceReferenceExpression qsre && !qsre.ReferencedQuerySource.HasGeneratedItemName()\n                ? qsre.ReferencedQuerySource.ItemName\n                : navigation.DeclaringEntityType.ShortName()[0].ToString().ToLowerInvariant();\n\n            JoinClause joinClause\n                = new JoinClause(\n                    $\"{itemName}.{navigation.Name}\",\n                    targetEntityType.ClrType,\n                    NullAsyncQueryProvider.Instance.CreateEntityQueryableExpression(targetEntityType.ClrType),\n                    outerKeySelector,\n                    Expression.Constant(null));\n\n            innerQuerySourceReferenceExpression = new QuerySourceReferenceExpression(joinClause);\n            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(joinClause, targetEntityType);\n\n            Expression innerKeySelector\n                = CreateKeyAccessExpression(\n                    innerQuerySourceReferenceExpression,\n                    navigation.IsDependentToPrincipal()\n                        ? navigation.ForeignKey.PrincipalKey.Properties\n                        : navigation.ForeignKey.Properties);\n\n            if (innerKeySelector.Type != joinClause.OuterKeySelector.Type)\n            {\n                if (innerKeySelector.Type.IsNullableType())\n                {\n                    joinClause.OuterKeySelector\n                        = Expression.Convert(\n                            joinClause.OuterKeySelector,\n                            innerKeySelector.Type);\n                }\n                else\n                {\n                    innerKeySelector\n                        = Expression.Convert(\n                            innerKeySelector,\n                            joinClause.OuterKeySelector.Type);\n                }\n            }\n\n            joinClause.InnerKeySelector = innerKeySelector;\n\n            return joinClause;\n        }\n\n        private static Expression CreateKeyAccessExpression(\n            Expression target, IReadOnlyList<IProperty> properties, bool addNullCheck = false)\n            => properties.Count == 1\n                ? CreatePropertyExpression(target, properties[0], addNullCheck)\n                : Expression.New(\n                    AnonymousObject.AnonymousObjectCtor,\n                    Expression.NewArrayInit(\n                        typeof(object),\n                        properties\n                            .Select(p => Expression.Convert(CreatePropertyExpression(target, p, addNullCheck), typeof(object)))\n                            .Cast<Expression>()\n                            .ToArray()));\n\n        private static Expression CreatePropertyExpression(Expression target, IProperty property, bool addNullCheck)\n        {\n            Expression propertyExpression = target.CreateEFPropertyExpression(property, makeNullable: false);\n\n            Type propertyDeclaringType = property.DeclaringType.ClrType;\n            if (propertyDeclaringType != target.Type\n                && target.Type.GetTypeInfo().IsAssignableFrom(propertyDeclaringType.GetTypeInfo()))\n            {\n                if (!propertyExpression.Type.IsNullableType())\n                {\n                    propertyExpression = Expression.Convert(propertyExpression, propertyExpression.Type.MakeNullable());\n                }\n\n                return Expression.Condition(\n                    Expression.TypeIs(target, propertyDeclaringType),\n                    propertyExpression,\n                    Expression.Constant(null, propertyExpression.Type));\n            }\n\n            return addNullCheck\n                ? new NullConditionalExpression(target, propertyExpression)\n                : propertyExpression;\n        }\n\n        private static bool IsCompositeKey([NotNull] Type type)\n        {\n            Check.NotNull(type, nameof(type));\n\n            return type == typeof(AnonymousObject);\n        }\n\n        private static Expression CompensateForNullabilityDifference(Expression expression, Type originalType)\n        {\n            Type newType = expression.Type;\n\n            bool needsTypeCompensation\n                = originalType != newType\n                  && !originalType.IsNullableType()\n                  && newType.IsNullableType()\n                  && originalType == newType.UnwrapNullableType();\n\n            return needsTypeCompensation\n                ? Expression.Convert(expression, originalType)\n                : expression;\n        }\n\n        private class DocumentNavigationRewritingQueryModelVisitor : ExpressionTransformingQueryModelVisitor<DocumentNavigationRewritingExpressionVisitor>\n        {\n            private readonly CollectionNavigationSubqueryInjector _subqueryInjector;\n            private readonly bool _navigationExpansionSubquery;\n            private readonly QueryCompilationContext _queryCompilationContext;\n\n            public AdditionalFromClause AdditionalFromClauseBeingProcessed { get; private set; }\n\n            public DocumentNavigationRewritingQueryModelVisitor(\n                DocumentNavigationRewritingExpressionVisitor transformingVisitor,\n                EntityQueryModelVisitor queryModelVisitor,\n                bool navigationExpansionSubquery)\n                : base(transformingVisitor)\n            {\n                _subqueryInjector = new CollectionNavigationSubqueryInjector(queryModelVisitor, shouldInject: true);\n                _navigationExpansionSubquery = navigationExpansionSubquery;\n                _queryCompilationContext = queryModelVisitor.QueryCompilationContext;\n            }\n\n            public override void VisitMainFromClause(MainFromClause fromClause, QueryModel queryModel)\n            {\n                base.VisitMainFromClause(fromClause, queryModel);\n\n                QueryCompilationContext queryCompilationContext = TransformingVisitor._queryModelVisitor.QueryCompilationContext;\n                if (queryCompilationContext.FindEntityType(fromClause) == null\n                    && fromClause.FromExpression is SubQueryExpression subQuery)\n                {\n                    IEntityType entityType = MemberAccessBindingExpressionVisitor.GetEntityType(\n                        subQuery.QueryModel.SelectClause.Selector, queryCompilationContext);\n\n                    if (entityType != null)\n                    {\n                        queryCompilationContext.AddOrUpdateMapping(fromClause, entityType);\n                    }\n                }\n            }\n\n            public override void VisitAdditionalFromClause(AdditionalFromClause fromClause, QueryModel queryModel, int index)\n            {\n                // ReSharper disable once PatternAlwaysOfType\n                if (fromClause.TryGetFlattenedGroupJoinClause()?.JoinClause is JoinClause joinClause\n                    // ReSharper disable once PatternAlwaysOfType\n                    && _queryCompilationContext.FindEntityType(joinClause) is IEntityType entityType)\n                {\n                    _queryCompilationContext.AddOrUpdateMapping(fromClause, entityType);\n                }\n\n                AdditionalFromClause oldAdditionalFromClause = AdditionalFromClauseBeingProcessed;\n                AdditionalFromClauseBeingProcessed = fromClause;\n                fromClause.TransformExpressions(TransformingVisitor.Visit);\n                AdditionalFromClauseBeingProcessed = oldAdditionalFromClause;\n            }\n\n            public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index)\n            {\n                base.VisitWhereClause(whereClause, queryModel, index);\n\n                if (whereClause.Predicate.Type == typeof(bool?))\n                {\n                    whereClause.Predicate = Expression.Equal(whereClause.Predicate, Expression.Constant(true, typeof(bool?)));\n                }\n            }\n\n            public override void VisitOrderByClause(OrderByClause orderByClause, QueryModel queryModel, int index)\n            {\n                List<Type> originalTypes = orderByClause.Orderings.Select(o => o.Expression.Type).ToList();\n\n                bool oldInsideOrderBy = TransformingVisitor._insideOrderBy;\n                TransformingVisitor._insideOrderBy = true;\n\n                base.VisitOrderByClause(orderByClause, queryModel, index);\n\n                TransformingVisitor._insideOrderBy = oldInsideOrderBy;\n\n                for (int i = 0; i < orderByClause.Orderings.Count; i++)\n                {\n                    orderByClause.Orderings[i].Expression = CompensateForNullabilityDifference(\n                        orderByClause.Orderings[i].Expression,\n                        originalTypes[i]);\n                }\n            }\n\n            public override void VisitJoinClause(JoinClause joinClause, QueryModel queryModel, int index)\n                => VisitJoinClauseInternal(joinClause);\n\n            public override void VisitJoinClause(JoinClause joinClause, QueryModel queryModel, GroupJoinClause groupJoinClause)\n                => VisitJoinClauseInternal(joinClause);\n\n            private void VisitJoinClauseInternal(JoinClause joinClause)\n            {\n                joinClause.InnerSequence = TransformingVisitor.Visit(joinClause.InnerSequence);\n\n                QueryCompilationContext queryCompilationContext = TransformingVisitor._queryModelVisitor.QueryCompilationContext;\n                if (queryCompilationContext.FindEntityType(joinClause) == null\n                    && joinClause.InnerSequence is SubQueryExpression subQuery)\n                {\n                    IEntityType entityType = MemberAccessBindingExpressionVisitor.GetEntityType(\n                        subQuery.QueryModel.SelectClause.Selector, queryCompilationContext);\n                    if (entityType != null)\n                    {\n                        queryCompilationContext.AddOrUpdateMapping(joinClause, entityType);\n                    }\n                }\n\n                joinClause.OuterKeySelector = TransformingVisitor.Visit(joinClause.OuterKeySelector);\n\n                bool oldInsideInnerKeySelector = TransformingVisitor._insideInnerKeySelector;\n                TransformingVisitor._insideInnerKeySelector = true;\n                joinClause.InnerKeySelector = TransformingVisitor.Visit(joinClause.InnerKeySelector);\n\n                if (joinClause.OuterKeySelector.Type.IsNullableType()\n                    && !joinClause.InnerKeySelector.Type.IsNullableType())\n                {\n                    joinClause.InnerKeySelector = Expression.Convert(joinClause.InnerKeySelector, joinClause.InnerKeySelector.Type.MakeNullable());\n                }\n\n                if (joinClause.InnerKeySelector.Type.IsNullableType()\n                    && !joinClause.OuterKeySelector.Type.IsNullableType())\n                {\n                    joinClause.OuterKeySelector = Expression.Convert(joinClause.OuterKeySelector, joinClause.OuterKeySelector.Type.MakeNullable());\n                }\n\n                TransformingVisitor._insideInnerKeySelector = oldInsideInnerKeySelector;\n            }\n\n            public override void VisitSelectClause(SelectClause selectClause, QueryModel queryModel)\n            {\n                selectClause.Selector = _subqueryInjector.Visit(selectClause.Selector);\n\n                if (_navigationExpansionSubquery)\n                {\n                    base.VisitSelectClause(selectClause, queryModel);\n                    return;\n                }\n\n                Type originalType = selectClause.Selector.Type;\n\n                base.VisitSelectClause(selectClause, queryModel);\n\n                selectClause.Selector = CompensateForNullabilityDifference(selectClause.Selector, originalType);\n            }\n\n            public override void VisitResultOperator(ResultOperatorBase resultOperator, QueryModel queryModel, int index)\n            {\n                if (resultOperator is AllResultOperator allResultOperator)\n                {\n                    Expression expressionExtractor(AllResultOperator o) => o.Predicate;\n                    void adjuster(AllResultOperator o, Expression e) => o.Predicate = e;\n                    VisitAndAdjustResultOperatorType(allResultOperator, expressionExtractor, adjuster);\n\n                    return;\n                }\n\n                if (resultOperator is ContainsResultOperator containsResultOperator)\n                {\n                    Expression expressionExtractor(ContainsResultOperator o) => o.Item;\n                    void adjuster(ContainsResultOperator o, Expression e) => o.Item = e;\n                    VisitAndAdjustResultOperatorType(containsResultOperator, expressionExtractor, adjuster);\n\n                    return;\n                }\n\n                if (resultOperator is SkipResultOperator skipResultOperator)\n                {\n                    Expression expressionExtractor(SkipResultOperator o) => o.Count;\n                    void adjuster(SkipResultOperator o, Expression e) => o.Count = e;\n                    VisitAndAdjustResultOperatorType(skipResultOperator, expressionExtractor, adjuster);\n\n                    return;\n                }\n\n                if (resultOperator is TakeResultOperator takeResultOperator)\n                {\n                    Expression expressionExtractor(TakeResultOperator o) => o.Count;\n                    void adjuster(TakeResultOperator o, Expression e) => o.Count = e;\n                    VisitAndAdjustResultOperatorType(takeResultOperator, expressionExtractor, adjuster);\n\n                    return;\n                }\n\n                if (resultOperator is GroupResultOperator groupResultOperator)\n                {\n                    groupResultOperator.ElementSelector\n                        = _subqueryInjector.Visit(groupResultOperator.ElementSelector);\n\n                    Type originalKeySelectorType = groupResultOperator.KeySelector.Type;\n                    Type originalElementSelectorType = groupResultOperator.ElementSelector.Type;\n\n                    base.VisitResultOperator(resultOperator, queryModel, index);\n\n                    groupResultOperator.KeySelector = CompensateForNullabilityDifference(\n                        groupResultOperator.KeySelector,\n                        originalKeySelectorType);\n\n                    groupResultOperator.ElementSelector = CompensateForNullabilityDifference(\n                        groupResultOperator.ElementSelector,\n                        originalElementSelectorType);\n\n                    return;\n                }\n\n                base.VisitResultOperator(resultOperator, queryModel, index);\n            }\n\n            private void VisitAndAdjustResultOperatorType<TResultOperator>(\n                TResultOperator resultOperator,\n                Func<TResultOperator, Expression> expressionExtractor,\n                Action<TResultOperator, Expression> adjuster)\n                where TResultOperator : ResultOperatorBase\n            {\n                Expression originalExpression = expressionExtractor(resultOperator);\n                Type originalType = originalExpression.Type;\n\n                Expression translatedExpression = CompensateForNullabilityDifference(\n                    TransformingVisitor.Visit(originalExpression),\n                    originalType);\n\n                adjuster(resultOperator, translatedExpression);\n            }\n        }\n\n        private class ProjectionSubqueryInjectingQueryModelVisitor : QueryModelVisitorBase\n        {\n            private readonly CollectionNavigationSubqueryInjector _subqueryInjector;\n\n            public ProjectionSubqueryInjectingQueryModelVisitor(EntityQueryModelVisitor queryModelVisitor)\n            {\n                _subqueryInjector = new CollectionNavigationSubqueryInjector(queryModelVisitor, shouldInject: true);\n            }\n\n            public override void VisitSelectClause(SelectClause selectClause, QueryModel queryModel)\n            {\n                selectClause.Selector = _subqueryInjector.Visit(selectClause.Selector);\n\n                base.VisitSelectClause(selectClause, queryModel);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/DocumentNavigationRewritingExpressionVisitorFactory.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class DocumentNavigationRewritingExpressionVisitorFactory : NavigationRewritingExpressionVisitorFactory\n    {\n        /// <inheritdoc />\n        public override NavigationRewritingExpressionVisitor Create(EntityQueryModelVisitor queryModelVisitor)\n            => new DocumentNavigationRewritingExpressionVisitor(queryModelVisitor);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/IMongoDbDenormalizedCollectionCompensatingVisitorFactory.cs",
    "content": "﻿namespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public interface IMongoDbDenormalizedCollectionCompensatingVisitorFactory\n    {\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        MongoDbDenormalizedCollectionCompensatingVisitor Create();\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbDenormalizedCollectionCompensatingVisitor.cs",
    "content": "﻿using System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Remotion.Linq.Parsing;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbDenormalizedCollectionCompensatingVisitor : RelinqExpressionVisitor\n    {\n        /// <inheritdoc />\n        protected override Expression VisitBlock(BlockExpression node)\n        {\n            if (TryFindAddToCollectionExpression(node.Expressions, out MethodCallExpression methodCallExpression))\n            {\n                Expression callReplaceDenormalizedInstances = Expression.Call(\n                    null,\n                    RemoveDenormalizedInstancesMethodInfo,\n                    methodCallExpression.Arguments);\n                IList<Expression> newBlockExpressions = new List<Expression>(node.Expressions);\n                newBlockExpressions.Add(callReplaceDenormalizedInstances);\n                node = node.Update(node.Variables, newBlockExpressions);\n            }\n            return base.VisitBlock(node);\n        }\n\n        private bool TryFindAddToCollectionExpression(IReadOnlyList<Expression> expressions, out MethodCallExpression methodCallExpression)\n        {\n            methodCallExpression = null;\n\n            foreach (Expression expression in expressions)\n            {\n                if (expression is MethodCallExpression candidateMethodCallExpression\n                    && candidateMethodCallExpression.Method == AddToCollectionSnapshotMethodInfo)\n                {\n                    methodCallExpression = candidateMethodCallExpression;\n                    break;\n                }\n            }\n\n            return methodCallExpression != null;\n        }\n\n        private static void RemoveDenormalizedInstances(\n            IStateManager stateManager,\n            INavigation navigation,\n            object entity,\n            object instance)\n        {\n            InternalEntityEntry internalEntityEntry = stateManager.TryGetEntry(entity);\n            internalEntityEntry.EnsureRelationshipSnapshot();\n\n            INavigation inverse = navigation.FindInverse();\n            IKey primaryKey = inverse.DeclaringEntityType.FindPrimaryKey();\n            IProperty primaryKeyProperty = primaryKey.Properties.Single();\n            object keyValue = primaryKeyProperty.GetGetter().GetClrValue(instance);\n\n            IClrCollectionAccessor collectionAccessor = navigation.GetCollectionAccessor();\n            ICollection list = (ICollection) collectionAccessor.GetOrCreate(entity);\n\n            IList<object> toRemove = list\n                .OfType<object>()\n                .Where(item => (Equals(\n                                    keyValue,\n                                    primaryKeyProperty.GetGetter().GetClrValue(item))\n                                && !ReferenceEquals(instance, item)))\n                .ToList();\n\n            foreach (object item in toRemove)\n            {\n                collectionAccessor.Remove(entity, item);\n                internalEntityEntry.RemoveFromCollectionSnapshot(navigation, item);\n            }\n        }\n\n        private static readonly MethodInfo RemoveDenormalizedInstancesMethodInfo\n            = MethodHelper\n                .GetMethodInfo(() => RemoveDenormalizedInstances(default, default, default, default));\n\n        private static readonly MethodInfo AddToCollectionSnapshotMethodInfo\n            = (MethodInfo) typeof(IncludeCompiler)\n                .GetNestedType(\"IncludeLoadTreeNode\", BindingFlags.NonPublic)\n                ?.GetField(\"_addToCollectionSnapshotMethodInfo\", BindingFlags.NonPublic | BindingFlags.Static)\n                ?.GetValue(null);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbDenormalizedCollectionCompensatingVisitorFactory.cs",
    "content": "﻿namespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class MongoDbDenormalizedCollectionCompensatingVisitorFactory : IMongoDbDenormalizedCollectionCompensatingVisitorFactory\n    {\n        /// <inheritdoc />\n        public MongoDbDenormalizedCollectionCompensatingVisitor Create()\n            => new MongoDbDenormalizedCollectionCompensatingVisitor();\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbEntityQueryableExpressionVisitor.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Remotion.Linq.Clauses;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class MongoDbEntityQueryableExpressionVisitor : EntityQueryableExpressionVisitor\n    {\n        private readonly IModel _model;\n        private readonly IQuerySource _querySource;\n        private readonly IDocumentQueryExpressionFactory _documentQueryExpressionFactory;\n\n        /// <inheritdoc />\n        public MongoDbEntityQueryableExpressionVisitor(\n            // ReSharper disable once SuggestBaseTypeForParameter\n            [NotNull] MongoDbEntityQueryModelVisitor entityQueryModelVisitor,\n            [NotNull] IModel model,\n            [CanBeNull] IQuerySource querySource,\n            [NotNull] IDocumentQueryExpressionFactory documentQueryExpressionFactory)\n            : base(entityQueryModelVisitor)\n        {\n            _model = Check.NotNull(model, nameof(model));\n            _querySource = querySource;\n            _documentQueryExpressionFactory = Check.NotNull(documentQueryExpressionFactory, nameof(documentQueryExpressionFactory));\n        }\n\n        private new MongoDbEntityQueryModelVisitor QueryModelVisitor => (MongoDbEntityQueryModelVisitor)base.QueryModelVisitor;\n\n        /// <inheritdoc />\n        protected override Expression VisitEntityQueryable(Type elementType)\n        {\n            Check.NotNull(elementType, nameof(elementType));\n\n            IEntityType entityType = QueryModelVisitor.QueryCompilationContext.FindEntityType(_querySource)\n                                     ?? _model.FindEntityType(elementType);\n\n            entityType = entityType.GetMongoDbCollectionEntityType();\n\n            var documentQueryExpression = _documentQueryExpressionFactory\n                .CreateDocumentQueryExpression(entityType);\n\n            if (entityType.ClrType != elementType)\n            {\n                MethodInfo ofTypeMethodInfo = MethodHelper\n                    .GetGenericMethodDefinition<object>(() => Enumerable.OfType<object>(null))\n                    .MakeGenericMethod(elementType);\n\n                documentQueryExpression = Expression.Call(\n                    null,\n                    ofTypeMethodInfo,\n                    documentQueryExpression);\n            }\n\n            return documentQueryExpression;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbEntityQueryableExpressionVisitorFactory.cs",
    "content": "﻿using System.Linq.Expressions;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Remotion.Linq.Clauses;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <summary>\n    ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n    ///     directly from your code. This API may change or be removed in future releases.\n    /// </summary>\n    public class MongoDbEntityQueryableExpressionVisitorFactory : IEntityQueryableExpressionVisitorFactory\n    {\n        private readonly IModel _model;\n        private readonly IDocumentQueryExpressionFactory _documentQueryExpressionFactory;\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public MongoDbEntityQueryableExpressionVisitorFactory(\n            [NotNull] IModel model,\n            [NotNull] IDocumentQueryExpressionFactory documentQueryExpressionFactory)\n        {\n            _model = Check.NotNull(model, nameof(model));\n            _documentQueryExpressionFactory = Check.NotNull(documentQueryExpressionFactory, nameof(documentQueryExpressionFactory));\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        public virtual ExpressionVisitor Create(\n            EntityQueryModelVisitor entityQueryModelVisitor,\n            IQuerySource querySource)\n            => new MongoDbEntityQueryableExpressionVisitor(\n                Check.Is<MongoDbEntityQueryModelVisitor>(entityQueryModelVisitor, nameof(entityQueryModelVisitor)),\n                _model,\n                querySource,\n                _documentQueryExpressionFactory);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbMemberAccessBindingExpressionVisitor.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Extensions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Remotion.Linq.Clauses;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class MongoDbMemberAccessBindingExpressionVisitor : MemberAccessBindingExpressionVisitor\n    {\n        private readonly IModel _model;\n\n        /// <inheritdoc />\n        public MongoDbMemberAccessBindingExpressionVisitor(\n            [NotNull] QuerySourceMapping querySourceMapping,\n            [NotNull] MongoDbEntityQueryModelVisitor mongoDbEntityQueryModelVisitor,\n            bool inProjection)\n            : base(\n                Check.NotNull(querySourceMapping, nameof(querySourceMapping)),\n                Check.NotNull(mongoDbEntityQueryModelVisitor, nameof(mongoDbEntityQueryModelVisitor)),\n                inProjection)\n        {\n            _model = mongoDbEntityQueryModelVisitor.QueryCompilationContext.Model;\n        }\n\n        /// <summary>\n        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///     directly from your code. This API may change or be removed in future releases.\n        /// </summary>\n        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)\n        {\n            Expression newExpression = null;\n\n            if (methodCallExpression.Method.IsEFPropertyMethod())\n            {\n                var newArguments\n                    = VisitAndConvert(\n                        new List<Expression>\n                        {\n                            methodCallExpression.Arguments[0],\n                            methodCallExpression.Arguments[1]\n                        }.AsReadOnly(),\n                        nameof(VisitMethodCall));\n\n                Expression targetExpression = newArguments[0];\n\n                IEntityType entityType = _model\n                    .FindEntityType(targetExpression.Type);\n                IProperty property = entityType\n                    .FindProperty((string)((ConstantExpression)newArguments[1]).Value);\n                PropertyInfo propertyInfo = property.PropertyInfo;\n\n                if (property.IsShadowProperty && property.IsForeignKey())\n                {\n                    IForeignKey foreignKey = property.AsProperty().ForeignKeys.Single();\n                    INavigation navigation = foreignKey.PrincipalEntityType == entityType\n                                             || foreignKey.IsSelfPrimaryKeyReferencing()\n                        ? foreignKey.PrincipalToDependent\n                        : foreignKey.DependentToPrincipal;\n\n                    if (navigation != null)\n                    {\n                        targetExpression = Expression.MakeMemberAccess(targetExpression, navigation.PropertyInfo);\n\n                        IEntityType targetEntityType = navigation.GetTargetType();\n                        property = targetEntityType.FindPrimaryKey().Properties.Single();\n                        propertyInfo = property.PropertyInfo;\n                    }\n                }\n\n                newExpression = Expression.Convert(\n                    Expression.MakeMemberAccess(targetExpression, propertyInfo),\n                    typeof(Nullable<>).MakeGenericType(propertyInfo.PropertyType));\n            }\n\n            return newExpression ?? base.VisitMethodCall(methodCallExpression);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ExpressionVisitors/MongoDbMemberAccessBindingExpressionVisitorFactory.cs",
    "content": "﻿using System;\nusing System.Linq.Expressions;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal;\nusing Remotion.Linq.Clauses;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors\n{\n    /// <inheritdoc />\n    public class MongoDbMemberAccessBindingExpressionVisitorFactory : MemberAccessBindingExpressionVisitorFactory\n    {\n        /// <inheritdoc />\n        public override ExpressionVisitor Create(\n            QuerySourceMapping querySourceMapping,\n            EntityQueryModelVisitor queryModelVisitor,\n            bool inProjection)\n            => new MongoDbMemberAccessBindingExpressionVisitor(\n                querySourceMapping,\n                queryModelVisitor is MongoDbEntityQueryModelVisitor mongoDbEntityQueryModelVisitor\n                    ? mongoDbEntityQueryModelVisitor\n                    : throw new ArgumentException(\n                        @\"EntityQueryModelVisitor must be an instance of MongoDbEntityQueryModelVisitor.\",\n                        nameof(queryModelVisitor)),\n                inProjection);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/Expressions/DocumentQueryExpression.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Represents a query for a set of documents from a document database.\n    /// </summary>\n    public class DocumentQueryExpression : Expression\n    {\n        private readonly IDocumentQueryExpressionFactory _documentQueryExpressionFactory;\n        private readonly IEntityType _entityType;\n\n        /// <inheritdoc />\n        /// <summary>\n        ///   Creates a new instance of the <see cref=\"DocumentQueryExpression\"/> class.\n        /// </summary>\n        /// <param name=\"documentQueryExpressionFactory\">The <see cref=\"IDocumentQueryExpressionFactory\"/> to use to create\n        /// the root document query expression.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> representing the type of entities to query.</param>\n        public DocumentQueryExpression(\n            [NotNull] IDocumentQueryExpressionFactory documentQueryExpressionFactory,\n            [NotNull] IEntityType entityType)\n        {\n            _documentQueryExpressionFactory = Check.NotNull(documentQueryExpressionFactory, nameof(documentQueryExpressionFactory));\n            _entityType = Check.NotNull(entityType, nameof(entityType));\n        }\n\n        /// <inheritdoc />\n        public override bool CanReduce => true;\n\n        /// <inheritdoc />\n        public override Expression Reduce()\n            => _documentQueryExpressionFactory\n                .CreateDocumentQueryExpression(_entityType);\n\n        /// <inheritdoc />\n        public override Type Type\n            => typeof(IQueryable<>).MakeGenericType(_entityType.ClrType);\n\n        /// <inheritdoc />\n        protected override Expression VisitChildren(ExpressionVisitor visitor) => this;\n\n        /// <inheritdoc />\n        public override ExpressionType NodeType => ExpressionType.Extension;\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/Expressions/IDocumentQueryExpressionFactory.cs",
    "content": "﻿using System.Linq.Expressions;\nusing Microsoft.EntityFrameworkCore.Metadata;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions\n{\n    /// <summary>\n    /// Interface for a service that can be used to generate a document query expression.\n    /// </summary>\n    public interface IDocumentQueryExpressionFactory\n    {\n        /// <summary>\n        /// Creates an <see cref=\"Expression\"/> that represents a query for documents of a given entity type.\n        /// </summary>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> that represents that documents to query.</param>\n        /// <returns>An <see cref=\"Expression\"/> that represents a query for documents of a given entity type.</returns>\n        Expression CreateDocumentQueryExpression(IEntityType entityType);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/Expressions/MongoDbDocumentQueryExpressionFactory.cs",
    "content": "﻿using System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query.Expressions\n{\n    /// <inheritdoc />\n    public class MongoDbDocumentQueryExpressionFactory : IDocumentQueryExpressionFactory\n    {\n        private static readonly MethodInfo GetCollectionMethodInfo\n            = MethodHelper.GetGenericMethodDefinition<IMongoDatabase, object>(\n                mongoDatabase => mongoDatabase.GetCollection<object>(\"\", null));\n\n        private static readonly MethodInfo AsQueryableMethodInfo\n            = MethodHelper.GetGenericMethodDefinition<IMongoCollection<object>, object>(\n                mongoCollection => mongoCollection.AsQueryable(null));\n\n        private static readonly MethodInfo OfTypeMethodInfo\n            = MethodHelper.GetGenericMethodDefinition<IQueryable<object>, object>(\n                queryable => queryable.OfType<object>());\n\n        private readonly IMongoDbConnection _mongoDbConnection;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbDocumentQueryExpressionFactory\"/> class.\n        /// </summary>\n        /// <param name=\"mongoDbConnection\">The <see cref=\"IMongoDbConnection\"/> used to connect to the instance of MongoDb.</param>\n        public MongoDbDocumentQueryExpressionFactory(\n            [NotNull] IMongoDbConnection mongoDbConnection)\n        {\n            _mongoDbConnection = Check.NotNull(mongoDbConnection, nameof(mongoDbConnection));\n        }\n\n        /// <inheritdoc />\n        public Expression CreateDocumentQueryExpression(IEntityType entityType)\n        {\n            MongoDbEntityTypeAnnotations annotations = Check.NotNull(entityType, nameof(entityType)).MongoDb();\n\n            IEntityType queryEntityType = entityType;\n\n            if (!entityType.IsDocumentRootEntityType())\n            {\n                entityType = entityType.GetMongoDbCollectionEntityType();\n            }\n\n            Expression queryExpression = Expression.Call(\n                Expression.Constant(_mongoDbConnection.GetDatabase()),\n                GetCollectionMethodInfo.MakeGenericMethod(entityType.ClrType),\n                new Expression[]\n                {\n                    Expression.Constant(annotations.CollectionName),\n                    Expression.Constant(\n                        annotations.CollectionSettings,\n                        typeof(MongoCollectionSettings))\n                });\n\n            queryExpression = Expression.Call(\n                null,\n                AsQueryableMethodInfo.MakeGenericMethod(entityType.ClrType),\n                new []\n                {\n                    queryExpression,\n                    Expression.Constant(\n                        null,\n                        typeof(AggregateOptions))\n                });\n\n            if (queryEntityType != entityType)\n            {\n                queryExpression = Expression.Call(\n                    queryExpression,\n                    OfTypeMethodInfo.MakeGenericMethod(queryEntityType.ClrType));\n            }\n\n            return queryExpression;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/IEntityLoadInfoFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Query;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <summary>\n    /// Interface for a service that can create instances of <see cref=\"EntityLoadInfo\"/>.\n    /// </summary>\n    public interface IEntityLoadInfoFactory\n    {\n        /// <summary>\n        /// Creates a new instance of <see cref=\"EntityLoadInfo\"/> for the given <paramref name=\"document\"/> instance.\n        /// </summary>\n        /// <param name=\"document\">The object for which the <see cref=\"EntityLoadInfo\"/> will be created.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> representing the type of <paramref name=\"document\"/>.</param>\n        /// <param name=\"owner\">The entity instance that owns <paramref name=\"document\"/>, if any.</param>\n        /// <param name=\"owningNavigation\">The <see cref=\"INavigation\"/> that describes the ownership, if any.</param>\n        /// <returns>A new instance of <see cref=\"EntityLoadInfo\"/> that can be used to load the given <paramref name=\"document\"/>.</returns>\n        EntityLoadInfo Create(\n            [NotNull] object document,\n            [NotNull] IEntityType entityType,\n            [CanBeNull] object owner,\n            [CanBeNull] INavigation owningNavigation);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/IValueBufferFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Storage;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <summary>\n    /// Interface for a service that can create <see cref=\"ValueBuffer\"/> instances.\n    /// </summary>\n    public interface IValueBufferFactory\n    {\n        /// <summary>\n        /// Creates an instance of <see cref=\"ValueBuffer\"/> from the given <paramref name=\"instance\"/>.\n        /// </summary>\n        /// <param name=\"instance\">An existing object instance to use to build the value buffer.</param>\n        /// <param name=\"entityType\">The <see cref=\"IEntityType\"/> containing the metadata for <paramref name=\"instance\"/>.</param>\n        /// <param name=\"owner\">The entity that owns <paramref name=\"instance\"/>, if any.</param>\n        /// <param name=\"owningNavigation\">The <see cref=\"INavigation\"/> that describes the ownership, if any.</param>\n        /// <returns>A new <see cref=\"ValueBuffer\"/> that reflects the properties of the given <paramref name=\"instance\"/>.</returns>\n        ValueBuffer CreateFromInstance(\n            [NotNull] object instance,\n            [NotNull] IEntityType entityType,\n            [CanBeNull] object owner,\n            [CanBeNull] INavigation owningNavigation);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/LinqQueryCompilationContextFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class LinqQueryCompilationContextFactory : QueryCompilationContextFactory\n    {\n        /// <inheritdoc />\n        public LinqQueryCompilationContextFactory(\n            [NotNull] QueryCompilationContextDependencies dependencies) : base(dependencies)\n        {\n        }\n\n        /// <inheritdoc />\n        public override QueryCompilationContext Create(bool async)\n            => new QueryCompilationContext(\n                Dependencies,\n                new QueryableLinqOperatorProvider(),\n                TrackQueryResults);\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbEntityQueryModelVisitor.cs",
    "content": "using System;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Remotion.Linq;\nusing Remotion.Linq.Clauses;\nusing Remotion.Linq.Clauses.Expressions;\nusing Remotion.Linq.Clauses.ResultOperators;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class MongoDbEntityQueryModelVisitor : EntityQueryModelVisitor\n    {\n        private readonly IProjectionExpressionVisitorFactory _projectionExpressionVisitorFactory;\n        private readonly IMongoDbDenormalizedCollectionCompensatingVisitorFactory\n            _mongoDbDenormalizedCollectionCompensatingVisitorFactory;\n\n        /// <inheritdoc />\n        public MongoDbEntityQueryModelVisitor(\n            [NotNull] EntityQueryModelVisitorDependencies entityQueryModelVisitorDependencies,\n            [NotNull] QueryCompilationContext queryCompilationContext,\n            [NotNull] MongoDbEntityQueryModelVisitorDependencies mongoDbEntityQueryModelVisitorDependencies)\n            : base(\n                Check.NotNull(entityQueryModelVisitorDependencies, nameof(entityQueryModelVisitorDependencies)),\n                Check.NotNull(queryCompilationContext, nameof(queryCompilationContext))\n            )\n        {\n            _projectionExpressionVisitorFactory = entityQueryModelVisitorDependencies\n                .ProjectionExpressionVisitorFactory;\n            _mongoDbDenormalizedCollectionCompensatingVisitorFactory\n                = Check.NotNull(mongoDbEntityQueryModelVisitorDependencies, nameof(mongoDbEntityQueryModelVisitorDependencies))\n                    .MongoDbDenormalizedCollectionCompensatingVisitorFactory;\n        }\n\n        /// <inheritdoc />\n        public override void VisitSelectClause(\n            SelectClause selectClause,\n            QueryModel queryModel)\n        {\n            Check.NotNull(selectClause, nameof(selectClause));\n            Check.NotNull(queryModel, nameof(queryModel));\n\n            if (selectClause.Selector.Type == Expression.Type.GetSequenceType()\n                && selectClause.Selector is QuerySourceReferenceExpression)\n            {\n                return;\n            }\n\n            Expression selector = ReplaceClauseReferences(\n                _projectionExpressionVisitorFactory\n                    .Create(this, queryModel.MainFromClause)\n                    .Visit(selectClause.Selector),\n                inProjection: true);\n\n            if ((Expression.Type.TryGetSequenceType() != null || !(selectClause.Selector is QuerySourceReferenceExpression))\n                && !queryModel.ResultOperators\n                    .Select(ro => ro.GetType())\n                    .Any(\n                        t => t == typeof(GroupResultOperator)\n                             || t == typeof(AllResultOperator)))\n            {\n                Expression = Expression.Call(\n                    LinqOperatorProvider.Select\n                        .MakeGenericMethod(CurrentParameter.Type, selector.Type),\n                    Expression,\n                    Expression.Lambda(ConvertToRelationshipAssignments(selector), CurrentParameter));\n            }\n        }\n\n        private Expression ConvertToRelationshipAssignments(Expression expression)\n        {\n            if (expression is MethodCallExpression methodCallExpression\n                && IncludeCompiler.IsIncludeMethod(methodCallExpression))\n            {\n                expression = (MethodCallExpression) _mongoDbDenormalizedCollectionCompensatingVisitorFactory\n                    .Create()\n                    .Visit(methodCallExpression);\n            }\n            return expression;\n        }\n\n        /// <inheritdoc />\n        protected override Expression CallCreateTransparentIdentifier(\n            Type transparentIdentifierType,\n            Expression outerExpression,\n            Expression innerExpression)\n        {\n            ConstructorInfo constructorInfo = transparentIdentifierType.GetConstructor(\n                BindingFlags.NonPublic | BindingFlags.Instance,\n                null,\n                new []\n                {\n                    outerExpression.Type,\n                    innerExpression.Type\n                },\n                Array.Empty<ParameterModifier>());\n            return Expression.New(\n                constructorInfo,\n                outerExpression,\n                innerExpression);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbEntityQueryModelVisitorDependencies.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Query.ExpressionVisitors;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <summary>\n    ///     <para>\n    ///         Service dependencies parameter class for <see cref=\"MongoDbEntityQueryModelVisitor\" />\n    ///     </para>\n    ///     <para>\n    ///         This type is typically used by database providers (and other extensions). It is generally\n    ///         not used in application code.\n    ///     </para>\n    ///     <para>\n    ///         Do not construct instances of this class directly from either provider or application code as the\n    ///         constructor signature may change as new dependencies are added. Instead, use this type in\n    ///         your constructor so that an instance will be created and injected automatically by the\n    ///         dependency injection container. To create an instance with some dependent services replaced,\n    ///         first resolve the object from the dependency injection container, then replace selected\n    ///         services using the 'With...' methods. Do not call the constructor at any point in this process.\n    ///     </para>\n    /// </summary>\n    public class MongoDbEntityQueryModelVisitorDependencies\n    {\n        /// <summary>\n        ///     <para>\n        ///         Creates the service dependencies parameter object for a <see cref=\"MongoDbEntityQueryModelVisitorFactory\" />.\n        ///     </para>\n        ///     <para>\n        ///         This API supports the Entity Framework Core infrastructure and is not intended to be used\n        ///         directly from your code. This API may change or be removed in future releases.\n        ///     </para>\n        ///     <para>\n        ///         Do not call this constructor directly from either provider or application code as it may change\n        ///         as new dependencies are added. Instead, use this type in your constructor so that an instance\n        ///         will be created and injected automatically by the dependency injection container. To create\n        ///         an instance with some dependent services replaced, first resolve the object from the dependency\n        ///         injection container, then replace selected services using the 'With...' methods. Do not call\n        ///         the constructor at any point in this process.\n        ///     </para>\n        /// </summary>\n        /// <param name=\"mongoDbDenormalizedCollectionCompensatingVisitorFactory\">\n        ///     The <see cref=\"IMongoDbDenormalizedCollectionCompensatingVisitorFactory\" /> to be used when processing the query.\n        /// </param>\n        public MongoDbEntityQueryModelVisitorDependencies(\n            [NotNull] IMongoDbDenormalizedCollectionCompensatingVisitorFactory mongoDbDenormalizedCollectionCompensatingVisitorFactory\n            )\n        {\n            MongoDbDenormalizedCollectionCompensatingVisitorFactory\n                = Check.NotNull(mongoDbDenormalizedCollectionCompensatingVisitorFactory,\n                    nameof(mongoDbDenormalizedCollectionCompensatingVisitorFactory));\n        }\n\n        /// <summary>\n        ///     Gets the <see cref=\"IMongoDbDenormalizedCollectionCompensatingVisitorFactory\" /> to be used when processing a query.\n        /// </summary>\n        public IMongoDbDenormalizedCollectionCompensatingVisitorFactory\n            MongoDbDenormalizedCollectionCompensatingVisitorFactory { get; }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbEntityQueryModelVisitorFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class MongoDbEntityQueryModelVisitorFactory : EntityQueryModelVisitorFactory\n    {\n        /// <inheritdoc />\n        public MongoDbEntityQueryModelVisitorFactory(\n            [NotNull] EntityQueryModelVisitorDependencies entityQueryModelVisitorDependencies,\n            [NotNull] MongoDbEntityQueryModelVisitorDependencies mongoDbEntityQueryModelVisitorDependencies)\n            : base(Check.NotNull(entityQueryModelVisitorDependencies, nameof(entityQueryModelVisitorDependencies)))\n        {\n            MongoDbDependencies\n                = Check.NotNull(mongoDbEntityQueryModelVisitorDependencies, nameof(mongoDbEntityQueryModelVisitorDependencies));\n        }\n\n        /// <summary>\n        /// Dependencies used to create a <see cref=\"MongoDbEntityQueryModelVisitor\"/>.\n        /// </summary>\n        public MongoDbEntityQueryModelVisitorDependencies MongoDbDependencies { get; }\n\n        /// <inheritdoc />\n        public override EntityQueryModelVisitor Create(\n            QueryCompilationContext queryCompilationContext,\n            EntityQueryModelVisitor parentEntityQueryModelVisitor)\n            => new MongoDbEntityQueryModelVisitor(\n                Dependencies,\n                Check.NotNull(queryCompilationContext, nameof(queryCompilationContext)),\n                MongoDbDependencies);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbQueryBuffer.cs",
    "content": "﻿using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Linq;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class MongoDbQueryBuffer : QueryBuffer\n    {\n        private readonly IModel _model;\n        private readonly IStateManager _stateManager;\n        [NotNull] private readonly IEntityLoadInfoFactory _entityLoadInfoFactory;\n\n        /// <inheritdoc />\n        public MongoDbQueryBuffer(\n            [NotNull] QueryContextDependencies dependencies,\n            [NotNull] IEntityLoadInfoFactory entityLoadInfoFactory)\n\n            : base(dependencies)\n        {\n            _model = dependencies.CurrentDbContext.Context.Model;\n            _stateManager = dependencies.StateManager;\n            _entityLoadInfoFactory = Check.NotNull(entityLoadInfoFactory, nameof(entityLoadInfoFactory));\n        }\n\n        /// <inheritdoc />\n        public override void IncludeCollection<TEntity, TRelated, TElement>(\n            int includeId,\n            INavigation navigation,\n            INavigation inverseNavigation,\n            IEntityType targetEntityType,\n            IClrCollectionAccessor clrCollectionAccessor,\n            IClrPropertySetter inverseClrPropertySetter,\n            bool tracking,\n            TEntity entity,\n            Func<IEnumerable<TRelated>> relatedEntitiesFactory,\n            Func<TEntity, TRelated, bool> joinPredicate)\n        {\n            Check.NotNull(clrCollectionAccessor, nameof(clrCollectionAccessor));\n            Check.NotNull(inverseNavigation, nameof(inverseNavigation));\n            Check.NotNull(inverseClrPropertySetter, nameof(inverseClrPropertySetter));\n\n            ICollection<TRelated> collection = (ICollection<TRelated>) clrCollectionAccessor\n                .GetOrCreate(entity);\n\n            IClrPropertyGetter primaryKeyPropertyGetter = navigation\n                .GetTargetType()\n                .FindPrimaryKey()\n                .Properties\n                .Single()\n                .GetGetter();\n\n            IDictionary<object, TRelated> replacementMap = relatedEntitiesFactory()\n                .ToDictionary(\n                    related => primaryKeyPropertyGetter.GetClrValue(related));\n\n            IEnumerable<object> newCollectionItems = collection\n                .Select(original =>\n                    replacementMap.TryGetValue(\n                            primaryKeyPropertyGetter.GetClrValue(original),\n                            out TRelated related)\n                        ? related\n                        : original)\n                .Cast<object>()\n                .ToList();\n\n            collection.Clear();\n\n            foreach (TRelated item in newCollectionItems)\n            {\n                inverseClrPropertySetter.SetClrValue(item, entity);\n\n                if (tracking)\n                {\n                    InternalEntityEntry originalEntry = _stateManager.TryGetEntry(item);\n                    if (originalEntry != null)\n                    {\n                        _stateManager.StopTracking(originalEntry);\n                    }\n\n                    base.StartTracking(\n                        LoadEntity(\n                            item,\n                            targetEntityType,\n                            entity,\n                            inverseNavigation),\n                        targetEntityType);\n                }\n            }\n        }\n\n        /// <inheritdoc />\n        public override void StartTracking(object entity, EntityTrackingInfo entityTrackingInfo)\n            => base.StartTracking(\n                LoadEntity(\n                    Check.NotNull(entity, nameof(entity)),\n                    _model.FindEntityType(entity.GetType()),\n                    null,\n                    null),\n                entityTrackingInfo);\n\n        /// <inheritdoc />\n        public override void StartTracking(object entity, IEntityType entityType)\n            => base.StartTracking(\n                LoadEntity(entity, entityType, null, null),\n                entityType);\n\n        private object LoadEntity(object entity, IEntityType entityType, object owner, INavigation owningNavigation)\n        {\n            if (entity.GetType() != entityType.ClrType)\n            {\n                entityType = _model.FindEntityType(entity.GetType());\n            }\n\n            entity = GetEntity(\n                entityType.FindPrimaryKey(),\n                _entityLoadInfoFactory.Create(entity, entityType, owner, owningNavigation),\n                true,\n                true);\n\n            IEnumerable<INavigation> ownedNavigations = entityType\n                .GetNavigations()\n                .Where(navigation => navigation.ForeignKey.IsOwnership);\n\n            foreach (INavigation ownedNavigation in ownedNavigations)\n            {\n                IEntityType targetEntityType = ownedNavigation.GetTargetType();\n                var documentOrCollection = ownedNavigation.GetGetter().GetClrValue(entity);\n\n                if (ownedNavigation.IsCollection())\n                {\n                    IEnumerable collection = (IEnumerable) documentOrCollection;\n                    foreach (object document in collection)\n                    {\n                        base.StartTracking(\n                            LoadEntity(document, targetEntityType, entity, ownedNavigation),\n                            targetEntityType);\n                    }\n                }\n                else\n                {\n                    base.StartTracking(\n                        LoadEntity(documentOrCollection, targetEntityType, entity, ownedNavigation),\n                        targetEntityType);\n                }\n            }\n\n            return entity;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbQueryContext.cs",
    "content": "﻿using System;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class MongoDbQueryContext : QueryContext\n    {\n        /// <inheritdoc />\n        public MongoDbQueryContext(\n            [NotNull] QueryContextDependencies queryContextDependencies,\n            [NotNull] Func<IQueryBuffer> queryBufferFactory)\n            : base(\n                Check.NotNull(queryContextDependencies, nameof(queryContextDependencies)),\n                Check.NotNull(queryBufferFactory, nameof(queryBufferFactory))\n            )\n        {\n        }\n\n        /// <inheritdoc />\n        public override void BeginTrackingQuery()\n        {\n            Check.NotNull(QueryBuffer, nameof(QueryBuffer));\n            base.BeginTrackingQuery();\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/MongoDbQueryContextFactory.cs",
    "content": "﻿using JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class MongoDbQueryContextFactory : QueryContextFactory\n    {\n        [NotNull] private readonly IEntityLoadInfoFactory _entityLoadInfoFactory;\n\n        /// <inheritdoc />\n        public MongoDbQueryContextFactory(\n            [NotNull] QueryContextDependencies queryContextDependencies,\n            [NotNull] IEntityLoadInfoFactory entityLoadInfoFactory)\n            : base(\n                Check.NotNull(queryContextDependencies, nameof(queryContextDependencies)))\n        {\n            _entityLoadInfoFactory = Check.NotNull(entityLoadInfoFactory, nameof(entityLoadInfoFactory));\n        }\n\n        /// <inheritdoc />\n        public override QueryContext Create()\n            => new MongoDbQueryContext(\n                Dependencies,\n                CreateQueryBuffer);\n\n        /// <inheritdoc />\n        protected override IQueryBuffer CreateQueryBuffer()\n            => new MongoDbQueryBuffer(\n                Dependencies,\n                _entityLoadInfoFactory);\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/QueryableLinqOperatorProvider.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Reflection;\nusing Microsoft.EntityFrameworkCore.Query.Internal;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class QueryableLinqOperatorProvider : LinqOperatorProvider\n    {\n        private static readonly MethodInfo AllMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.All<object>(null, obj => false));\n\n        private static readonly MethodInfo AnyMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Any<object>(null, obj => false));\n\n        private static readonly MethodInfo CastMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Cast<object>(null));\n\n        private static readonly MethodInfo ConcatMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Concat<object>(null, null));\n\n        private static readonly MethodInfo ContainsMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Contains<object>(null, null));\n\n        private static readonly MethodInfo CountMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Count<object>(null));\n\n        private static readonly MethodInfo DefaultIfEmptyMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.DefaultIfEmpty<object>(null));\n\n        private static readonly MethodInfo ParameterizedDefaultIfEmptyMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.DefaultIfEmpty<object>(null, null));\n\n        private static readonly MethodInfo DistinctMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Distinct<object>(null));\n\n        private static readonly MethodInfo ExceptMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Except<object>(null, null));\n\n        private static readonly MethodInfo FirstMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.First<object>(null, obj => false));\n\n        private static readonly MethodInfo FirstOrDefaultMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.FirstOrDefault<object>(null, obj => false));\n\n        private static readonly MethodInfo GroupByMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.GroupBy<object, object, object>(\n                null,\n                obj => null,\n                (obj1, obj2) => null));\n\n        private static readonly MethodInfo GroupJoinMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.GroupJoin<object, object, object, object>(\n                null,\n                null,\n                obj => null,\n                obj => null,\n                (@obj1, @obj2) => null));\n\n        private static readonly MethodInfo IntersectByMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Intersect<object>(null, null));\n\n        private static readonly MethodInfo JoinMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Join<object, object, object, object>(\n                null,\n                null,\n                obj => null,\n                obj => null,\n                (@obj1, @obj2) => null));\n\n        private static readonly MethodInfo LastMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Last<object>(null, obj => false));\n\n        private static readonly MethodInfo LastOrDefaultMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.LastOrDefault<object>(null, obj => false));\n\n        private static readonly MethodInfo LongCountMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.LongCount<object>(null, obj => false));\n\n        private static readonly MethodInfo OfTypeMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.OfType<object>(null));\n\n        private static readonly MethodInfo OrderByMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.OrderBy<object, object>(null, obj => null));\n\n        private static readonly MethodInfo SelectMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Select<object, object>(null, obj => null));\n\n        private static readonly MethodInfo SelectManyMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.SelectMany<object, object>(null, obj => null));\n\n        private static readonly MethodInfo SingleMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Single<object>(null, obj => false));\n\n        private static readonly MethodInfo SingleOrDefaultMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.SingleOrDefault<object>(null, obj => false));\n\n        private static readonly MethodInfo SkipMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Skip<object>(null, 0));\n\n        private static readonly MethodInfo TakeMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Take<object>(null, 0));\n\n        private static readonly MethodInfo UnionMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Union<object>(null, null));\n\n        private static readonly MethodInfo WhereMethodInfo = MethodHelper.GetGenericMethodDefinition<object>(\n            () => Queryable.Where<object>(null, obj => false));\n\n        /// <inheritdoc />\n        public override MethodInfo GetAggregateMethod(string methodName, Type elementType)\n            => base.GetAggregateMethod(methodName, elementType);\n\n        /// <inheritdoc />\n        public override Type MakeSequenceType(Type elementType)\n            => base.MakeSequenceType(elementType);\n\n        /// <inheritdoc />\n        public override MethodInfo All => AllMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Any => AnyMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Cast => CastMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Concat => ConcatMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Contains => ContainsMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Count => CountMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo DefaultIfEmpty => DefaultIfEmptyMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo DefaultIfEmptyArg => ParameterizedDefaultIfEmptyMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Distinct => DistinctMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Except => ExceptMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo First => FirstMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo FirstOrDefault => FirstOrDefaultMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo GroupBy => GroupByMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo GroupJoin => GroupJoinMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Intersect => IntersectByMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Join => JoinMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Last => LastMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo LastOrDefault => LastOrDefaultMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo LongCount => LongCountMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo OfType => OfTypeMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo OrderBy => OrderByMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Select => SelectMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo SelectMany => SelectManyMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Single => SingleMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo SingleOrDefault => SingleOrDefaultMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Skip => SkipMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Take => TakeMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo ThenBy => TakeMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Union => UnionMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo Where => WhereMethodInfo;\n\n        /// <inheritdoc />\n        public override MethodInfo ToSequence => base.ToSequence;\n\n        /// <inheritdoc />\n        public override MethodInfo ToOrdered => base.ToOrdered;\n\n        /// <inheritdoc />\n        public override MethodInfo ToEnumerable => base.ToEnumerable;\n\n        /// <inheritdoc />\n        public override MethodInfo ToQueryable => base.ToQueryable;\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Query/ValueBufferFactory.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Query\n{\n    /// <inheritdoc />\n    public class ValueBufferFactory : IValueBufferFactory\n    {\n        /// <inheritdoc />\n        public ValueBuffer CreateFromInstance(\n            object instance,\n            IEntityType entityType,\n            object owner,\n            INavigation owningNavigation)\n        {\n            Check.NotNull(instance, nameof(instance));\n            Check.NotNull(entityType, nameof(entityType));\n\n            PropertyCounts propertyCounts = entityType.AsEntityType().Counts;\n\n            var propertyValues = new object[propertyCounts.PropertyCount];\n\n            IEnumerable<Property> properties = entityType\n                .GetProperties()\n                .Where(property => !property.IsForeignKey())\n                .Select(property => property.AsProperty());\n\n            foreach (Property property in properties)\n            {\n                if (!property.IsShadowProperty)\n                {\n                    propertyValues[property.GetIndex()] = property.Getter.GetClrValue(instance);\n                }\n                else if (property.IsPrimaryKey())\n                {\n                    Debug.Assert(entityType.IsOwned(), $\"Non-owned entity type {entityType.Name} with a shadow primary key.\");\n                    propertyValues[property.GetShadowIndex()] = instance.GetHashCode();\n                }\n            }\n\n            if (owningNavigation != null)\n            {\n                Check.NotNull(owner, nameof(owner));\n\n                IForeignKey foreignKey = owningNavigation.ForeignKey;\n\n                for (int i = 0; i < foreignKey.Properties.Count; i++)\n                {\n                    IProperty foreignKeyProperty = foreignKey.Properties[i];\n                    IProperty principalKeyProperty = foreignKey.PrincipalKey.Properties[i];\n\n                    propertyValues[foreignKeyProperty.GetIndex()] = foreignKey.IsOwnership\n                                                                    && principalKeyProperty.IsShadowProperty\n                        ? owner.GetHashCode()\n                        : principalKeyProperty.GetGetter().GetClrValue(owner);\n                }\n            }\n\n            IEnumerable<INavigation> navigations = entityType\n                .GetNavigations()\n                .Where(navigation => navigation.IsDependentToPrincipal()\n                                     && !navigation.IsCollection());\n\n            foreach (INavigation navigation in navigations)\n            {\n                var related = navigation.GetGetter().GetClrValue(instance);\n                if (related != null)\n                {\n                    IForeignKey foreignKey = navigation.ForeignKey;\n\n                    for (int i = 0; i < foreignKey.Properties.Count; i++)\n                    {\n                        IProperty foreignKeyProperty = foreignKey.Properties[i];\n                        IProperty principalKeyProperty = foreignKey.PrincipalKey.Properties[i];\n\n                        propertyValues[foreignKeyProperty.GetIndex()] = foreignKey.IsOwnership\n                                                                        && principalKeyProperty.IsShadowProperty\n                            ? related.GetHashCode()\n                            : principalKeyProperty.GetGetter().GetClrValue(related);\n                    }\n                }\n            }\n\n            return new ValueBuffer(propertyValues, 0);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/IMongoDbConnection.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing MongoDB.Driver;\nusing MongoDB.Driver.Linq;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <summary>\n    ///     An interface for a service that can be used to interact with a MongoDB instance.\n    /// </summary>\n    public interface IMongoDbConnection\n    {\n        /// <summary>\n        ///     Gets the <see cref=\"IMongoDatabase\"/> used by the current model.\n        /// </summary>\n        /// <returns>The <see cref=\"IMongoDatabase\"/> used by the MongoDB C# driver to communicate with the MongoDB instance.</returns>\n        IMongoDatabase GetDatabase();\n\n        /// <summary>\n        ///     Asynchronously gets the <see cref=\"IMongoDatabase\"/> used by the current model.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A <see cref=\"CancellationToken \"/> to observe while waiting for the task to complete.</param>\n        /// <returns>\n        ///     A <see cref=\"Task{TResult}\"/> representing the state of the operation. The result contains The\n        ///     <see cref=\"IMongoDatabase\"/> used by the MongoDB C# driver to communicate with the MongoDB instance.\n        /// </returns>\n        Task<IMongoDatabase> GetDatabaseAsync(CancellationToken cancellationToken = default(CancellationToken));\n\n        /// <summary>\n        ///     Drops the database used by this model from the MongoDB instance.\n        /// </summary>\n        void DropDatabase();\n\n        /// <summary>\n        ///     Asynchronously drops the database used by this model from the MongoDB instance.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A <see cref=\"CancellationToken \"/> to observe while waiting for the task to complete.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> representing the state of the operation.</returns>\n        Task DropDatabaseAsync(CancellationToken cancellationToken = default(CancellationToken));\n\n        /// <summary>\n        ///     Gets a <see cref=\"IMongoCollection{TEntity}\"/> instance that can be used to store instances of <typeparamref name=\"TEntity\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">The type of entity stored in the collection.</typeparam>\n        /// <returns>The <see cref=\"IMongoCollection{TEntity}\"/> instance that can store <typeparamref name=\"TEntity\"/>.</returns>\n        IMongoCollection<TEntity> GetCollection<TEntity>();\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/IMongoDbTypeMappingSource.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.Storage;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <inheritdoc />\n    public interface IMongoDbTypeMappingSource : ITypeMappingSource\n    {\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/MongoDbConnection.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <summary>\n    ///     A service that can be used to interact with a MongoDB instance.\n    /// </summary>\n    public class MongoDbConnection : IMongoDbConnection\n    {\n        private readonly IMongoClient _mongoClient;\n        private readonly IMongoDatabase _mongoDatabase;\n        private readonly IModel _model;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbConnection\"/> class.\n        /// </summary>\n        /// <param name=\"mongoClient\">The <see cref=\"IMongoClient\"/> used to communicate with the MongoDB instance.</param>\n        /// <param name=\"model\">The <see cref=\"IModel\"/> used by this connection.</param>\n        public MongoDbConnection(\n            [NotNull] IMongoClient mongoClient,\n            [NotNull] IModel model)\n        {\n            _model = Check.NotNull(model, nameof(model));\n\n            _mongoClient = Check.NotNull(mongoClient, nameof(mongoClient));\n            _mongoDatabase = _mongoClient.GetDatabase(new MongoDbModelAnnotations(model).Database);\n        }\n\n        /// <inheritdoc />\n        public virtual IMongoDatabase GetDatabase()\n            => _mongoDatabase;\n\n        /// <inheritdoc />\n        public virtual Task<IMongoDatabase> GetDatabaseAsync(CancellationToken cancellationToken = default(CancellationToken))\n            => Task.FromResult(_mongoDatabase);\n\n        /// <inheritdoc />\n        public virtual void DropDatabase()\n            => _mongoClient.DropDatabase(new MongoDbModelAnnotations(_model).Database);\n\n        /// <inheritdoc />\n        public virtual Task DropDatabaseAsync(CancellationToken cancellationToken = default(CancellationToken))\n            => _mongoClient.DropDatabaseAsync(new MongoDbModelAnnotations(_model).Database, cancellationToken);\n\n        /// <inheritdoc />\n        public virtual IMongoCollection<TEntity> GetCollection<TEntity>()\n        {\n            IEntityType collectionEntityType = _model\n                .FindEntityType(typeof(TEntity))\n                .GetMongoDbCollectionEntityType();\n\n            MongoDbEntityTypeAnnotations annotations = collectionEntityType.MongoDb();\n\n            return _mongoDatabase.GetCollection<TEntity>(annotations.CollectionName, annotations.CollectionSettings);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/MongoDbDatabase.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Driver;\nusing Remotion.Linq;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <summary>\n    ///     The main interaction point between a context and MongoDB.\n    ///     This type is typically used by database providers (and other extensions). It\n    ///     is generally not used in application code.\n    /// </summary>\n    public class MongoDbDatabase : Database\n    {\n        private static readonly MethodInfo GenericUpdateEntries = \n            MethodHelper.GetGenericMethodDefinition(\n                (MongoDbDatabase mongoDbDatabase) => mongoDbDatabase.UpdateEntries<object>(null));\n\n        private static readonly MethodInfo GenericUpdateEntriesAsync\n            = MethodHelper.GetGenericMethodDefinition(\n                (MongoDbDatabase mongoDbDatabase) => mongoDbDatabase.UpdateEntriesAsync<object>(null, CancellationToken.None));\n\n        private readonly IMongoDbConnection _mongoDbConnection;\n        private readonly IMongoDbWriteModelFactorySelector _mongoDbWriteModelFactorySelector;\n\n        /// <summary>\n        /// Initializes a new instance of hte <see cref=\"MongoDbDatabase\"/> class.\n        /// </summary>\n        /// <param name=\"databaseDependencies\">Parameter object containing dependencies for this service.</param>\n        /// <param name=\"mongoDbConnection\">A <see cref=\"IMongoDbConnection\"/> used to communicate with the MongoDB instance.</param>\n        /// <param name=\"mongoDbWriteModelFactorySelector\">The <see cref=\"IMongoDbWriteModelFactorySelector\"/> to use to create\n        /// <see cref=\"IMongoDbWriteModelFactory{TEntity}\"/> instances.</param>\n        public MongoDbDatabase(\n            [NotNull] DatabaseDependencies databaseDependencies,\n            [NotNull] IMongoDbConnection mongoDbConnection,\n            [NotNull] IMongoDbWriteModelFactorySelector mongoDbWriteModelFactorySelector)\n            : base(Check.NotNull(databaseDependencies, nameof(databaseDependencies)))\n        {\n            _mongoDbConnection = Check.NotNull(mongoDbConnection, nameof(mongoDbConnection));\n            _mongoDbWriteModelFactorySelector = Check.NotNull(mongoDbWriteModelFactorySelector, nameof(mongoDbWriteModelFactorySelector));\n        }\n\n        /// <summary>\n        ///     Persists changes from the supplied entries to the database.\n        /// </summary>\n        /// <param name=\"entries\">A list of entries to be persisted.</param>\n        /// <returns>The number of entries that were persisted.</returns>\n        public override int SaveChanges(IReadOnlyList<IUpdateEntry> entries)\n            => GetDocumentUpdateDefinitions(entries)\n                .ToLookup(entry => entry.EntityType.GetMongoDbCollectionEntityType())\n                .Sum(grouping => (int)GenericUpdateEntries.MakeGenericMethod(grouping.Key.ClrType)\n                    .Invoke(this, new object[] { grouping }));\n\n        private int UpdateEntries<TEntity>(IEnumerable<IUpdateEntry> entries)\n        {\n            IEnumerable<WriteModel<TEntity>> writeModels = entries\n                .Select(entry => _mongoDbWriteModelFactorySelector.Select<TEntity>(entry).CreateWriteModel(entry))\n                .ToList();\n            BulkWriteResult result = _mongoDbConnection.GetCollection<TEntity>()\n                .BulkWrite(writeModels);\n            return (int) (result.DeletedCount + result.InsertedCount + result.ModifiedCount);\n        }\n\n        private ISet<IUpdateEntry> GetDocumentUpdateDefinitions(IReadOnlyCollection<IUpdateEntry> entries)\n        {\n            Check.NotNull(entries, nameof(entries));\n\n            ISet<IUpdateEntry> rootEntries = new HashSet<IUpdateEntry>();\n\n            foreach (IUpdateEntry updateEntry in entries)\n            {\n                if (updateEntry.EntityType.IsDocumentRootEntityType())\n                {\n                    rootEntries.Add(updateEntry);\n                }\n                else if (updateEntry is InternalEntityEntry internalEntityEntry)\n                {\n                    rootEntries.Add(GetRootDocument(internalEntityEntry));\n                }\n                else\n                {\n                    // TBD - throw error\n                }\n            }\n\n            return rootEntries;\n        }\n\n        /// <summary>\n        ///     Asynchronously persists changes from the supplied entries to the database.\n        /// </summary>\n        /// <param name=\"entries\">A list of entries to be persisted.</param>\n        /// <param name=\"cancellationToken\">A <see cref=\"CancellationToken \"/> to observe while waiting for the task to complete.</param>\n        /// <returns>\n        ///     A <see cref=\"Task{TResult}\"/> representing the state of the operation. The result contains the number\n        ///     of entries that were persisted to the database.\n        /// </returns>\n        public override async Task<int> SaveChangesAsync(\n            IReadOnlyList<IUpdateEntry> entries,\n            CancellationToken cancellationToken = default)\n        {\n            IEnumerable<Task<int>> tasks = GetDocumentUpdateDefinitions(entries)\n                .ToLookup(entry => entry.EntityType.GetMongoDbCollectionEntityType())\n                .Select(async grouping => await InvokeUpdateEntriesAsync(grouping, cancellationToken))\n                .ToList();\n\n            int[] totals = await Task.WhenAll(tasks);\n            return totals.Sum();\n        }\n\n        private Task<int> InvokeUpdateEntriesAsync(IGrouping<IEntityType, IUpdateEntry> entryGrouping, CancellationToken cancellationToken)\n            => (Task<int>)GenericUpdateEntriesAsync.MakeGenericMethod(entryGrouping.Key.ClrType)\n                .Invoke(this, new object[] {entryGrouping, cancellationToken});\n\n        private async Task<int> UpdateEntriesAsync<TEntity>(\n            IEnumerable<IUpdateEntry> entries,\n            CancellationToken cancellationToken)\n        {\n            IEnumerable<WriteModel<TEntity>> writeModels = entries\n                .Select(entry => _mongoDbWriteModelFactorySelector.Select<TEntity>(entry).CreateWriteModel(entry))\n                .ToList();\n            BulkWriteResult result = await _mongoDbConnection.GetCollection<TEntity>()\n                .BulkWriteAsync(writeModels,\n                    options: null,\n                    cancellationToken: cancellationToken);\n            return (int) (result.DeletedCount + result.InsertedCount + result.ModifiedCount);\n        }\n\n        /// <inheritdoc />\n        public override Func<QueryContext, IAsyncEnumerable<TResult>> CompileAsyncQuery<TResult>(QueryModel queryModel)\n            => queryContext => CompileQuery<TResult>(queryModel)(queryContext).ToAsyncEnumerable();\n\n        private IUpdateEntry GetRootDocument(InternalEntityEntry entry)\n        {\n            var stateManager = entry.StateManager;\n\n            InternalEntityEntry owningEntityEntry = entry.EntityType\n                .GetForeignKeys()\n                .Where(foreignKey => foreignKey.IsOwnership)\n                .Select(foreignKey => stateManager.GetPrincipal(entry, foreignKey))\n                .SingleOrDefault(owner => owner != null);\n\n            if (owningEntityEntry == null)\n            {\n                throw new InvalidOperationException($\"Encountered orphaned document of type {entry.EntityType.DisplayName()}.\");\n            }\n\n            return owningEntityEntry.EntityType.IsDocumentRootEntityType()\n                ? owningEntityEntry\n                : GetRootDocument(owningEntityEntry);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/MongoDbDatabaseCreator.cs",
    "content": "using System.Threading;\nusing System.Threading.Tasks;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <summary>\n    ///     Creates and deletes databases for a given database provider.\n    ///     This interface is typically used by database providers (and other extensions).\n    ///     It is generally not used in application code.\n    /// </summary>\n    public class MongoDbDatabaseCreator : IDatabaseCreator\n    {\n        private readonly IMongoDbConnection _mongoDbConnection;\n\n        /// <summary>\n        ///     Initializes a new instance of the <see cref=\"MongoDbDatabaseCreator\"/> class.\n        /// </summary>\n        /// <param name=\"mongoDbConnection\">The <see cref=\"IMongoDbConnection\"/> used to communicate with the MongoDB instance.</param>\n        public MongoDbDatabaseCreator([NotNull] IMongoDbConnection mongoDbConnection)\n        {\n            _mongoDbConnection = Check.NotNull(mongoDbConnection, nameof(mongoDbConnection));\n        }\n\n        /// <summary>\n        ///     Ensures that the database for the context exists.\n        /// </summary>\n        /// <returns>\n        ///     MongoDB databases will always be created when they are first referenced, so this method will always\n        ///     return <code>false</code>.\n        /// </returns>\n        public virtual bool EnsureCreated()\n        {\n            _mongoDbConnection.GetDatabase();\n            return false;\n        }\n\n        /// <summary>\n        ///     Asynchronously ensures that the database for the context exists.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A <see cref=\"CancellationToken\"/> to observe while waiting for the task to complete.</param>\n        /// <returns>\n        ///     A task that represents the asynchronous save operation. MongoDB databases will always be created when they are\n        ///     first referenced, so the result will always contain <code>false</code>.\n        /// </returns>\n        public virtual async Task<bool> EnsureCreatedAsync(CancellationToken cancellationToken = new CancellationToken())\n        {\n            await _mongoDbConnection.GetDatabaseAsync(cancellationToken);\n            return false;\n        }\n\n        /// <summary>\n        ///     Ensures that the database for the context does not exist.\n        /// </summary>\n        /// <returns>\n        ///     MongoDB database are always created when they are first referenced, so this method\n        ///     will always return <code>true</code>.\n        /// </returns>\n        public virtual bool EnsureDeleted()\n        {\n            _mongoDbConnection.DropDatabase();\n            return true;\n        }\n\n        /// <summary>\n        ///     Asynchronously ensures that the database for the context does not exist.\n        /// </summary>\n        /// <param name=\"cancellationToken\">A <see cref=\"CancellationToken \"/> to observe while waiting for the task to complete.</param>\n        /// <returns>\n        ///     A task that represents the asynchronous save operation. MongoDB database are always created when they are first\n        ///     referenced, so the result will always contain <code>true</code>.\n        /// </returns>\n        public virtual async Task<bool> EnsureDeletedAsync(CancellationToken cancellationToken = new CancellationToken())\n        {\n            await _mongoDbConnection.DropDatabaseAsync(cancellationToken);\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/Storage/MongoDbTypeMappingSource.cs",
    "content": "﻿using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Storage\n{\n    /// <inheritdoc cref=\"TypeMappingSource\" />\n    /// <inheritdoc cref=\"IMongoDbTypeMappingSource\" />\n    /// <summary>\n    /// Determines whether a .NET type can be mapped to a MongoDB database type.\n    /// </summary>\n    public class MongoDbTypeMappingSource : TypeMappingSource, IMongoDbTypeMappingSource\n    {\n        private readonly ConcurrentDictionary<Type, CoreTypeMapping> _typeCache = new ConcurrentDictionary<Type, CoreTypeMapping>\n        {\n            [typeof(string)] = new PassThruTypeMapping(typeof(string)),\n            [typeof(IEnumerable<string>)] = new PassThruTypeMapping(typeof(IEnumerable<string>)),\n            [typeof(ObjectId)] = new PassThruTypeMapping(typeof(ObjectId)),\n            [typeof(IEnumerable<ObjectId>)] = new PassThruTypeMapping(typeof(IEnumerable<ObjectId>)),\n            [typeof(byte[])] = new PassThruTypeMapping(typeof(byte[])),\n            [typeof(IEnumerable<byte[]>)] = new PassThruTypeMapping(typeof(IEnumerable<byte[]>))\n        };\n\n        /// <inheritdoc />\n        public MongoDbTypeMappingSource([NotNull] TypeMappingSourceDependencies dependencies)\n            : base(dependencies)\n        {\n        }\n\n        /// <inheritdoc />\n        protected override CoreTypeMapping FindMapping(in TypeMappingInfo mappingInfo)\n            => _typeCache.GetOrAdd(\n                   mappingInfo.ClrType,\n                   clrType =>\n                   {\n                       TypeInfo typeInfo = (clrType.TryGetSequenceType() ?? clrType).UnwrapNullableType().GetTypeInfo();\n\n                       return typeInfo.IsPrimitive\n                              || typeInfo.IsValueType\n                           ? new PassThruTypeMapping(clrType)\n                           : null;\n                   });\n\n        private class PassThruTypeMapping : CoreTypeMapping\n        {\n            private PassThruTypeMapping(CoreTypeMappingParameters parameters)\n                : base(parameters)\n            {\n            }\n\n            public PassThruTypeMapping([NotNull] Type clrType)\n                : base(new CoreTypeMappingParameters(clrType))\n            {\n            }\n\n            public override CoreTypeMapping Clone(ValueConverter converter)\n                => new PassThruTypeMapping(Parameters.WithComposedConverter(converter));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ValueGeneration/HashCodeValueGenerator.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration\n{\n    /// <inheritdoc />\n    public class HashCodeValueGenerator : ValueGenerator<int?>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        ///     Generates a new <see cref=\"ObjectId\"/> value.\n        /// </summary>\n        /// <param name=\"entry\">The <see cref=\"EntityEntry\"/> whose value is to be generated.</param>\n        /// <returns>A new <see cref=\"ObjectId\"/> for <see cref=\"EntityEntry\"/>.</returns>\n        public override int? Next(EntityEntry entry)\n            => entry.Entity?.GetHashCode();\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     <code>true</code> if this <see cref=\"HashCodeValueGenerator\"/> generates temporary values;\n        ///     otherwise <code>false</code>.\n        /// </summary>\n        /// <remarks>Always returns <c>true</c>.</remarks>\n        public override bool GeneratesTemporaryValues => false;\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ValueGeneration/IntegerValueGenerator.cs",
    "content": "﻿using System;\nusing System.Globalization;\nusing System.Threading;\nusing Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration\n{\n    /// <inheritdoc />\n    public class IntegerValueGenerator<TValue> : ValueGenerator<TValue>\n    {\n        private long _currentValue;\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     Generates a new <see cref=\"ObjectId\"/> value.\n        /// </summary>\n        /// <param name=\"entry\">The <see cref=\"EntityEntry\"/> whose value is to be generated.</param>\n        /// <returns>A new <see cref=\"ObjectId\"/> for <see cref=\"EntityEntry\"/>.</returns>\n        public override TValue Next(EntityEntry entry)\n            => (TValue) Convert.ChangeType(\n                Interlocked.Increment(ref _currentValue),\n                typeof(TValue),\n                CultureInfo.InvariantCulture);\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     <code>true</code> if this <see cref=\"IntegerValueGenerator{TValue}\"/> generates temporary values;\n        ///     otherwise <code>false</code>.\n        /// </summary>\n        /// <remarks>Always returns <c>false</c>.</remarks>\n        public override bool GeneratesTemporaryValues => false;\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ValueGeneration/MongoDbValueGeneratorSelector.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration\n{\n    /// <inheritdoc />\n    public class MongoDbValueGeneratorSelector : ValueGeneratorSelector\n    {\n        private readonly IDictionary<Type, Func<ValueGenerator>> _valueGeneratorMap =\n            new Dictionary<Type, Func<ValueGenerator>>\n            {\n                [typeof(ObjectId)] = () => new ObjectIdValueGenerator(),\n                [typeof(short)] = () => new IntegerValueGenerator<short>(),\n                [typeof(int)] = () => new IntegerValueGenerator<int>(),\n                [typeof(long)] = () => new IntegerValueGenerator<long>(),\n            };\n\n        private readonly IDictionary<Type, Func<ValueGenerator>> _shadowKeyGeneratorMap =\n            new Dictionary<Type, Func<ValueGenerator>>\n            {\n                [typeof(int)] = () => new HashCodeValueGenerator()\n            };\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration.MongoDbValueGeneratorSelector\" /> class.\n        /// </summary>\n        /// <param name=\"dependencies\">Parameter object containing dependencies for this service.</param>\n        public MongoDbValueGeneratorSelector([NotNull] ValueGeneratorSelectorDependencies dependencies)\n            : base(dependencies)\n        {\n        }\n\n        /// <inheritdoc />\n        /// <summary>\n        ///     Creates a new value generator for the given property.\n        /// </summary>\n        /// <param name=\"property\">The property to get the value generator for.</param>\n        /// <param name=\"entityType\">\n        ///     The entity type that the value generator will be used for. When called on inherited\n        ///     properties on derived entity types, this entity type may be different from the\n        ///     declared entity type on property\n        /// </param>\n        /// <returns>The newly created value generator.</returns>\n        public override ValueGenerator Create(\n            IProperty property,\n            IEntityType entityType)\n        {\n            Check.NotNull(property, nameof(property));\n            Check.NotNull(entityType, nameof(entityType));\n\n            IDictionary<Type, Func<ValueGenerator>> valueGeneratorCreator = property.IsShadowProperty\n                ? _shadowKeyGeneratorMap\n                : _valueGeneratorMap;\n\n            return valueGeneratorCreator\n                .TryGetValue(\n                    property.ClrType.UnwrapNullableType(),\n                    out Func<ValueGenerator> valueGeneratorFactory)\n                ? valueGeneratorFactory()\n                : base.Create(property, entityType);\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB/ValueGeneration/ObjectIdValueGenerator.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Bson;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration\n{\n    /// <summary>\n    ///     Generates values for <see cref=\"ObjectId\"/> properties when an entity is added to a context.\n    /// </summary>\n    public class ObjectIdValueGenerator : ValueGenerator<ObjectId>\n    {\n        /// <summary>\n        ///     Generates a new <see cref=\"ObjectId\"/> value.\n        /// </summary>\n        /// <param name=\"entry\">The <see cref=\"EntityEntry\"/> whose value is to be generated.</param>\n        /// <returns>A new <see cref=\"ObjectId\"/> for <see cref=\"EntityEntry\"/>.</returns>\n        public override ObjectId Next(EntityEntry entry)\n            => ObjectId.GenerateNewId();\n\n        /// <summary>\n        ///     <code>true</code> if this <see cref=\"ObjectIdValueGenerator\"/> generates temporary values;\n        ///     otherwise <code>false</code>.\n        /// </summary>\n        /// <remarks>Always returns <c>false</c>.</remarks>\n        public override bool GeneratesTemporaryValues => false;\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(BuildFrameworks)</TargetFrameworks>\n    <Product>Blueshift MongoDb Provider for EntityFrameworkCore</Product>\n    <Description>Sample Domain Library for EntityFramework Core MongoDb Provider</Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\CodeAnnotations.cs\" Link=\"CodeAnnotations.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Blueshift.EntityFrameworkCore.MongoDB\\Blueshift.EntityFrameworkCore.MongoDB.csproj\" NoWarn=\"KRB4002\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain/ZooDbContext.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization.Attributes;\nusing MongoDB.Driver;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\n{\n    [MongoDatabase(\"zooDb\")]\n    public class ZooDbContext : DbContext\n    {\n        public DbSet<Animal> Animals { get; set; }\n        public DbSet<Employee> Employees { get; set; }\n        public DbSet<Enclosure> Enclosures { get; set; }\n\n        public ZooDbContext()\n            : this(new DbContextOptions<ZooDbContext>())\n        {\n        }\n\n        public ZooDbContext(DbContextOptions<ZooDbContext> zooDbContextOptions)\n            : base(zooDbContextOptions)\n        {\n        }\n\n        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            const string connectionString = \"mongodb://localhost\";\n            //optionsBuilder.UseMongoDb(connectionString);\n\n            var mongoUrl = new MongoUrl(connectionString);\n            //optionsBuilder.UseMongoDb(mongoUrl);\n\n            MongoClientSettings settings = MongoClientSettings.FromUrl(mongoUrl);\n            //settings.SslSettings = new SslSettings\n            //{\n            //    EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12\n            //};\n            //optionsBuilder.UseMongoDb(settings);\n\n            var mongoClient = new MongoClient(settings);\n            optionsBuilder.UseMongoDb(mongoClient);\n        }\n    }\n\n    [BsonKnownTypes(typeof(Tiger), typeof(PolarBear), typeof(Otter))]\n    [BsonDiscriminator(RootClass = true)]\n    public abstract class Animal\n    {\n        // When using attribute-driven data modeling, either [BsonId] or [Key]\n        // is required for the primary key field; either will work with the\n        // MongoDb C# driver EFCore adapter\n        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n        public ObjectId AnimalId { get; [UsedImplicitly] private set; }\n\n        public string Name { get; set; }\n\n        public decimal Age { get; set; }\n\n        public decimal Height { get; set; }\n\n        public decimal Weight { get; set; }\n\n        [ConcurrencyCheck, DatabaseGenerated(DatabaseGeneratedOption.Computed)]\n        public string ConcurrencyField { get; [UsedImplicitly] private set; }\n\n        [Denormalize(nameof(SampleDomain.Enclosure.Name))]\n        public Enclosure Enclosure { get; set; }\n    }\n\n    [BsonDiscriminator(\"panthera tigris\")]\n    public class Tiger : Animal { }\n\n    [BsonDiscriminator(\"Ursus maritimus\")]\n    public class PolarBear : Animal { }\n\n    [BsonDiscriminator(\"Lutrinae\")]\n    [BsonKnownTypes(typeof(SeaOtter), typeof(EurasianOtter))]\n    public abstract class Otter : Animal { }\n\n    [BsonDiscriminator(\"Enhydra lutris\")]\n    public class SeaOtter : Otter { }\n\n    [BsonDiscriminator(\"Lutra lutra\")]\n    public class EurasianOtter : Otter { }\n\n    public class Employee\n    {\n        // When using attribute-driven data modeling, either [BsonId] or [Key]\n        // is required for the primary key field; either will work with the\n        // MongoDb C# driver EFCore adapter\n        [BsonId, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n        public ObjectId EmployeeId { get; [UsedImplicitly] private set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        [BsonElement]\n        public string FullName => string.IsNullOrWhiteSpace(FirstName)\n            ? LastName\n            : $\"{LastName}, {FirstName}\";\n\n        public decimal Age { get; set; }\n\n        public IList<Specialty> Specialties { get; set; } = new List<Specialty>();\n\n        [BsonIgnore]\n        public string Ignored => $\"This string should never show up in the database.\";\n\n        public Employee Manager { get; set; }\n\n        public IList<Employee> DirectReports { get; set; } = new List<Employee>();\n    }\n\n    public enum ZooTask\n    {\n        Feeding,\n        Training,\n        Exercise,\n        TourGuide\n    }\n\n    [Owned]\n    public class Specialty\n    {\n        public string AnimalType { get; set; }\n\n        public ZooTask Task { get; set; }\n    }\n\n    public class Enclosure\n    {\n        // When using attribute-driven data modeling, either [BsonId] or [Key]\n        // is required for the primary key field; either will work with the\n        // MongoDb C# driver EFCore adapter\n        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n        public ObjectId EnclosureId { get; [UsedImplicitly] private set; }\n\n        public string Name { get; set; }\n\n        public string AnimalEnclosureType { get; set; }\n\n        [Denormalize(nameof(Animal.Name))]\n        public IList<Animal> Animals { get; [UsedImplicitly] private set; } = new List<Animal>();\n\n        public Schedule WeeklySchedule { get; set; }\n\n    }\n\n    [Owned]\n    public class Schedule\n    {\n        public IList<ZooAssignment> Assignments { get; [UsedImplicitly] private set; } = new List<ZooAssignment>();\n\n        [Denormalize(nameof(Employee.FirstName), nameof(Employee.LastName))]\n        public Employee Approver { get; set; }\n    }\n\n    public class ZooAssignment\n    {\n        public TimeSpan Offset { get; set; }\n\n        public ZooTask Task { get; set; }\n\n        [Denormalize(nameof(Employee.FirstName), nameof(Employee.LastName))]\n        public Employee Assignee { get; set; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain/ZooDbDependencyInjection.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\n{\n    public static class ZooDbDependencyInjection\n    {\n        public static IServiceCollection AddZooDbContext(this IServiceCollection serviceCollection)\n        {\n            return serviceCollection\n                .AddDbContext<ZooDbContext>(options => options.UseMongoDb(\"mongodb://localhost\"));\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain/ZooEntityFixture.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\n{\n    internal static class ZooExtensions\n    {\n        public static TAnimal WithEnclosure<TAnimal>(this TAnimal animal, Enclosure enclosure)\n            where TAnimal : Animal\n        {\n            animal.Enclosure = enclosure;\n            enclosure.Animals.Add(animal);\n            return animal;\n        }\n\n        public static Enclosure WithSchedule(this Enclosure enclosure, Action<Schedule> configurator = null)\n        {\n            enclosure.WeeklySchedule = new Schedule();\n            configurator?.Invoke(enclosure.WeeklySchedule);\n            return enclosure;\n        }\n\n        public static Employee WithManager(this Employee employee, Employee manager)\n        {\n            employee.Manager = manager;\n            manager.DirectReports.Add(employee);\n            return employee;\n        }\n\n        public static Schedule WithApprover(this Schedule schedule, Employee manager)\n        {\n            schedule.Approver = manager;\n            return schedule;\n        }\n\n        public static Schedule WithAssignment(this Schedule schedule, ZooAssignment zooAssignment)\n        {\n            schedule.Assignments.Add(zooAssignment);\n            return schedule;\n        }\n\n        public static Schedule WithAssignment(\n            this Schedule schedule,\n            TimeSpan offset,\n            Employee assignee,\n            ZooTask assignedTask)\n            => schedule.WithAssignment(new ZooAssignment\n            {\n                Offset = offset,\n                Assignee = assignee,\n                Task = assignedTask\n            });\n    }\n\n    public class ZooEntityFixture\n    {\n        static ZooEntityFixture()\n        {\n            EntityFrameworkConventionPack.Register(type => true);\n        }\n\n        public ZooEntities Entities => new ZooEntities();\n    }\n\n    public class ZooEntities\n    {\n        public ZooEntities()\n        {\n            ManAgier = new Employee\n            {\n                FirstName = \"Man\",\n                LastName = \"A'Gier\",\n                Age = 58.4M,\n                Specialties =\n                {\n                    // those who can't zoo, manage!\n                }\n            };\n\n            TaigaMasuta = new Employee\n                {\n                    FirstName = \"Taiga\",\n                    LastName = \"Masuta\",\n                    Age = 31.7M,\n                    Specialties =\n                    {\n                        new Specialty {AnimalType = nameof(Tiger), Task = ZooTask.Feeding},\n                        new Specialty {AnimalType = nameof(Tiger), Task = ZooTask.Exercise},\n                        new Specialty {AnimalType = nameof(Tiger), Task = ZooTask.Training}\n                    }\n                }\n                .WithManager(ManAgier);\n\n            OttoVonEssenmacher = new Employee\n                {\n                    FirstName = \"Otto\",\n                    LastName = \"von Essenmacher\",\n                    Age = 22.1M,\n                    Specialties =\n                    {\n                        new Specialty {AnimalType = nameof(Otter), Task = ZooTask.Feeding},\n                        new Specialty {AnimalType = nameof(Otter), Task = ZooTask.Exercise}\n                    }\n                }\n                .WithManager(ManAgier);\n\n            BearOCreary = new Employee\n                {\n                    FirstName = \"Bear\",\n                    LastName = \"O'Creary\",\n                    Age = 41.4M,\n                    Specialties =\n                    {\n                        new Specialty {AnimalType = nameof(PolarBear), Task = ZooTask.Feeding},\n                        new Specialty {AnimalType = nameof(PolarBear), Task = ZooTask.Training}\n                    }\n                }\n                .WithManager(ManAgier);\n\n            TurGuidry = new Employee\n                {\n                    FirstName = \"Tur\",\n                    LastName = \"Guidry\",\n                    Age = 36.7M,\n                    Specialties =\n                    {\n                        new Specialty {AnimalType = nameof(Tiger), Task = ZooTask.TourGuide},\n                        new Specialty {AnimalType = nameof(Otter), Task = ZooTask.TourGuide},\n                        new Specialty {AnimalType = nameof(PolarBear), Task = ZooTask.TourGuide}\n                    }\n                }\n                .WithManager(ManAgier);\n\n            TigerEnclosure = new Enclosure\n                {\n                    AnimalEnclosureType = nameof(Tiger),\n                    Name = \"Tiger Pen\"\n                }\n                .WithSchedule(schedule =>\n                    schedule\n                        .WithApprover(ManAgier)\n                        .WithAssignment(TimeSpan.FromHours(1), TaigaMasuta, ZooTask.Feeding)\n                        .WithAssignment(TimeSpan.FromHours(3), TaigaMasuta, ZooTask.Training)\n                        .WithAssignment(TimeSpan.FromHours(4), TurGuidry, ZooTask.TourGuide)\n                        .WithAssignment(TimeSpan.FromHours(7), TaigaMasuta, ZooTask.Feeding));\n\n            OtterEnclosure = new Enclosure\n                {\n                    AnimalEnclosureType = nameof(Otter),\n                    Name = \"Otter Tank\"\n                }\n                .WithSchedule(schedule =>\n                    schedule\n                        .WithApprover(ManAgier)\n                        .WithAssignment(TimeSpan.FromHours(1), OttoVonEssenmacher, ZooTask.Feeding)\n                        .WithAssignment(TimeSpan.FromHours(3), OttoVonEssenmacher, ZooTask.Exercise)\n                        .WithAssignment(TimeSpan.FromHours(6), TurGuidry, ZooTask.TourGuide)\n                        .WithAssignment(TimeSpan.FromHours(7), OttoVonEssenmacher, ZooTask.Feeding));\n\n            PolarBearEnclosure = new Enclosure\n                {\n                    AnimalEnclosureType = nameof(PolarBear),\n                    Name = \"Igloo\"\n                }\n                .WithSchedule(schedule =>\n                    schedule\n                        .WithApprover(ManAgier)\n                        .WithAssignment(TimeSpan.FromHours(1), BearOCreary, ZooTask.Feeding)\n                        .WithAssignment(TimeSpan.FromHours(3), BearOCreary, ZooTask.Training)\n                        .WithAssignment(TimeSpan.FromHours(5), TurGuidry, ZooTask.TourGuide)\n                        .WithAssignment(TimeSpan.FromHours(7), BearOCreary, ZooTask.Feeding));\n\n            Tigger = new Tiger\n                {\n                    Name = \"Tigger\",\n                    Age = 6.4M,\n                    Weight = 270,\n                    Height = .98M\n                }\n                .WithEnclosure(TigerEnclosure);\n\n            Ursus = new PolarBear\n                {\n                    Name = \"Ursus\",\n                    Age = 4.9M,\n                    Weight = 612,\n                    Height = 2.7M\n                }\n                .WithEnclosure(PolarBearEnclosure);\n\n            Hydron = new SeaOtter\n                {\n                    Name = \"Hydron\",\n                    Age = 1.8M,\n                    Weight = 19,\n                    Height = .3M\n                }\n                .WithEnclosure(OtterEnclosure);\n\n            Yuri = new EurasianOtter\n                {\n                    Name = \"Yuri\",\n                    Age = 1.8M,\n                    Weight = 19,\n                    Height = .3M\n                }\n                .WithEnclosure(OtterEnclosure);\n\n            Animals = new Animal[]\n                {\n                    Tigger,\n                    Ursus,\n                    Hydron,\n                    Yuri\n                }\n                .OrderBy(animal => animal.Name)\n                .ThenBy(animal => animal.Height)\n                .ToList();\n\n            Enclosures = new[]\n                {\n                    TigerEnclosure,\n                    PolarBearEnclosure,\n                    OtterEnclosure\n                }\n                .OrderBy(enclosure => enclosure.AnimalEnclosureType)\n                .ThenBy(enclosure => enclosure.Name)\n                .ToList();\n\n            Employees = new[]\n                {\n                    TaigaMasuta,\n                    BearOCreary,\n                    OttoVonEssenmacher,\n                    TurGuidry,\n                    ManAgier\n                }\n                .OrderBy(employee => employee.FullName)\n                .ToList();\n\n            Entities = Animals\n                .Cast<object>()\n                .Concat(Enclosures)\n                .Concat(Employees)\n                .ToList();\n        }\n\n        public Employee TaigaMasuta { get; }\n\n        public Employee OttoVonEssenmacher { get; }\n\n        public Employee BearOCreary { get; }\n\n        public Employee TurGuidry { get; }\n\n        public Employee ManAgier { get; }\n\n        public Enclosure TigerEnclosure { get; }\n\n        public Enclosure OtterEnclosure { get; }\n\n        public Enclosure PolarBearEnclosure { get; }\n\n        public Tiger Tigger { get; }\n\n        public PolarBear Ursus { get; }\n\n        public SeaOtter Hydron { get; }\n\n        public EurasianOtter Yuri { get; }\n\n        public ICollection<Animal> Animals { get; }\n\n        public ICollection<Enclosure> Enclosures { get; }\n\n        public ICollection<Employee> Employees { get; }\n\n        public ICollection<object> Entities { get; }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.EntityFrameworkCore.MongoDB.SampleDomain/_Comparers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\n{\n    public class AnimalComparer : IComparer<Animal>\n    {\n        public int Compare(Animal x, Animal y)\n            => x?.GetType() == y?.GetType()\n                ? Comparer<string>.Default.Compare(x?.Name, y?.Name)\n                : Comparer<string>.Default.Compare(x?.GetType().Name, y?.GetType().Name);\n    }\n\n    public abstract class BaseEqualityComparer<T> : EqualityComparer<T>\n    {\n        public override int GetHashCode(T obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n\n        public sealed override bool Equals(T item1, T item2)\n            => (item1 == null && item2 == null)\n               || (item1 != null && item2 != null\n                   && MemberwiseEquals(item1, item2));\n\n        protected abstract bool MemberwiseEquals(T item1, T item2);\n    }\n\n    public static class EqualityComparerExtensions\n    {\n        public static bool CompareCollections<T>(\n            this EqualityComparer<T> equalityComparer,\n            ICollection<T> collection1,\n            ICollection<T> collection2)\n            => collection1.Count == collection2.Count\n               && collection1.All(item1 => collection2.Contains(item1, equalityComparer))\n               && collection2.All(item2 => collection1.Contains(item2, equalityComparer));\n    }\n\n    public class EmployeeEqualityComparer : BaseEqualityComparer<Employee>\n    {\n        private readonly SpecialtyEqualityComparer _specialtyEqualityComparer = new SpecialtyEqualityComparer();\n\n        private EmployeeEqualityComparer _managerEqualityComparer;\n\n        private EmployeeEqualityComparer _directReportsEqualityComparer;\n\n        public EmployeeEqualityComparer WithDirectReportsComparer(Action<EmployeeEqualityComparer> configurator = null)\n        {\n            _directReportsEqualityComparer = new EmployeeEqualityComparer();\n            configurator?.Invoke(_directReportsEqualityComparer);\n            return this;\n        }\n\n        public EmployeeEqualityComparer WithManagerComparer(Action<EmployeeEqualityComparer> configurator = null)\n        {\n            _managerEqualityComparer = new EmployeeEqualityComparer();\n            configurator?.Invoke(_managerEqualityComparer);\n            return this;\n        }\n\n        protected override bool MemberwiseEquals(Employee employee1, Employee employee2)\n            => Equals(employee1.EmployeeId, employee2.EmployeeId)\n               && string.Equals(employee1.FirstName, employee2.FirstName, StringComparison.Ordinal)\n               && string.Equals(employee1.LastName, employee2.LastName, StringComparison.Ordinal)\n               && employee1.Age == employee2.Age\n               && (_specialtyEqualityComparer?.CompareCollections(employee1.Specialties, employee2.Specialties) ?? true)\n               && (_managerEqualityComparer?.Equals(employee1.Manager, employee2.Manager) ?? true)\n               && (_directReportsEqualityComparer?.CompareCollections(employee1.DirectReports, employee2.DirectReports) ?? true);\n    }\n\n    public class SpecialtyEqualityComparer : BaseEqualityComparer<Specialty>\n    {\n        protected override bool MemberwiseEquals(Specialty specialty1, Specialty specialty2)\n            => string.Equals(specialty1.AnimalType, specialty2.AnimalType, StringComparison.Ordinal)\n               && specialty1.Task == specialty2.Task;\n    }\n\n    public class AnimalEqualityComparer : BaseEqualityComparer<Animal>\n    {\n        private EnclosureEqualityComparer _enclosureEqualityComparer;\n\n        protected override bool MemberwiseEquals(Animal animal1, Animal animal2)\n            => Equals(animal1.AnimalId, animal2.AnimalId)\n               && animal1.GetType() == animal2.GetType()\n               && string.Equals(animal1.Name, animal2.Name, StringComparison.Ordinal)\n               && animal1.Age == animal2.Age\n               && animal1.Height == animal2.Height\n               && animal1.Weight == animal2.Weight\n               && Equals(animal1.Enclosure?.EnclosureId, animal2.Enclosure?.EnclosureId)\n               && (_enclosureEqualityComparer?.Equals(animal1.Enclosure, animal2.Enclosure) ?? true);\n\n        public AnimalEqualityComparer WithEnclosureEqualityComparer(Action<EnclosureEqualityComparer> configurator = null)\n        {\n            _enclosureEqualityComparer = new EnclosureEqualityComparer();\n            configurator?.Invoke(_enclosureEqualityComparer);\n            return this;\n        }\n    }\n\n    public class EnclosureEqualityComparer : BaseEqualityComparer<Enclosure>\n    {\n        private AnimalEqualityComparer _animalEqualityComparer = null;\n        private readonly ScheduleEqualityComparer _scheduleEqualityComparer\n            = new ScheduleEqualityComparer();\n\n        protected override bool MemberwiseEquals(Enclosure enclosure1, Enclosure enclosure2)\n            => Equals(enclosure1.EnclosureId, enclosure2.EnclosureId)\n               && string.Equals(enclosure1.Name, enclosure2.Name, StringComparison.Ordinal)\n               && string.Equals(enclosure1.AnimalEnclosureType, enclosure2.AnimalEnclosureType, StringComparison.Ordinal)\n               && (_animalEqualityComparer?.CompareCollections(enclosure1.Animals, enclosure2.Animals) ?? true)\n               && (_scheduleEqualityComparer?.Equals(enclosure1.WeeklySchedule, enclosure2.WeeklySchedule) ?? true);\n\n        public EnclosureEqualityComparer WithAnimalEqualityComparer(Action<AnimalEqualityComparer> configurator = null)\n        {\n            _animalEqualityComparer = new AnimalEqualityComparer();\n            configurator?.Invoke(_animalEqualityComparer);\n            return this;\n        }\n\n        public EnclosureEqualityComparer ConfigureWeeklyScheduleEqualityComparer(\n            Action<ScheduleEqualityComparer> configurator)\n        {\n            configurator.Invoke(_scheduleEqualityComparer);\n            return this;\n        }\n    }\n\n    public class ScheduleEqualityComparer : BaseEqualityComparer<Schedule>\n    {\n        private readonly ZooAssignmentEqualityComparer _zooAssignmentEqualityComparer\n            = new ZooAssignmentEqualityComparer();\n\n        private EmployeeEqualityComparer _approverEqualityComparer;\n\n        protected override bool MemberwiseEquals(Schedule schedule1, Schedule schedule2)\n            => (_approverEqualityComparer?.Equals(schedule1.Approver, schedule2.Approver) ?? true)\n                && _zooAssignmentEqualityComparer.CompareCollections(schedule1.Assignments, schedule2.Assignments);\n\n        public ScheduleEqualityComparer WithApproverEqualityComparer(\n            Action<EmployeeEqualityComparer> configurator = null)\n        {\n            _approverEqualityComparer = new EmployeeEqualityComparer();\n            configurator?.Invoke(_approverEqualityComparer);\n            return this;\n        }\n\n        public ScheduleEqualityComparer ConfigureZooAssignmentEqualityComparer(\n            Action<ZooAssignmentEqualityComparer> configurator)\n        {\n            configurator.Invoke(_zooAssignmentEqualityComparer);\n            return this;\n        }\n    }\n\n    public class ZooAssignmentEqualityComparer : BaseEqualityComparer<ZooAssignment>\n    {\n        private EmployeeEqualityComparer _employeeEqualityComparer;\n\n        protected override bool MemberwiseEquals(ZooAssignment zooAssignment1, ZooAssignment zooAssignment2)\n            => Equals(zooAssignment1.Offset, zooAssignment2.Offset)\n               && Equals(zooAssignment1.Task, zooAssignment2.Task)\n               && (_employeeEqualityComparer?.Equals(zooAssignment1.Assignee, zooAssignment2.Assignee) ?? true);\n\n        public ZooAssignmentEqualityComparer WithEmployeeEqualityComparer()\n        {\n            _employeeEqualityComparer = new EmployeeEqualityComparer();\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/Blueshift.Identity.MongoDB.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(BuildFrameworks)</TargetFrameworks>\n    <Product>Blueshift MongoDB EntityFrameworkCore Identity Provider for Microsoft ASP.NET Core</Product>\n    <Description>Blueshift Software MongoDB EntityFrameworkCore Identity Provider for Microsoft ASP.NET Core</Description>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <PackageTags>$(PackageTags);AspNetCore;Identity;Membership</PackageTags>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\Shared\\Check.cs\" Link=\"Shared\\Check.cs\" />\n    <Compile Include=\"..\\Shared\\CodeAnnotations.cs\" Link=\"Shared\\CodeAnnotations.cs\" />\n    <Compile Include=\"..\\Shared\\MemberInfoExtensions.cs\" Link=\"Shared\\MemberInfoExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\PropertyInfoExtensions.cs\" Link=\"Shared\\PropertyInfoExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\SharedTypeExtensions.cs\" Link=\"Shared\\SharedTypeExtensions.cs\" />\n    <Compile Include=\"..\\Shared\\StringBuilderExtensions.cs\" Link=\"Shared\\StringBuilderExtensions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Blueshift.EntityFrameworkCore.MongoDB\\Blueshift.EntityFrameworkCore.MongoDB.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Folder Include=\"Shared\\\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.AspNetCore.Identity\" Version=\"$(MicrosoftAspNetCoreIdentityPackageVersion)\" NoWarn=\"KRB4002\" />\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/DependencyInjection/IdentityEntityFrameworkMongoDbBuilderExtensions.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Blueshift.Identity.MongoDB;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\n// ReSharper disable once CheckNamespace\nnamespace Microsoft.Extensions.DependencyInjection\n{\n    /// <summary>\n    ///     Provides extension methods to <see cref=\"IdentityBuilder\"/> for adding MongoDB for EntityFramework stores.\n    /// </summary>\n    public static class IdentityEntityFrameworkMongoDbBuilderExtensions\n    {\n        private static readonly Type BaseUserType = typeof(MongoDbIdentityUser<,,,,>);\n        private static readonly Type BaseRoleType = typeof(MongoDbIdentityRole<,>);\n        private static readonly Type BaseStoreType = typeof(MongoDbUserStore<,,,,,,,>);\n\n        /// <summary>\n        /// Adds a MongoDB for Entity Framework implementation of identity information stores.\n        /// </summary>\n        /// <typeparam name=\"TContext\">The Entity Framework database context to use.</typeparam>\n        /// <param name=\"builder\">The <see cref=\"IdentityBuilder\"/> instance this method extends.</param>\n        /// <returns>The <see cref=\"IdentityBuilder\"/> instance this method extends.</returns>\n        public static IdentityBuilder AddEntityFrameworkMongoDbStores<TContext>(this IdentityBuilder builder)\n            where TContext : DbContext\n        {\n            AddMongoDbStores(builder.Services, builder.UserType, builder.RoleType, typeof(TContext));\n            return builder;\n        }\n\n        /// <summary>\n        /// Adds a default MongoDB for Entity Framework implementation of identity information stores.\n        /// </summary>\n        /// <typeparam name=\"TContext\">The Entity Framework database context to use.</typeparam>\n        /// <typeparam name=\"TKey\">The type of the primary key used for the users and roles.</typeparam>\n        /// <param name=\"builder\">The <see cref=\"IdentityBuilder\"/> instance this method extends.</param>\n        /// <returns>The <see cref=\"IdentityBuilder\"/> instance this method extends.</returns>\n        public static IdentityBuilder AddEntityFrameworkDbStores<TContext, TKey>(this IdentityBuilder builder)\n            where TContext : DbContext\n            where TKey : IEquatable<TKey>\n        {\n            AddMongoDbStores(builder.Services, builder.UserType, builder.RoleType, typeof(TContext), typeof(TKey));\n            return builder;\n        }\n\n        private static void AddMongoDbStores(IServiceCollection services, Type userType, Type roleType, Type contextType, Type keyType = null)\n        {\n            TypeInfo identityUserType = FindGenericBaseType(userType, BaseUserType);\n            if (identityUserType == null)\n            {\n                throw new InvalidOperationException($\"User type does not derive from {BaseUserType.FullName}.\");\n            }\n            TypeInfo identityRoleType = FindGenericBaseType(roleType, BaseRoleType);\n            if (identityRoleType == null)\n            {\n                throw new InvalidOperationException($\"Role type does not derive from {BaseRoleType.FullName}.\");\n            }\n\n            Type userStoreType = BaseStoreType\n                    .MakeGenericType(\n                        userType,\n                        roleType,\n                        contextType,\n                        keyType ?? identityUserType.GenericTypeArguments[0],\n                        identityUserType.GenericTypeArguments[1], //TClaim\n                        identityUserType.GenericTypeArguments[2], //TUserRole\n                        identityUserType.GenericTypeArguments[3], //TUserLogin\n                        identityUserType.GenericTypeArguments[4]); //TUserToken\n            Type roleStoreType = typeof(MongoDbRoleStore<,,,>)\n                    .MakeGenericType(\n                        roleType,\n                        contextType,\n                        keyType ?? identityUserType.GenericTypeArguments[0],\n                        identityRoleType.GenericTypeArguments[1]); //TClaim\n\n            object GetUserStore(IServiceProvider provider) => provider.GetRequiredService(userStoreType);\n            object GetRoleStore(IServiceProvider provider) => provider.GetRequiredService(roleStoreType);\n\n            services.TryAddScoped(userStoreType);\n            services.TryAddScoped(typeof(IQueryableUserStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserAuthenticationTokenStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserAuthenticatorKeyStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserClaimStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserEmailStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserLoginStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserLockoutStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserPasswordStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserRoleStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserPhoneNumberStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserSecurityStampStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserTwoFactorStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserTwoFactorRecoveryCodeStore<>).MakeGenericType(userType), GetUserStore);\n            services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(userType), GetUserStore);\n\n            services.TryAddScoped(roleStoreType);\n            services.TryAddScoped(typeof(IQueryableRoleStore<>).MakeGenericType(roleType), GetRoleStore);\n            services.TryAddScoped(typeof(IRoleClaimStore<>).MakeGenericType(roleType), GetRoleStore);\n            services.TryAddScoped(typeof(IRoleStore<>).MakeGenericType(roleType), GetRoleStore);\n        }\n\n        private static TypeInfo FindGenericBaseType(Type currentType, Type genericBaseType)\n        {\n            var type = currentType.GetTypeInfo();\n            while (type != null)\n            {\n                type = type.GetTypeInfo();\n                var genericType = type.IsGenericType ? type.GetGenericTypeDefinition() : null;\n                if (genericType != null && genericType == genericBaseType)\n                {\n                    return type;\n                }\n\n                type = type.BaseType.GetTypeInfo();\n            }\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/IdentityMongoDbContext.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Microsoft.EntityFrameworkCore;\nusing MongoDB.Bson;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Base class for the Entity Framework MongoDB database context used for identity.\n    /// </summary>\n    [MongoDatabase(\"__identities\")]\n    public class IdentityMongoDbContext\n        : IdentityMongoDbContext<MongoDbIdentityUser, MongoDbIdentityRole>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        public IdentityMongoDbContext(DbContextOptions<IdentityMongoDbContext> options)\n            : base(options)\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"IdentityMongoDbContext\"/>.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"DbContext\"/>.</param>\n        protected IdentityMongoDbContext(DbContextOptions options)\n            : base(options) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdentityMongoDbContext\" /> class.\n        /// </summary>\n        protected IdentityMongoDbContext() { }\n    }\n\n    /// <summary>\n    /// Base class for the Entity Framework MongoDB database context used for identity.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the primary key for users and roles.</typeparam>\n    [MongoDatabase(\"__identities\")]\n    public class IdentityMongoDbContext<TKey>\n        : IdentityMongoDbContext<\n            MongoDbIdentityUser<TKey>,\n            MongoDbIdentityRole<TKey>,\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"IdentityMongoDbContext{TKey}\"/>.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"DbContext\"/>.</param>\n        public IdentityMongoDbContext(DbContextOptions<IdentityMongoDbContext<TKey>> options)\n            : base(options)\n        { }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"IdentityMongoDbContext{TKey}\"/>.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"DbContext\"/>.</param>\n        protected IdentityMongoDbContext(DbContextOptions options)\n            : base(options) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdentityMongoDbContext{TKey}\" /> class.\n        /// </summary>\n        protected IdentityMongoDbContext() { }\n    }\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Base class for the Entity Framework MongoDB database context used for identity.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of user objects.</typeparam>\n    /// <typeparam name=\"TRole\">The type of role objects.</typeparam>\n    [MongoDatabase(\"__identities\")]\n    public class IdentityMongoDbContext<TUser, TRole>\n        : IdentityMongoDbContext<TUser, TRole, ObjectId>\n        where TUser : MongoDbIdentityUser<ObjectId>\n        where TRole : MongoDbIdentityRole<ObjectId>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`2\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        public IdentityMongoDbContext(DbContextOptions<IdentityMongoDbContext<TUser, TRole>> options) \n            : base(options)\n        { }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`2\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        protected IdentityMongoDbContext(DbContextOptions options)\n            : base(options) { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"IdentityMongoDbContext{TUser, TRole}\" /> class.\n        /// </summary>\n        protected IdentityMongoDbContext() { }\n    }\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Base class for the Entity Framework MongoDB database context used for identity.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of user objects.</typeparam>\n    /// <typeparam name=\"TRole\">The type of role objects.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the primary key for users and roles.</typeparam>\n    [MongoDatabase(\"__identities\")]\n    public class IdentityMongoDbContext<TUser, TRole, TKey>\n        : IdentityMongoDbContext<\n            TUser,\n            TRole,\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TUser : MongoDbIdentityUser<\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TRole : MongoDbIdentityRole<\n            TKey,\n            MongoDbIdentityClaim>\n        where TKey : IEquatable<TKey>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`3\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        public IdentityMongoDbContext(DbContextOptions<IdentityMongoDbContext<TUser, TRole, TKey>> options)\n            : base(options)\n        { }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`3\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        protected IdentityMongoDbContext(DbContextOptions options)\n            : base(options) { }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`3\" /> class.\n        /// </summary>\n        protected IdentityMongoDbContext() { }\n    }\n\n    /// <inheritdoc />\n    /// <summary>\n    /// Base class for the Entity Framework MongoDB database context used for identity.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of user objects.</typeparam>\n    /// <typeparam name=\"TRole\">The type of role objects.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the primary key for users and roles.</typeparam>\n    /// <typeparam name=\"TClaim\">The type of the role claim object.</typeparam>\n    /// <typeparam name=\"TUserRole\">The type of the user role object.</typeparam>\n    /// <typeparam name=\"TUserLogin\">The type of the user login object.</typeparam>\n    /// <typeparam name=\"TUserToken\">The type of the user token object.</typeparam>\n    [MongoDatabase(\"__identities\")]\n    public class IdentityMongoDbContext<TUser, TRole, TKey, TClaim, TUserRole, TUserLogin, TUserToken> : DbContext\n        where TUser : MongoDbIdentityUser<TKey, TClaim, TUserRole, TUserLogin, TUserToken>\n        where TRole : MongoDbIdentityRole<TKey, TClaim>\n        where TKey : IEquatable<TKey>\n        where TClaim : MongoDbIdentityClaim\n        where TUserRole : MongoDbIdentityUserRole\n        where TUserLogin : MongoDbIdentityUserLogin<TUserToken>\n        where TUserToken : MongoDbIdentityUserToken\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`7\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        public IdentityMongoDbContext(DbContextOptions<IdentityMongoDbContext<TUser, TRole, TKey, TClaim, TUserRole, TUserLogin, TUserToken>> options)\n            : base(options) { }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`7\" />.\n        /// </summary>\n        /// <param name=\"options\">The options to be used by a <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        protected IdentityMongoDbContext(DbContextOptions options)\n            : base(options) { }\n\n        /// <inheritdoc />\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:Blueshift.Identity.MongoDB.IdentityMongoDbContext`7\" /> class.\n        /// </summary>\n        protected IdentityMongoDbContext() { }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"DbSet{TUser}\"/> used to store user documents.\n        /// </summary>\n        public DbSet<TUser> Users { get; set; }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"DbSet{TEntity}\"/> of roles.\n        /// </summary>\n        public DbSet<TRole> Roles { get; set; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityClaim.cs",
    "content": "﻿using System.Security.Claims;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of an authorization claim for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [Owned]\n    public class MongoDbIdentityClaim\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityClaim\"/> class.\n        /// </summary>\n        public MongoDbIdentityClaim() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityClaim\"/> class.\n        /// </summary>\n        /// <param name=\"claim\">The security <see cref=\"Claim\"/> to use to initialize this role claim.</param>\n        public MongoDbIdentityClaim(Claim claim)\n        {\n            InitializeFromClaim(claim);\n        }\n\n        /// <summary>\n        /// Gets or sets the claim type for this claim.\n        /// </summary>\n        public virtual string ClaimType { get; set; }\n\n        /// <summary>\n        /// Gets or sets the claim value for this claim.\n        /// </summary>\n        public virtual string ClaimValue { get; set; }\n\n        /// <summary>\n        /// Constructs a new claim with the type and value.\n        /// </summary>\n        /// <returns>A <see cref=\"Claim\"/> that represents this <see cref=\"MongoDbIdentityClaim\"/>.</returns>\n        public virtual Claim ToClaim()\n            => new Claim(ClaimType, ClaimValue);\n\n        /// <summary>\n        /// Initializes this <see cref=\"MongoDbIdentityClaim\"/> with values from the given <see cref=\"Claim\"/>.\n        /// </summary>\n        /// <param name=\"claim\">The source <see cref=\"Claim\"/> to use for initialization.</param>\n        public virtual void InitializeFromClaim(Claim claim)\n        {\n            Check.NotNull(claim, nameof(claim));\n            ClaimType = claim.Type;\n            ClaimValue = claim.Value;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityRole.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of an authorization role for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [MongoCollection(\"roles\")]\n    public class MongoDbIdentityRole\n        : MongoDbIdentityRole<ObjectId>\n    {\n    }\n\n    /// <summary>\n    /// A representation of an authorization role for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the role's identifier.</typeparam>\n    [MongoCollection(\"roles\")]\n    public class MongoDbIdentityRole<TKey>\n        : MongoDbIdentityRole<TKey, MongoDbIdentityClaim>\n        where TKey : IEquatable<TKey>\n    {\n    }\n\n    /// <summary>\n    /// A representation of an authorization role for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the role's identifier.</typeparam>\n    /// <typeparam name=\"TClaim\">The type of authorization claims assigned to this role.</typeparam>\n    [MongoCollection(\"roles\")]\n    public class MongoDbIdentityRole<TKey, TClaim>\n        where TKey : IEquatable<TKey>\n        where TClaim : MongoDbIdentityClaim\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityRole{TKey, TClaim}\"/> class.\n        /// </summary>\n        public MongoDbIdentityRole() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityRole{TKey, TClaim}\"/> class.\n        /// </summary>\n        /// <param name=\"roleName\">The name of the role.</param>\n        public MongoDbIdentityRole(string roleName)\n        {\n            RoleName = Check.NotNull(roleName, nameof(roleName));\n        }\n\n        /// <summary>\n        /// A collection of the security claims assigned to this role.\n        /// </summary>\n        public virtual ICollection<TClaim> Claims { get; [UsedImplicitly] private set; } = new List<TClaim>();\n\n        /// <summary>\n        /// Gets or sets the primary key for this role.\n        /// </summary>\n        [BsonId, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n        public virtual TKey Id { get; [UsedImplicitly] private set; }\n\n        /// <summary>\n        /// Gets or sets the name for this role.\n        /// </summary>\n        public virtual string RoleName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the normalized name for this role.\n        /// </summary>\n        public virtual string NormalizedRoleName { get; set; }\n\n        /// <summary>\n        /// A random value that should change whenever a role is persisted to the store.\n        /// </summary>\n        [ConcurrencyCheck]\n        public virtual string ConcurrencyStamp { get; set; }\n\n        /// <summary>\n        /// Returns the name of this <see cref=\"MongoDbIdentityRole{TKey, TClaim}\"/>.\n        /// </summary>\n        /// <returns>The name of this role.</returns>\n        public override string ToString() => RoleName;\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityUser.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel.DataAnnotations;\nusing System.ComponentModel.DataAnnotations.Schema;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing JetBrains.Annotations;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of a user security principal for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [MongoCollection(\"users\")]\n    public class MongoDbIdentityUser : MongoDbIdentityUser<ObjectId>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser\"/>.\n        /// </summary>\n        public MongoDbIdentityUser() { }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser\"/>.\n        /// </summary>\n        /// <param name=\"userName\">The user name.</param>\n        public MongoDbIdentityUser(string userName) : base(userName) { }\n    }\n\n    /// <summary>\n    /// A representation of a user security principal for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the primary key for this object.</typeparam>\n    [MongoCollection(\"users\")]\n    public class MongoDbIdentityUser<TKey>\n        : MongoDbIdentityUser<\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser{TKey}\"/>.\n        /// </summary>\n        public MongoDbIdentityUser() { }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser{TKey}\"/>.\n        /// </summary>\n        /// <param name=\"userName\">The user name.</param>\n        public MongoDbIdentityUser(string userName) : base(userName) { }\n    }\n\n    /// <summary>\n    /// A representation of a user security principal for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the primary key for this object.</typeparam>\n    /// <typeparam name=\"TClaim\">The type of security claims assigned to this user.</typeparam>\n    /// <typeparam name=\"TUserRole\">The type security roles assigned to this user.</typeparam>\n    /// <typeparam name=\"TUserLogin\">The type of external login provider information assigned to this user.</typeparam>\n    /// <typeparam name=\"TUserToken\">The type of external login provider tokens assigned to this user.</typeparam>\n    [MongoCollection(\"users\")]\n    public class MongoDbIdentityUser<TKey, TClaim, TUserRole, TUserLogin, TUserToken>\n        where TKey : IEquatable<TKey>\n        where TClaim : MongoDbIdentityClaim\n        where TUserRole : MongoDbIdentityUserRole\n        where TUserLogin : MongoDbIdentityUserLogin<TUserToken>\n        where TUserToken : MongoDbIdentityUserToken\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser{TKey, TUserClaim, TUserRole, TUserLogin, TUserToken}\"/>.\n        /// </summary>\n        public MongoDbIdentityUser() { }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MongoDbIdentityUser{TKey, TUserClaim, TUserRole, TUserLogin, TUserToken}\"/>.\n        /// </summary>\n        /// <param name=\"userName\">The user name.</param>\n        public MongoDbIdentityUser(string userName)\n            : this()\n        {\n            UserName = userName;\n        }\n\n        /// <summary>\n        /// Gets or sets the primary key for this user.\n        /// </summary>\n        [BsonId, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n        public virtual TKey Id { get; [UsedImplicitly] private set; }\n\n        /// <summary>\n        /// Gets or sets the user name for this user.\n        /// </summary>\n        public virtual string UserName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the normalized user name for this user.\n        /// </summary>\n        public virtual string NormalizedUserName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the email address for this user.\n        /// </summary>\n        public virtual string Email { get; set; }\n\n        /// <summary>\n        /// Gets or sets the normalized email address for this user.\n        /// </summary>\n        public virtual string NormalizedEmail { get; set; }\n\n        /// <summary>\n        /// Gets or sets a flag indicating if a user has confirmed their email address.\n        /// </summary>\n        /// <value>True if the email address has been confirmed, otherwise false.</value>\n        public virtual bool EmailConfirmed { get; set; }\n\n        /// <summary>\n        /// Gets or sets a salted and hashed representation of the password for this user.\n        /// </summary>\n        public virtual string PasswordHash { get; set; }\n\n        /// <summary>\n        /// A random value that must change whenever a users credentials change (password changed, login removed)\n        /// </summary>\n        public virtual string SecurityStamp { get; set; }\n\n        /// <summary>\n        /// A random value that must change whenever a user is persisted to the store\n        /// </summary>\n        [ConcurrencyCheck]\n        public virtual string ConcurrencyStamp { get; set; }\n\n        /// <summary>\n        /// Gets or sets a telephone number for the user.\n        /// </summary>\n        public virtual string PhoneNumber { get; set; }\n\n        /// <summary>\n        /// Gets or sets a flag indicating if a user has confirmed their telephone address.\n        /// </summary>\n        /// <value>True if the telephone number has been confirmed, otherwise false.</value>\n        public virtual bool PhoneNumberConfirmed { get; set; }\n\n        /// <summary>\n        /// Gets or sets a flag indicating if two factor authentication is enabled for this user.\n        /// </summary>\n        /// <value>True if 2fa is enabled, otherwise false.</value>\n        public virtual bool TwoFactorEnabled { get; set; }\n\n        /// <summary>\n        /// Gets or sets the date and time, in UTC, when any user lockout ends.\n        /// </summary>\n        /// <remarks>\n        /// A value in the past means the user is not locked out.\n        /// </remarks>\n        public virtual DateTimeOffset? LockoutEnd { get; set; }\n\n        /// <summary>\n        /// Gets or sets a flag indicating if the user could be locked out.\n        /// </summary>\n        /// <value>True if the user could be locked out, otherwise false.</value>\n        public virtual bool LockoutEnabled { get; set; }\n\n        /// <summary>\n        /// Gets or sets the number of failed login attempts for the current user.\n        /// </summary>\n        public virtual int AccessFailedCount { get; set; }\n\n        /// <summary>\n        /// A collection of security roles assigned to this user.\n        /// </summary>\n        public virtual ICollection<TUserRole> Roles { get; [UsedImplicitly] private set; } = new List<TUserRole>();\n\n        /// <summary>\n        /// A collection of security claims assigned to this user.\n        /// </summary>\n        public virtual ICollection<TClaim> Claims { get; [UsedImplicitly] private set; } = new List<TClaim>();\n\n        /// <summary>\n        /// A collection of external login provider information assigned to this user.\n        /// </summary>\n        public virtual ICollection<TUserLogin> Logins { get; [UsedImplicitly] private set; } = new List<TUserLogin>();\n\n        /// <summary>\n        /// Returns the <see cref=\"UserName\"/> for this user.\n        /// </summary>\n        /// <returns>The username of this user.</returns>\n        public override string ToString() => UserName;\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityUserLogin.cs",
    "content": "﻿using System.Collections.Generic;\nusing JetBrains.Annotations;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Utilities;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of an external user login provider for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [Owned]\n    public class MongoDbIdentityUserLogin : MongoDbIdentityUserLogin<MongoDbIdentityUserToken>\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityUserLogin\"/> class.\n        /// </summary>\n        public MongoDbIdentityUserLogin() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityUserLogin\"/> class.\n        /// </summary>\n        /// <param name=\"userLoginInfo\">The <see cref=\"UserLoginInfo\"/> to use to initialize this user login.</param>\n        public MongoDbIdentityUserLogin(UserLoginInfo userLoginInfo)\n            : base(userLoginInfo)\n        {\n        }\n    }\n\n    /// <summary>\n    /// A representation of an external user login provider for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    /// <typeparam name=\"TUserToken\">The type of tokens assigned to this external login provider information.</typeparam>\n    [Owned]\n    public class MongoDbIdentityUserLogin<TUserToken>\n        where TUserToken : MongoDbIdentityUserToken\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityUserLogin\"/> class.\n        /// </summary>\n        public MongoDbIdentityUserLogin() { }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDbIdentityUserLogin\"/> class.\n        /// </summary>\n        /// <param name=\"userLoginInfo\">The <see cref=\"UserLoginInfo\"/> to use to initialize this user login.</param>\n        public MongoDbIdentityUserLogin(UserLoginInfo userLoginInfo)\n        {\n            InitializeFromUserLoginInfo(userLoginInfo);\n        }\n\n        /// <summary>\n        /// Gets or sets the external login provider, such as \"Facebook\" or \"Google\"..\n        /// </summary>\n        public virtual string LoginProvider { get; set; }\n\n        /// <summary>\n        /// Gets or sets a unique provider identifier for this login.\n        /// </summary>\n        public virtual string ProviderKey { get; set; }\n\n        /// <summary>\n        /// Gets or sets a friendly name for this login that can be displayed to a user.\n        /// </summary>\n        public virtual string ProviderDisplayName { get; set; }\n\n        /// <summary>\n        /// A collection of <typeparamref name=\"TUserToken\"/> assigned to this provider.\n        /// </summary>\n        public ICollection<TUserToken> UserTokens { get; [UsedImplicitly] private set; } = new List<TUserToken>();\n\n        /// <summary>\n        /// Constructs a new claim with the type and value.\n        /// </summary>\n        /// <returns>A <see cref=\"UserLoginInfo\"/> that represents this <see cref=\"MongoDbIdentityUserLogin{TUserToken}\"/>.</returns>\n        public virtual UserLoginInfo ToUserLoginInfo()\n            => new UserLoginInfo(LoginProvider, ProviderKey, ProviderDisplayName);\n\n        /// <summary>\n        /// Initializes this <see cref=\"MongoDbIdentityUserLogin{TUserToken}\"/> with values from the given <see cref=\"UserLoginInfo\"/>.\n        /// </summary>\n        /// <param name=\"userLoginInfo\">The source <see cref=\"UserLoginInfo\"/> to use for initialization.</param>\n        public virtual void InitializeFromUserLoginInfo(UserLoginInfo userLoginInfo)\n        {\n            Check.NotNull(userLoginInfo, nameof(userLoginInfo));\n            LoginProvider = userLoginInfo.LoginProvider;\n            ProviderKey = userLoginInfo.ProviderKey;\n            ProviderDisplayName = userLoginInfo.ProviderDisplayName;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityUserRole.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of a user's security authorization role for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [Owned]\n    public class MongoDbIdentityUserRole\n    {\n        /// <summary>\n        /// Gets or sets the name of the role that the user is in.\n        /// </summary>\n        public string RoleName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the normalized name of the role that the user is in.\n        /// </summary>\n        public string NormalizedRoleName { get; set; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbIdentityUserToken.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    /// A representation of an external user login provider token for use with a MongoDB EntityFramework provider.\n    /// </summary>\n    [Owned]\n    public class MongoDbIdentityUserToken\n    {\n        /// <summary>\n        /// Gets or sets the name of the token.\n        /// </summary>\n        public virtual string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the token value.\n        /// </summary>\n        public virtual string Value { get; set; }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbRoleStore.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Security.Claims;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <inheritdoc />\n    /// <summary>\n    /// Creates a new instance of a persistence store for roles.\n    /// </summary>\n    public class MongoDbRoleStore : MongoDbRoleStore<MongoDbIdentityRole, IdentityMongoDbContext>\n    {\n        /// <inheritdoc />\n        /// <summary>\n        /// Constructs a new instance of <see cref=\"T:Blueshift.Identity.MongoDB.MongoDbRoleStore\" />.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" />.</param>\n        /// <param name=\"describer\">The <see cref=\"T:Microsoft.AspNetCore.Identity.IdentityErrorDescriber\" />.</param>\n        public MongoDbRoleStore(IdentityMongoDbContext context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Creates a new instance of a persistence store for roles.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the primary key for a role.</typeparam>\n    public class MongoDbRoleStore<TKey> : MongoDbRoleStore<MongoDbIdentityRole<TKey>, IdentityMongoDbContext<TKey>, TKey>\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        /// Constructs a new instance of <see cref=\"MongoDbRoleStore{TKey}\"/>.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"IdentityMongoDbContext{TKey}\"/>.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\"/>.</param>\n        public MongoDbRoleStore(IdentityMongoDbContext<TKey> context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Creates a new instance of a persistence store for roles.\n    /// </summary>\n    /// <typeparam name=\"TRole\">The type of the class representing a role.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the data context class used to access the store.</typeparam>\n    public class MongoDbRoleStore<TRole, TContext>\n        : MongoDbRoleStore<TRole, TContext, ObjectId>\n        where TRole : MongoDbIdentityRole<ObjectId, MongoDbIdentityClaim>, new()\n        where TContext : DbContext\n    {\n        /// <summary>\n        /// Constructs a new instance of <see cref=\"MongoDbRoleStore{TRole, TContext, TKey, TClaim}\"/>.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"DbContext\"/>.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\"/>.</param>\n        public MongoDbRoleStore(TContext context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Creates a new instance of a persistence store for roles.\n    /// </summary>\n    /// <typeparam name=\"TRole\">The type of the class representing a role.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the data context class used to access the store.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the primary key for a role.</typeparam>\n    public class MongoDbRoleStore<TRole, TContext, TKey>\n        : MongoDbRoleStore<TRole, TContext, TKey, MongoDbIdentityClaim>\n        where TRole : MongoDbIdentityRole<TKey, MongoDbIdentityClaim>, new()\n        where TKey : IEquatable<TKey>\n        where TContext : DbContext\n    {\n        /// <summary>\n        /// Constructs a new instance of <see cref=\"MongoDbRoleStore{TRole, TContext, TKey, TClaim}\"/>.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"DbContext\"/>.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\"/>.</param>\n        public MongoDbRoleStore(TContext context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    /// Creates a new instance of a persistence store for roles.\n    /// </summary>\n    /// <typeparam name=\"TRole\">The type of the class representing a role.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the data context class used to access the store.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the primary key for a role.</typeparam>\n    /// <typeparam name=\"TClaim\">The type of the class representing a role claim.</typeparam>\n    public class MongoDbRoleStore<TRole, TContext, TKey, TClaim> :\n        IQueryableRoleStore<TRole>,\n        IRoleClaimStore<TRole>\n        where TRole : MongoDbIdentityRole<TKey, TClaim>, new()\n        where TKey : IEquatable<TKey>\n        where TContext : DbContext\n        where TClaim : MongoDbIdentityClaim, new()\n    {\n        private bool _disposed;\n\n        /// <summary>\n        /// Constructs a new instance of <see cref=\"MongoDbRoleStore{TRole, TContext, TKey, TClaim}\"/>.\n        /// </summary>\n        /// <param name=\"context\">The <see cref=\"DbContext\"/>.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\"/>.</param>\n        public MongoDbRoleStore(TContext context, IdentityErrorDescriber describer = null)\n        {\n            Context = Check.NotNull(context, nameof(context));\n            ErrorDescriber = describer ?? new IdentityErrorDescriber();\n        }\n\n        /// <summary>\n        /// Gets the database context for this store.\n        /// </summary>\n        public TContext Context { get; }\n\n        /// <summary>\n        /// Gets or sets the <see cref=\"IdentityErrorDescriber\"/> for any error that occurred with the current operation.\n        /// </summary>\n        public IdentityErrorDescriber ErrorDescriber { get; set; }\n\n        /// <summary>\n        /// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.\n        /// </summary>\n        /// <value>\n        /// True if changes should be automatically persisted, otherwise false.\n        /// </value>\n        public bool AutoSaveChanges { get; set; } = true;\n\n        /// <summary>\n        /// A navigation property for the roles the store contains.\n        /// </summary>\n        public virtual IQueryable<TRole> Roles => Context.Set<TRole>();\n\n        /// <summary>\n        /// Throws if this class has been disposed.\n        /// </summary>\n        protected void ThrowIfDisposed()\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(GetType().Name);\n            }\n        }\n\n        /// <summary>\n        /// Dispose the stores\n        /// </summary>\n        public void Dispose()\n        {\n            _disposed = true;\n        }\n\n        /// <summary>Saves the current store.</summary>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>The <see cref=\"Task\"/> that represents the asynchronous operation.</returns>\n        private async Task SaveChanges(CancellationToken cancellationToken)\n        {\n            if (AutoSaveChanges)\n            {\n                await Context.SaveChangesAsync(cancellationToken);\n            }\n        }\n\n        /// <summary>\n        /// Creates a new role in a store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role to create in the store.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that represents the <see cref=\"IdentityResult\"/> of the asynchronous query.</returns>\n        public virtual async Task<IdentityResult> CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Context.Add(Check.NotNull(role, nameof(role)));\n            await SaveChanges(cancellationToken);\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        /// Updates a role in a store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role to update in the store.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that represents the <see cref=\"IdentityResult\"/> of the asynchronous query.</returns>\n        public virtual async Task<IdentityResult> UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Context.Attach(Check.NotNull(role, nameof(role)));\n            role.ConcurrencyStamp = Guid.NewGuid().ToString();\n            Context.Update(role);\n            try\n            {\n                await SaveChanges(cancellationToken);\n            }\n            catch (DbUpdateConcurrencyException)\n            {\n                return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());\n            }\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        /// Deletes a role from the store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role to delete from the store.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that represents the <see cref=\"IdentityResult\"/> of the asynchronous query.</returns>\n        public virtual async Task<IdentityResult> DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Context.Remove(Check.NotNull(role, nameof(role)));\n            try\n            {\n                await SaveChanges(cancellationToken);\n            }\n            catch (DbUpdateConcurrencyException)\n            {\n                return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());\n            }\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        /// Gets the ID for a role from the store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose ID should be returned.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that contains the ID of the role.</returns>\n        public virtual Task<string> GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(ConvertIdToString(Check.NotNull(role, nameof(role)).Id));\n        }\n\n        /// <summary>\n        /// Gets the name of a role from the store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose name should be returned.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that contains the name of the role.</returns>\n        public virtual Task<string> GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(role, nameof(role)).RoleName);\n        }\n\n        /// <summary>\n        /// Sets the name of a role in the store as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose name should be set.</param>\n        /// <param name=\"roleName\">The name of the role.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>The <see cref=\"Task\"/> that represents the asynchronous operation.</returns>\n        public virtual Task SetRoleNameAsync(TRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(role, nameof(role)).RoleName = roleName;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Converts the provided <paramref name=\"id\"/> to a strongly typed key object.\n        /// </summary>\n        /// <param name=\"id\">The id to convert.</param>\n        /// <returns>An instance of <typeparamref name=\"TKey\"/> representing the provided <paramref name=\"id\"/>.</returns>\n        public virtual TKey ConvertIdFromString(string id)\n            => string.IsNullOrWhiteSpace(id)\n                ? default(TKey)\n                : (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id);\n\n        /// <summary>\n        /// Converts the provided <paramref name=\"id\"/> to its string representation.\n        /// </summary>\n        /// <param name=\"id\">The id to convert.</param>\n        /// <returns>An <see cref=\"string\"/> representation of the provided <paramref name=\"id\"/>.</returns>\n        public virtual string ConvertIdToString(TKey id)\n            => id.Equals(default(TKey))\n                ? null\n                : id.ToString();\n\n        /// <summary>\n        /// Finds the role who has the specified ID as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"id\">The role ID to look for.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that result of the look up.</returns>\n        public virtual Task<TRole> FindByIdAsync(string id, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            var roleId = ConvertIdFromString(id);\n            return Roles.FirstOrDefaultAsync(role => role.Id.Equals(roleId), cancellationToken);\n        }\n\n        /// <summary>\n        /// Finds the role who has the specified normalized name as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"normalizedName\">The normalized role name to look for.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that result of the look up.</returns>\n        public virtual Task<TRole> FindByNameAsync(string normalizedName, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Roles.FirstOrDefaultAsync(role => role.NormalizedRoleName == normalizedName, cancellationToken);\n        }\n\n        /// <summary>\n        /// Get a role's normalized name as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose normalized name should be retrieved.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that contains the name of the role.</returns>\n        public virtual Task<string> GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(role, nameof(role)).NormalizedRoleName);\n        }\n\n        /// <summary>\n        /// Set a role's normalized name as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose normalized name should be set.</param>\n        /// <param name=\"normalizedName\">The normalized name to set</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>The <see cref=\"Task\"/> that represents the asynchronous operation.</returns>\n        public virtual Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(role, nameof(role)).NormalizedRoleName = normalizedName;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Get the claims associated with the specified <paramref name=\"role\"/> as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"role\">The role whose claims should be retrieved.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>A <see cref=\"Task{TResult}\"/> that contains the claims granted to a role.</returns>\n        public virtual async Task<IList<Claim>> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(role, nameof(role));\n            IList<Claim> claims = role.Claims\n                .Select(roleClaim => roleClaim.ToClaim())\n                .ToList();\n            return await Task.FromResult(claims);\n        }\n\n        /// <summary>\n        /// Adds the <paramref name=\"claim\"/> given to the specified <paramref name=\"role\"/>.\n        /// </summary>\n        /// <param name=\"role\">The role to add the claim to.</param>\n        /// <param name=\"claim\">The claim to add to the role.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>The <see cref=\"Task\"/> that represents the asynchronous operation.</returns>\n        public virtual Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(role, nameof(role));\n            Check.NotNull(claim, nameof(claim));\n            role.Claims.Add(CreateRoleClaim(role, claim));\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Creates a entity representing a role claim.\n        /// </summary>\n        /// <param name=\"role\">The associated role.</param>\n        /// <param name=\"claim\">The associated claim.</param>\n        /// <returns>The role claim entity.</returns>\n        protected virtual TClaim CreateRoleClaim(TRole role, Claim claim)\n            => new TClaim()\n            {\n                ClaimType = claim.Type,\n                ClaimValue = claim.Value\n            };\n\n        /// <summary>\n        /// Removes the <paramref name=\"claim\"/> given from the specified <paramref name=\"role\"/>.\n        /// </summary>\n        /// <param name=\"role\">The role to remove the claim from.</param>\n        /// <param name=\"claim\">The claim to remove from the role.</param>\n        /// <param name=\"cancellationToken\">The <see cref=\"CancellationToken\"/> used to propagate notifications that the operation should be canceled.</param>\n        /// <returns>The <see cref=\"Task\"/> that represents the asynchronous operation.</returns>\n        public virtual async Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(role, nameof(role));\n            Check.NotNull(claim, nameof(claim));\n            IList<TClaim> matchedClaims = role.Claims\n                .Where(roleClaim => roleClaim.ClaimValue == claim.Value && roleClaim.ClaimType == claim.Type)\n                .ToList();\n            foreach (var roleClaim in matchedClaims)\n            {\n                role.Claims.Remove(roleClaim);\n            }\n            await Task.CompletedTask;\n        }\n    }\n}"
  },
  {
    "path": "src/Blueshift.Identity.MongoDB/MongoDbUserStore.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.Linq;\nusing System.Security.Claims;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Utilities;\nusing MongoDB.Bson;\n\nnamespace Blueshift.Identity.MongoDB\n{\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    public class MongoDbUserStore : MongoDbUserStore<MongoDbIdentityUser, MongoDbIdentityRole, IdentityMongoDbContext,\n        ObjectId>\n    {\n        /// <summary>\n        ///     Creates a new instance of <see cref=\"MongoDbUserStore\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(IdentityMongoDbContext context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    /// <typeparam name=\"TKey\">The type of the identifiers for this store's objects.</typeparam>\n    public class MongoDbUserStore<TKey> :\n        MongoDbUserStore<MongoDbIdentityUser<TKey>, MongoDbIdentityRole<TKey>, IdentityMongoDbContext<TKey>, TKey>\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        ///     Creates a new instance of <see cref=\"MongoDbUserStore{TKey}\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(IdentityMongoDbContext<TKey> context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of the user objects for this store.</typeparam>\n    /// <typeparam name=\"TRole\">The type of the role objects for this store.</typeparam>\n    public class MongoDbUserStore<TUser, TRole> :\n        MongoDbUserStore<\n            TUser,\n            TRole,\n            ObjectId>\n        where TUser : MongoDbIdentityUser<ObjectId>, new()\n        where TRole : MongoDbIdentityRole<ObjectId>, new()\n    {\n        /// <summary>\n        ///     Creates a new instance of <see cref=\"MongoDbUserStore{TUser, TRole}\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(IdentityMongoDbContext<TUser, TRole, ObjectId> context,\n            IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of the user objects for this store.</typeparam>\n    /// <typeparam name=\"TRole\">The type of the role objects for this store.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the identifiers for this store's objects.</typeparam>\n    public class MongoDbUserStore<TUser, TRole, TKey> :\n        MongoDbUserStore<\n            TUser,\n            TRole,\n            IdentityMongoDbContext<\n                TUser,\n                TRole,\n                TKey,\n                MongoDbIdentityClaim,\n                MongoDbIdentityUserRole,\n                MongoDbIdentityUserLogin,\n                MongoDbIdentityUserToken>,\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TUser : MongoDbIdentityUser<\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>, new()\n        where TRole : MongoDbIdentityRole<TKey>, new()\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        ///     Creates a new instance of <see cref=\"MongoDbUserStore{TUser, TRole, TContext, TKey}\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(\n            IdentityMongoDbContext<TUser,\n                TRole,\n                TKey,\n                MongoDbIdentityClaim,\n                MongoDbIdentityUserRole,\n                MongoDbIdentityUserLogin,\n                MongoDbIdentityUserToken> context,\n            IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <inheritdoc />\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of the user objects for this store.</typeparam>\n    /// <typeparam name=\"TRole\">The type of the role objects for this store.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the <see cref=\"T:Microsoft.EntityFrameworkCore.DbContext\" /> with which this store communicates.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the identifiers for this store's objects.</typeparam>\n    public class MongoDbUserStore<TUser, TRole, TContext, TKey> :\n        MongoDbUserStore<\n            TUser,\n            TRole,\n            TContext,\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>\n        where TUser : MongoDbIdentityUser<\n            TKey,\n            MongoDbIdentityClaim,\n            MongoDbIdentityUserRole,\n            MongoDbIdentityUserLogin,\n            MongoDbIdentityUserToken>, new()\n        where TRole : MongoDbIdentityRole<TKey, MongoDbIdentityClaim>, new()\n        where TContext : DbContext\n        where TKey : IEquatable<TKey>\n    {\n        /// <summary>\n        ///     Creates a new instance of <see cref=\"MongoDbUserStore{TUser, TRole, TContext, TKey}\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(TContext context, IdentityErrorDescriber describer = null)\n            : base(context, describer)\n        {\n        }\n    }\n\n    /// <summary>\n    ///     Represents a new instance of a persistence store for the specified user and role types.\n    /// </summary>\n    /// <typeparam name=\"TUser\">The type of the user objects for this store.</typeparam>\n    /// <typeparam name=\"TRole\">The type of the role objects for this store.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the <see cref=\"DbContext\" /> with which this store communicates.</typeparam>\n    /// <typeparam name=\"TKey\">The type of the identifiers for this store's objects.</typeparam>\n    /// <typeparam name=\"TClaim\">The type of the security claim objects for this store.</typeparam>\n    /// <typeparam name=\"TUserRole\">The type type of the user role objects for this store.</typeparam>\n    /// <typeparam name=\"TUserLogin\">The type of the user login objects for this store.</typeparam>\n    /// <typeparam name=\"TUserToken\">The type of the user token objects for this store.</typeparam>\n    public class MongoDbUserStore<TUser, TRole, TContext, TKey, TClaim, TUserRole, TUserLogin, TUserToken> :\n        IQueryableUserStore<TUser>,\n        IUserAuthenticationTokenStore<TUser>,\n        IUserAuthenticatorKeyStore<TUser>,\n        IUserClaimStore<TUser>,\n        IUserEmailStore<TUser>,\n        IUserLockoutStore<TUser>,\n        IUserLoginStore<TUser>,\n        IUserPasswordStore<TUser>,\n        IUserPhoneNumberStore<TUser>,\n        IUserRoleStore<TUser>,\n        IUserSecurityStampStore<TUser>,\n        IUserTwoFactorStore<TUser>,\n        IUserTwoFactorRecoveryCodeStore<TUser>\n        where TUser : MongoDbIdentityUser<TKey, TClaim, TUserRole, TUserLogin, TUserToken>, new()\n        where TRole : MongoDbIdentityRole<TKey, TClaim>, new()\n        where TContext : DbContext\n        where TKey : IEquatable<TKey>\n        where TClaim : MongoDbIdentityClaim, new()\n        where TUserRole : MongoDbIdentityUserRole, new()\n        where TUserLogin : MongoDbIdentityUserLogin<TUserToken>, new()\n        where TUserToken : MongoDbIdentityUserToken, new()\n    {\n        private const string InternalLoginProvider = \"[BlueshiftMongoDbUserStore]\";\n        private const string AuthenticatorKeyTokenName = \"AuthenticatorKey\";\n        private const string RecoveryCodeTokenName = \"RecoveryCodes\";\n\n        private bool _disposed;\n\n        /// <summary>\n        ///     Creates a new instance of\n        ///     <see cref=\"MongoDbUserStore{TUser, TRole, TContext, TKey, TClaim, TUserRole, TUserLogin, TUserToken}\" />.\n        /// </summary>\n        /// <param name=\"context\">The context used to access the store.</param>\n        /// <param name=\"describer\">The <see cref=\"IdentityErrorDescriber\" /> used to describe store errors.</param>\n        public MongoDbUserStore(TContext context, IdentityErrorDescriber describer = null)\n        {\n            Context = Check.NotNull(context, nameof(context));\n            ErrorDescriber = describer ?? new IdentityErrorDescriber();\n        }\n\n        /// <summary>\n        ///     Gets the database context used by this store.\n        /// </summary>\n        public TContext Context { get; }\n\n        /// <summary>\n        ///     Gets or sets the <see cref=\"IdentityErrorDescriber\" /> for any error that occurred with the current operation.\n        /// </summary>\n        public IdentityErrorDescriber ErrorDescriber { get; set; }\n\n        private DbSet<TRole> Roles => Context.Set<TRole>();\n\n        /// <summary>\n        ///     Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are\n        ///     called.\n        /// </summary>\n        /// <value>\n        ///     True if changes should be automatically persisted, otherwise false.\n        /// </value>\n        public bool AutoSaveChanges { get; set; } = true;\n\n        /// <summary>\n        ///     Gets the user identifier for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose identifier should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the identifier for the\n        ///     specified <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetUserIdAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(ConvertIdToString(Check.NotNull(user, nameof(user)).Id));\n        }\n\n        /// <summary>\n        ///     Gets the user name for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose name should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the name for the specified\n        ///     <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetUserNameAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).UserName);\n        }\n\n        /// <summary>\n        ///     Sets the given <paramref name=\"userName\" /> for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose name should be set.</param>\n        /// <param name=\"userName\">The user name to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetUserNameAsync(TUser user, string userName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).UserName = userName;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Gets the normalized user name for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose normalized name should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the normalized user name for\n        ///     the specified <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetNormalizedUserNameAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            return Task.FromResult(user.NormalizedUserName);\n        }\n\n        /// <summary>\n        ///     Sets the given normalized name for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose name should be set.</param>\n        /// <param name=\"normalizedName\">The normalized name to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetNormalizedUserNameAsync(TUser user, string normalizedName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).NormalizedUserName = normalizedName;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Creates the specified <paramref name=\"user\" /> in the user store.\n        /// </summary>\n        /// <param name=\"user\">The user to create.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the\n        ///     <see cref=\"IdentityResult\" /> of the creation operation.\n        /// </returns>\n        public virtual async Task<IdentityResult> CreateAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Context.Add(Check.NotNull(user, nameof(user)));\n            await SaveChanges(cancellationToken);\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        ///     Updates the specified <paramref name=\"user\" /> in the user store.\n        /// </summary>\n        /// <param name=\"user\">The user to update.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the\n        ///     <see cref=\"IdentityResult\" /> of the update operation.\n        /// </returns>\n        public virtual async Task<IdentityResult> UpdateAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n\n            Context.Attach(Check.NotNull(user, nameof(user)));\n            user.ConcurrencyStamp = Guid.NewGuid().ToString();\n            Context.Update(user);\n            try\n            {\n                await SaveChanges(cancellationToken);\n            }\n            catch (DbUpdateConcurrencyException)\n            {\n                return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());\n            }\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        ///     Deletes the specified <paramref name=\"user\" /> from the user store.\n        /// </summary>\n        /// <param name=\"user\">The user to delete.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the\n        ///     <see cref=\"IdentityResult\" /> of the update operation.\n        /// </returns>\n        public virtual async Task<IdentityResult> DeleteAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n\n            Context.Remove(Check.NotNull(user, nameof(user)));\n            try\n            {\n                await SaveChanges(cancellationToken);\n            }\n            catch (DbUpdateConcurrencyException)\n            {\n                return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());\n            }\n            return IdentityResult.Success;\n        }\n\n        /// <summary>\n        ///     Finds and returns a user, if any, who has the specified <paramref name=\"userId\" />.\n        /// </summary>\n        /// <param name=\"userId\">The user ID to search for.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the user matching the specified\n        ///     <paramref name=\"userId\" /> if it exists.\n        /// </returns>\n        public virtual Task<TUser> FindByIdAsync(string userId,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            TKey id = ConvertIdFromString(userId);\n            return Users.FirstOrDefaultAsync(u => u.Id.Equals(id), cancellationToken);\n        }\n\n        /// <summary>\n        ///     Finds and returns a user, if any, who has the specified normalized user name.\n        /// </summary>\n        /// <param name=\"normalizedUserName\">The normalized user name to search for.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the user matching the specified\n        ///     <paramref name=\"normalizedUserName\" /> if it exists.\n        /// </returns>\n        public virtual Task<TUser> FindByNameAsync(string normalizedUserName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Users.FirstOrDefaultAsync(u => u.NormalizedUserName == normalizedUserName, cancellationToken);\n        }\n\n        /// <summary>\n        ///     A navigation property for the users the store contains.\n        /// </summary>\n        public virtual IQueryable<TUser> Users => Context.Set<TUser>();\n\n        /// <summary>\n        ///     Dispose this MongoDB user store.\n        /// </summary>\n        public void Dispose()\n        {\n            _disposed = true;\n        }\n\n        /// <summary>\n        ///     Sets the token value for a particular user.\n        /// </summary>\n        /// <param name=\"user\">The user.</param>\n        /// <param name=\"loginProvider\">The authentication provider for the token.</param>\n        /// <param name=\"name\">The name of the token.</param>\n        /// <param name=\"value\">The value of the token.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetTokenAsync(TUser user, string loginProvider, string name, string value,\n            CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n\n            TUserLogin userLogin = Check.NotNull(user, nameof(user))\n                .Logins\n                .FirstOrDefault(login => login.LoginProvider == loginProvider);\n            TUserToken userToken = userLogin\n                ?.UserTokens\n                .FirstOrDefault(token => token.Name == name);\n            if (userToken == null)\n                userLogin.UserTokens.Add(CreateUserToken(user, loginProvider, name, value));\n            else\n                userToken.Value = value;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Deletes a token for a user.\n        /// </summary>\n        /// <param name=\"user\">The user.</param>\n        /// <param name=\"loginProvider\">The authentication provider for the token.</param>\n        /// <param name=\"name\">The name of the token.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n\n            TUserLogin userLogin = Check.NotNull(user, nameof(user))\n                .Logins\n                .FirstOrDefault(login => login.LoginProvider == loginProvider);\n            TUserToken userToken = userLogin\n                ?.UserTokens\n                .FirstOrDefault(token => token.Name == name);\n            if (userLogin != null && userToken != null)\n                userLogin.UserTokens.Remove(userToken);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Returns the token value.\n        /// </summary>\n        /// <param name=\"user\">The user.</param>\n        /// <param name=\"loginProvider\">The authentication provider for the token.</param>\n        /// <param name=\"name\">The name of the token.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public Task<string> GetTokenAsync(TUser user, string loginProvider, string name,\n            CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n\n            string tokenValue = Check.NotNull(user, nameof(user))\n                .Logins\n                .FirstOrDefault(login => login.LoginProvider == loginProvider)\n                ?.UserTokens\n                .FirstOrDefault(token => token.Name == name)\n                ?.Value;\n            return Task.FromResult(tokenValue);\n        }\n\n        /// <summary>\n        ///     Sets the authenticator key for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose authenticator key should be set.</param>\n        /// <param name=\"key\">The authenticator key to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetAuthenticatorKeyAsync(TUser user, string key, CancellationToken cancellationToken)\n        {\n            return SetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, key, cancellationToken);\n        }\n\n        /// <summary>\n        ///     Get the authenticator key for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose security stamp should be set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the security stamp for the\n        ///     specified <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetAuthenticatorKeyAsync(TUser user, CancellationToken cancellationToken)\n        {\n            return GetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, cancellationToken);\n        }\n\n        /// <summary>\n        ///     Asynchronously retrieves the claims associated with the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose claims should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>A <see cref=\"Task{TResult}\" /> that contains the claims granted to a user.</returns>\n        public virtual Task<IList<Claim>> GetClaimsAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            IList<Claim> userClaims = user.Claims\n                .Select(claim => claim.ToClaim())\n                .ToList();\n            return Task.FromResult(userClaims);\n        }\n\n        /// <summary>\n        ///     Adds the specified list of <paramref name=\"claims\" /> to the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to add the claim to.</param>\n        /// <param name=\"claims\">The claim to add to the user.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(claims, nameof(claims));\n            foreach (Claim claim in claims)\n                user.Claims.Add(CreateUserClaim(user, claim));\n            return Task.FromResult(false);\n        }\n\n        /// <summary>\n        ///     Replaces the <paramref name=\"claim\" /> on the specified <paramref name=\"user\" />, with the\n        ///     <paramref name=\"newClaim\" />.\n        /// </summary>\n        /// <param name=\"user\">The role to replace the claim on.</param>\n        /// <param name=\"claim\">The claim replace.</param>\n        /// <param name=\"newClaim\">The new claim replacing the <paramref name=\"claim\" />.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(claim, nameof(claim));\n            Check.NotNull(newClaim, nameof(newClaim));\n            IList<TClaim> matchedClaims = user.Claims\n                .Where(userClaim => userClaim.ClaimValue == claim.Value && userClaim.ClaimType == claim.Type)\n                .ToList();\n            foreach (TClaim matchedClaim in matchedClaims)\n                matchedClaim.InitializeFromClaim(newClaim);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Removes the <paramref name=\"claims\" /> given from the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to remove the claims from.</param>\n        /// <param name=\"claims\">The claim to remove.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(claims, nameof(claims));\n            IList<TClaim> matchedClaims = user.Claims\n                .Join(claims,\n                    userClaim => new {userClaim.ClaimType, userClaim.ClaimValue},\n                    claim => new {ClaimType = claim.Type, ClaimValue = claim.Value},\n                    (userClaim, claim) => userClaim)\n                .ToList();\n            foreach (TClaim userClaim in matchedClaims)\n                user.Claims.Remove(userClaim);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Retrieves all users with the specified claim.\n        /// </summary>\n        /// <param name=\"claim\">The claim whose users should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> contains a list of users, if any, that contain the specified claim.\n        /// </returns>\n        public virtual async Task<IList<TUser>> GetUsersForClaimAsync(Claim claim,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(claim, nameof(claim));\n            return await Users\n                .Where(user => user.Claims\n                    .Any(userClaim => userClaim.ClaimType == claim.Type\n                                      && userClaim.ClaimValue == claim.Value))\n                .ToListAsync(cancellationToken);\n        }\n\n        /// <summary>\n        ///     Gets a flag indicating whether the email address for the specified <paramref name=\"user\" /> has been verified, true\n        ///     if the email address is verified otherwise\n        ///     false.\n        /// </summary>\n        /// <param name=\"user\">The user whose email confirmation status should be returned.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The task object containing the results of the asynchronous operation, a flag indicating whether the email address\n        ///     for the specified <paramref name=\"user\" />\n        ///     has been confirmed or not.\n        /// </returns>\n        public virtual Task<bool> GetEmailConfirmedAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).EmailConfirmed);\n        }\n\n        /// <summary>\n        ///     Sets the flag indicating whether the specified <paramref name=\"user\" />'s email address has been confirmed or not.\n        /// </summary>\n        /// <param name=\"user\">The user whose email confirmation status should be set.</param>\n        /// <param name=\"confirmed\">\n        ///     A flag indicating if the email address has been confirmed, true if the address is confirmed\n        ///     otherwise false.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The task object representing the asynchronous operation.</returns>\n        public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).EmailConfirmed = confirmed;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Sets the <paramref name=\"email\" /> address for a <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose email should be set.</param>\n        /// <param name=\"email\">The email to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The task object representing the asynchronous operation.</returns>\n        public virtual Task SetEmailAsync(TUser user, string email,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).Email = email;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Gets the email address for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose email should be returned.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The task object containing the results of the asynchronous operation, the email address for the specified\n        ///     <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetEmailAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).Email);\n        }\n\n        /// <summary>\n        ///     Returns the normalized email for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose email address to retrieve.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The task object containing the results of the asynchronous lookup operation, the normalized email address if any\n        ///     associated with the specified user.\n        /// </returns>\n        public virtual Task<string> GetNormalizedEmailAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).NormalizedEmail);\n        }\n\n        /// <summary>\n        ///     Sets the normalized email for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose email address to set.</param>\n        /// <param name=\"normalizedEmail\">The normalized email to set for the specified <paramref name=\"user\" />.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The task object representing the asynchronous operation.</returns>\n        public virtual Task SetNormalizedEmailAsync(TUser user, string normalizedEmail,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).NormalizedEmail = normalizedEmail;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Gets the user, if any, associated with the specified, normalized email address.\n        /// </summary>\n        /// <param name=\"normalizedEmail\">The normalized email address to return the user for.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The task object containing the results of the asynchronous lookup operation, the user if any associated with the\n        ///     specified normalized email address.\n        /// </returns>\n        public virtual Task<TUser> FindByEmailAsync(string normalizedEmail,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Users.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, cancellationToken);\n        }\n\n        /// <summary>\n        ///     Gets the last <see cref=\"DateTimeOffset\" /> a user's last lockout expired, if any.\n        ///     Any time in the past should be indicates a user is not locked out.\n        /// </summary>\n        /// <param name=\"user\">The user whose lockout date should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     A <see cref=\"Task{TResult}\" /> that represents the result of the asynchronous query, a\n        ///     <see cref=\"DateTimeOffset\" /> containing the last time\n        ///     a user's lockout expired, if any.\n        /// </returns>\n        public virtual Task<DateTimeOffset?> GetLockoutEndDateAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).LockoutEnd);\n        }\n\n        /// <summary>\n        ///     Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a\n        ///     user.\n        /// </summary>\n        /// <param name=\"user\">The user whose lockout date should be set.</param>\n        /// <param name=\"lockoutEnd\">\n        ///     The <see cref=\"DateTimeOffset\" /> after which the <paramref name=\"user\" />'s lockout should\n        ///     end.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).LockoutEnd = lockoutEnd;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Records that a failed access has occurred, incrementing the failed access count.\n        /// </summary>\n        /// <param name=\"user\">The user whose cancellation count should be incremented.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the incremented failed access\n        ///     count.\n        /// </returns>\n        public virtual Task<int> IncrementAccessFailedCountAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(++Check.NotNull(user, nameof(user)).AccessFailedCount);\n        }\n\n        /// <summary>\n        ///     Resets a user's failed access count.\n        /// </summary>\n        /// <param name=\"user\">The user whose failed access count should be reset.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        /// <remarks>This is typically called after the account is successfully accessed.</remarks>\n        public virtual Task ResetAccessFailedCountAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).AccessFailedCount = 0;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Retrieves the current failed access count for the specified <paramref name=\"user\" />..\n        /// </summary>\n        /// <param name=\"user\">The user whose failed access count should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation, containing the failed access count.</returns>\n        public virtual Task<int> GetAccessFailedCountAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).AccessFailedCount);\n        }\n\n        /// <summary>\n        ///     Retrieves a flag indicating whether user lockout can enabled for the specified user.\n        /// </summary>\n        /// <param name=\"user\">The user whose ability to be locked out should be returned.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, true if a user can be locked out, otherwise\n        ///     false.\n        /// </returns>\n        public virtual Task<bool> GetLockoutEnabledAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).LockoutEnabled);\n        }\n\n        /// <summary>\n        ///     Set the flag indicating if the specified <paramref name=\"user\" /> can be locked out..\n        /// </summary>\n        /// <param name=\"user\">The user whose ability to be locked out should be set.</param>\n        /// <param name=\"enabled\">A flag indicating if lock out can be enabled for the specified <paramref name=\"user\" />.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetLockoutEnabledAsync(TUser user, bool enabled,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).LockoutEnabled = enabled;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Adds the <paramref name=\"login\" /> given to the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to add the login to.</param>\n        /// <param name=\"login\">The login to add to the user.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task AddLoginAsync(TUser user, UserLoginInfo login,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(login, nameof(login));\n            user.Logins.Add(CreateUserLogin(user, login));\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Removes the <paramref name=\"loginProvider\" /> given from the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to remove the login from.</param>\n        /// <param name=\"loginProvider\">The login to remove from the user.</param>\n        /// <param name=\"providerKey\">The key provided by the <paramref name=\"loginProvider\" /> to identify a user.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n\n            TUserLogin userLoginInfo = Check.NotNull(user, nameof(user))\n                .Logins\n                .SingleOrDefault(userLogin =>\n                    userLogin.LoginProvider == loginProvider\n                    && userLogin.ProviderKey == providerKey);\n            if (userLoginInfo != null)\n                user.Logins.Remove(userLoginInfo);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Retrieves the associated logins for the specified\n        ///     <param ref=\"user\" />\n        ///     .\n        /// </summary>\n        /// <param name=\"user\">The user whose associated logins to retrieve.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> for the asynchronous operation, containing a list of <see cref=\"UserLoginInfo\" /> for the\n        ///     specified <paramref name=\"user\" />, if any.\n        /// </returns>\n        public virtual Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n\n            IList<UserLoginInfo> userLogins = user.Logins\n                .Select(userLogin => userLogin.ToUserLoginInfo())\n                .ToList();\n            return Task.FromResult(userLogins);\n        }\n\n        /// <summary>\n        ///     Retrieves the user associated with the specified login provider and login provider key..\n        /// </summary>\n        /// <param name=\"loginProvider\">The login provider who provided the <paramref name=\"providerKey\" />.</param>\n        /// <param name=\"providerKey\">The key provided by the <paramref name=\"loginProvider\" /> to identify a user.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> for the asynchronous operation, containing the user, if any which matched the specified\n        ///     login provider and key.\n        /// </returns>\n        public virtual async Task<TUser> FindByLoginAsync(string loginProvider, string providerKey,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotEmpty(loginProvider, nameof(loginProvider));\n            Check.NotEmpty(providerKey, nameof(providerKey));\n            return await Users\n                .FirstOrDefaultAsync(user => user.Logins\n                    .Any(login => loginProvider == login.LoginProvider && providerKey == login.ProviderKey),\n                    cancellationToken);\n        }\n\n        /// <summary>\n        ///     Sets the password hash for a user.\n        /// </summary>\n        /// <param name=\"user\">The user to set the password hash for.</param>\n        /// <param name=\"passwordHash\">The password hash to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetPasswordHashAsync(TUser user, string passwordHash,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).PasswordHash = passwordHash;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Gets the password hash for a user.\n        /// </summary>\n        /// <param name=\"user\">The user to retrieve the password hash for.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>A <see cref=\"Task{TResult}\" /> that contains the password hash for the user.</returns>\n        public virtual Task<string> GetPasswordHashAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).PasswordHash);\n        }\n\n        /// <summary>\n        ///     Returns a flag indicating if the specified user has a password.\n        /// </summary>\n        /// <param name=\"user\">The user to retrieve the password hash for.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     A <see cref=\"Task{TResult}\" /> containing a flag indicating if the specified user has a password. If the\n        ///     user has a password the returned value with be true, otherwise it will be false.\n        /// </returns>\n        public virtual Task<bool> HasPasswordAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            return Task.FromResult(user.PasswordHash != null);\n        }\n\n        /// <summary>\n        ///     Sets the telephone number for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose telephone number should be set.</param>\n        /// <param name=\"phoneNumber\">The telephone number to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetPhoneNumberAsync(TUser user, string phoneNumber,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).PhoneNumber = phoneNumber;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Gets the telephone number, if any, for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose telephone number should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the user's telephone number, if\n        ///     any.\n        /// </returns>\n        public virtual Task<string> GetPhoneNumberAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).PhoneNumber);\n        }\n\n        /// <summary>\n        ///     Gets a flag indicating whether the specified <paramref name=\"user\" />'s telephone number has been confirmed.\n        /// </summary>\n        /// <param name=\"user\">The user to return a flag for, indicating whether their telephone number is confirmed.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, returning true if the specified\n        ///     <paramref name=\"user\" /> has a confirmed\n        ///     telephone number otherwise false.\n        /// </returns>\n        public virtual Task<bool> GetPhoneNumberConfirmedAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).PhoneNumberConfirmed);\n        }\n\n        /// <summary>\n        ///     Sets a flag indicating if the specified <paramref name=\"user\" />'s phone number has been confirmed..\n        /// </summary>\n        /// <param name=\"user\">The user whose telephone number confirmation status should be set.</param>\n        /// <param name=\"confirmed\">A flag indicating whether the user's telephone number has been confirmed.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).PhoneNumberConfirmed = confirmed;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Adds the given <paramref name=\"normalizedRoleName\" /> to the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to add the role to.</param>\n        /// <param name=\"normalizedRoleName\">The role to add.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual async Task AddToRoleAsync(TUser user, string normalizedRoleName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotEmpty(normalizedRoleName, nameof(normalizedRoleName));\n            TRole roleEntity =\n                await Roles.SingleOrDefaultAsync(r => r.NormalizedRoleName == normalizedRoleName, cancellationToken);\n            if (roleEntity == null)\n                throw new InvalidOperationException($\"Could not find role \\\"{normalizedRoleName}\\\".\");\n            user.Roles.Add(CreateUserRole(user, roleEntity));\n        }\n\n        /// <summary>\n        ///     Removes the given <paramref name=\"normalizedRoleName\" /> from the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user to remove the role from.</param>\n        /// <param name=\"normalizedRoleName\">The role to remove.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task RemoveFromRoleAsync(TUser user, string normalizedRoleName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotEmpty(normalizedRoleName, nameof(normalizedRoleName));\n            TUserRole role = user.Roles\n                .SingleOrDefault(r => r.NormalizedRoleName == normalizedRoleName);\n            if (role != null)\n                user.Roles.Remove(role);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Retrieves the roles the specified <paramref name=\"user\" /> is a member of.\n        /// </summary>\n        /// <param name=\"user\">The user whose roles should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>A <see cref=\"Task{TResult}\" /> that contains the roles the user is a member of.</returns>\n        public virtual Task<IList<string>> GetRolesAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            IList<string> roleNames = user.Roles\n                .Select(role => role.RoleName)\n                .ToList();\n            return Task.FromResult(roleNames);\n        }\n\n        /// <summary>\n        ///     Returns a flag indicating if the specified user is a member of the give <paramref name=\"normalizedRoleName\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose role membership should be checked.</param>\n        /// <param name=\"normalizedRoleName\">The role to check membership of</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     A <see cref=\"Task{TResult}\" /> containing a flag indicating if the specified user is a member of the given group.\n        ///     If the\n        ///     user is a member of the group the returned value with be true, otherwise it will be false.\n        /// </returns>\n        public virtual Task<bool> IsInRoleAsync(TUser user, string normalizedRoleName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotEmpty(normalizedRoleName, nameof(normalizedRoleName));\n            bool isInRole = user.Roles.Any(userRole => userRole.NormalizedRoleName == normalizedRoleName);\n            return Task.FromResult(isInRole);\n        }\n\n        /// <summary>\n        ///     Retrieves all users in the specified role.\n        /// </summary>\n        /// <param name=\"normalizedRoleName\">The role whose users should be retrieved.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> contains a list of users, if any, that are in the specified role.\n        /// </returns>\n        public virtual async Task<IList<TUser>> GetUsersInRoleAsync(string normalizedRoleName,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotEmpty(normalizedRoleName, nameof(normalizedRoleName));\n            return await Users\n                .Where(user => user.Roles\n                    .Any(userRole => userRole.NormalizedRoleName == normalizedRoleName))\n                .ToListAsync(cancellationToken);\n        }\n\n        /// <summary>\n        ///     Sets the provided security <paramref name=\"stamp\" /> for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose security stamp should be set.</param>\n        /// <param name=\"stamp\">The security stamp to set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetSecurityStampAsync(TUser user, string stamp,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).SecurityStamp = stamp;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Get the security stamp for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user whose security stamp should be set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing the security stamp for the\n        ///     specified <paramref name=\"user\" />.\n        /// </returns>\n        public virtual Task<string> GetSecurityStampAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).SecurityStamp);\n        }\n\n        /// <summary>\n        ///     Returns the number of remaining valid recovery codes for the specified <paramref name=\"user\" />.\n        /// </summary>\n        /// <param name=\"user\">The user who owns the recovery code.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The number of remaining valid recovery codes for the specified <paramref name=\"user\" />.</returns>\n        public virtual Task<int> CountCodesAsync(TUser user, CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            int count = user.Logins\n                .SelectMany(userLogin => userLogin.UserTokens)\n                .Sum(userToken => 1);\n            return Task.FromResult(count);\n        }\n\n        /// <summary>\n        ///     Updates the recovery codes for the user while invalidating any previous recovery codes.\n        /// </summary>\n        /// <param name=\"user\">The user to store new recovery codes for.</param>\n        /// <param name=\"recoveryCodes\">The new recovery codes for the user.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The new recovery codes for the user.</returns>\n        public virtual Task ReplaceCodesAsync(TUser user, IEnumerable<string> recoveryCodes,\n            CancellationToken cancellationToken)\n        {\n            return SetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, string.Join(\";\", recoveryCodes),\n                cancellationToken);\n        }\n\n        /// <summary>\n        ///     Returns whether a recovery code is valid for a user. Note: recovery codes are only valid\n        ///     once, and will be invalid after use.\n        /// </summary>\n        /// <param name=\"user\">The user who owns the recovery code.</param>\n        /// <param name=\"code\">The recovery code to use.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>True if the recovery code was found for the user.</returns>\n        public virtual async Task<bool> RedeemCodeAsync(TUser user, string code, CancellationToken cancellationToken)\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(code, nameof(code));\n\n            string originalCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName,\n                                       cancellationToken) ?? \"\";\n            string[] splitCodes = originalCodes.Split(';');\n            if (splitCodes.Contains(code))\n            {\n                var updatedCodes = new List<string>(splitCodes.Where(s => s != code));\n                await ReplaceCodesAsync(user, updatedCodes, cancellationToken);\n                return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        ///     Sets a flag indicating whether the specified <paramref name=\"user\" /> has two factor authentication enabled or not,\n        ///     as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"user\">The user whose two factor authentication enabled status should be set.</param>\n        /// <param name=\"enabled\">\n        ///     A flag indicating whether the specified <paramref name=\"user\" /> has two factor authentication\n        ///     enabled.\n        /// </param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        public virtual Task SetTwoFactorEnabledAsync(TUser user, bool enabled,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            Check.NotNull(user, nameof(user)).TwoFactorEnabled = enabled;\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Returns a flag indicating whether the specified <paramref name=\"user\" /> has two factor authentication enabled or\n        ///     not,\n        ///     as an asynchronous operation.\n        /// </summary>\n        /// <param name=\"user\">The user whose two factor authentication enabled status should be set.</param>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>\n        ///     The <see cref=\"Task\" /> that represents the asynchronous operation, containing a flag indicating whether the\n        ///     specified\n        ///     <paramref name=\"user\" /> has two factor authentication enabled or not.\n        /// </returns>\n        public virtual Task<bool> GetTwoFactorEnabledAsync(TUser user,\n            CancellationToken cancellationToken = default(CancellationToken))\n        {\n            cancellationToken.ThrowIfCancellationRequested();\n            ThrowIfDisposed();\n            return Task.FromResult(Check.NotNull(user, nameof(user)).TwoFactorEnabled);\n        }\n\n        /// <summary>\n        ///     Creates a new instance of the <typeparamref name=\"TUserRole\" /> that will be used to represent a user's security\n        ///     role.\n        /// </summary>\n        /// <param name=\"user\">The user to whom the role will be assigned.</param>\n        /// <param name=\"role\">The role to which the user will be assigned.</param>\n        /// <returns>A new instance of <typeparamref name=\"TUserRole\" /> for the given <paramref name=\"user\" />.</returns>\n        protected virtual TUserRole CreateUserRole(TUser user, TRole role)\n        {\n            return new TUserRole\n            {\n                RoleName = Check.NotNull(role, nameof(role)).RoleName,\n                NormalizedRoleName = role.RoleName.ToUpper()\n            };\n        }\n\n        /// <summary>\n        ///     Creates a new instance of the <typeparamref name=\"TClaim\" /> that will be used to represent a user's security\n        ///     claim.\n        /// </summary>\n        /// <param name=\"user\">The user to whom the claim will be assigned.</param>\n        /// <param name=\"claim\">The claim which will be assigned to the user.</param>\n        /// <returns>A new instance of <typeparamref name=\"TClaim\" /> for the given <paramref name=\"user\" />.</returns>\n        protected virtual TClaim CreateUserClaim(TUser user, Claim claim)\n        {\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(claim, nameof(claim));\n            var userClaim = new TClaim();\n            userClaim.InitializeFromClaim(claim);\n            return userClaim;\n        }\n\n        /// <summary>\n        ///     Creates a new instance of the <typeparamref name=\"TUserLogin\" /> that will be used to represent an external user\n        ///     login provider.\n        /// </summary>\n        /// <param name=\"user\">The user to whom the external login provider will be assigned.</param>\n        /// <param name=\"userLoginInfo\">An object containing information about the user's external login provider.</param>\n        /// <returns>A new instance of <typeparamref name=\"TUserLogin\" /> for the given <paramref name=\"user\" />.</returns>\n        protected virtual TUserLogin CreateUserLogin(TUser user, UserLoginInfo userLoginInfo)\n        {\n            Check.NotNull(user, nameof(user));\n            Check.NotNull(userLoginInfo, nameof(userLoginInfo));\n            var userLogin = new TUserLogin();\n            userLogin.InitializeFromUserLoginInfo(userLoginInfo);\n            return userLogin;\n        }\n\n        /// <summary>\n        ///     Creates a new instance of the <typeparamref name=\"TUserToken\" /> for use with an external user login provider.\n        /// </summary>\n        /// <param name=\"user\">The user to whom the external login provider token will be assigned.</param>\n        /// <param name=\"loginProvider\">The name of the external user login provider.</param>\n        /// <param name=\"name\">The name of the external user login provider token.</param>\n        /// <param name=\"value\">The value of the external user login provider token.</param>\n        /// <returns>A new instance of <typeparamref name=\"TUserToken\" /> for the given <paramref name=\"user\" />.</returns>\n        protected TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value)\n        {\n            return new TUserToken\n            {\n                Name = Check.NotEmpty(name, nameof(name)),\n                Value = Check.NotEmpty(value, nameof(value))\n            };\n        }\n\n        /// <summary>\n        ///     Saves the current store.\n        /// </summary>\n        /// <param name=\"cancellationToken\">\n        ///     The <see cref=\"CancellationToken\" /> used to propagate notifications that the operation\n        ///     should be canceled.\n        /// </param>\n        /// <returns>The <see cref=\"Task\" /> that represents the asynchronous operation.</returns>\n        protected Task SaveChanges(CancellationToken cancellationToken)\n        {\n            return AutoSaveChanges\n                ? Context.SaveChangesAsync(cancellationToken)\n                : Task.CompletedTask;\n        }\n\n        /// <summary>\n        ///     Converts the provided <paramref name=\"id\" /> to a strongly typed key object.\n        /// </summary>\n        /// <param name=\"id\">The id to convert.</param>\n        /// <returns>An instance of <typeparamref name=\"TKey\" /> representing the provided <paramref name=\"id\" />.</returns>\n        public virtual TKey ConvertIdFromString(string id)\n        {\n            return id == null\n                ? default(TKey)\n                : (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id);\n        }\n\n        /// <summary>\n        ///     Converts the provided <paramref name=\"id\" /> to its string representation.\n        /// </summary>\n        /// <param name=\"id\">The id to convert.</param>\n        /// <returns>An <see cref=\"string\" /> representation of the provided <paramref name=\"id\" />.</returns>\n        public virtual string ConvertIdToString(TKey id)\n        {\n            return Equals(id, default(TKey))\n                ? null\n                : id.ToString();\n        }\n\n        /// <summary>\n        ///     Throws an <see cref=\"ObjectDisposedException\" /> if this instance has already been disposed.\n        /// </summary>\n        /// <exception cref=\"ObjectDisposedException\">Thrown if this instance has already been disposed.</exception>\n        protected void ThrowIfDisposed()\n        {\n            if (_disposed)\n                throw new ObjectDisposedException(GetType().Name);\n        }\n    }\n}"
  },
  {
    "path": "src/Directory.Build.props",
    "content": "<Project>\n  <Import Project=\"..\\Directory.Build.props\" />\n\n  <PropertyGroup>\n    <DeveloperBuildFrameworks>netstandard2.0</DeveloperBuildFrameworks>\n    <BuildFrameworks>$(DeveloperBuildFrameworks)</BuildFrameworks>\n    <BuildFrameworks Condition=\" '$(DeveloperBuild)' != 'True' \">netstandard2.0</BuildFrameworks>\n    <BuildFrameworks Condition=\" '$(DeveloperBuild)' != 'True' AND '$(CoreOnly)' != 'True' AND '$(OS)' == 'Windows_NT' \">net461;$(BuildFrameworks)</BuildFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);CA1822</NoWarn>\n  </PropertyGroup>\n\n</Project>"
  },
  {
    "path": "src/Shared/Check.cs",
    "content": "// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Reflection;\nusing JetBrains.Annotations;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\n\nnamespace Microsoft.EntityFrameworkCore.Utilities\n{\n    [DebuggerStepThrough]\n    internal static class Check\n    {\n        [ContractAnnotation(\"value:null => halt\")]\n        public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)\n        {\n            if (ReferenceEquals(value, null))\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n\n                throw new ArgumentNullException(parameterName);\n            }\n\n            return value;\n        }\n\n        [ContractAnnotation(\"value:null => halt\")]\n        public static object IsInstanceOfType(\n            [NoEnumeration] object value,\n            [NotNull] Type type,\n            [InvokerParameterName] [NotNull] string parameterName)\n        {\n            if (!Check.NotNull(type, nameof(type)).IsInstanceOfType(value))\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n                throw new ArgumentException($@\"Argument {parameterName} is not an instance of {type.FullName}.\", parameterName);\n            }\n\n            return value;\n        }\n\n        [ContractAnnotation(\"value:null => halt\")]\n        public static T Is<T>(\n            [NoEnumeration] object value,\n            [InvokerParameterName] [NotNull] string parameterName)\n            where T : class\n            => IsInstanceOfType(value, typeof(T), parameterName) as T;\n\n        [ContractAnnotation(\"value:null => halt\")]\n        public static T NotNull<T>(\n            [NoEnumeration] T value,\n            [InvokerParameterName] [NotNull] string parameterName,\n            [NotNull] string propertyName)\n        {\n            if (ReferenceEquals(value, null))\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n                NotEmpty(propertyName, nameof(propertyName));\n\n                throw new ArgumentException(CoreStrings.ArgumentPropertyNull(propertyName, parameterName));\n            }\n\n            return value;\n        }\n\n        [ContractAnnotation(\"value:null => halt\")]\n        public static IReadOnlyList<T> NotEmpty<T>(IReadOnlyList<T> value, [InvokerParameterName] [NotNull] string parameterName)\n        {\n            NotNull(value, parameterName);\n\n            if (value.Count == 0)\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n\n                throw new ArgumentException(CoreStrings.CollectionArgumentIsEmpty(parameterName));\n            }\n\n            return value;\n        }\n\n        [ContractAnnotation(\"value:null => halt\")]\n        public static string NotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)\n        {\n            Exception e = null;\n            if (ReferenceEquals(value, null))\n            {\n                e = new ArgumentNullException(parameterName);\n            }\n            else if (value.Trim().Length == 0)\n            {\n                e = new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName));\n            }\n\n            if (e != null)\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n\n                throw e;\n            }\n\n            return value;\n        }\n\n        public static string NullButNotEmpty(string value, [InvokerParameterName] [NotNull] string parameterName)\n        {\n            if (!ReferenceEquals(value, null)\n                && (value.Length == 0))\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n\n                throw new ArgumentException(CoreStrings.ArgumentIsEmpty(parameterName));\n            }\n\n            return value;\n        }\n\n        public static IReadOnlyList<T> HasNoNulls<T>(IReadOnlyList<T> value, [InvokerParameterName] [NotNull] string parameterName)\n            where T : class\n        {\n            NotNull(value, parameterName);\n\n            if (value.Any(e => e == null))\n            {\n                NotEmpty(parameterName, nameof(parameterName));\n\n                throw new ArgumentException(parameterName);\n            }\n\n            return value;\n        }\n\n        public static IEntityType NotOwned(IEntityType entityType,\n            [InvokerParameterName] [NotNull] string parameterName)\n            => NotNull(entityType, parameterName).IsOwned()\n                ? throw new ArgumentException($@\"{entityType.Name} is an owned EntityType.\", parameterName)\n                : entityType;\n    }\n}\n"
  },
  {
    "path": "src/Shared/CodeAnnotations.cs",
    "content": "// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System;\n\nnamespace JetBrains.Annotations\n{\n    [AttributeUsage(\n         AttributeTargets.Method | AttributeTargets.Parameter |\n         AttributeTargets.Property | AttributeTargets.Delegate |\n         AttributeTargets.Field)]\n    internal sealed class NotNullAttribute : Attribute\n    {\n    }\n\n    [AttributeUsage(\n         AttributeTargets.Method | AttributeTargets.Parameter |\n         AttributeTargets.Property | AttributeTargets.Delegate |\n         AttributeTargets.Field)]\n    internal sealed class CanBeNullAttribute : Attribute\n    {\n    }\n\n    [AttributeUsage(AttributeTargets.Parameter)]\n    internal sealed class InvokerParameterNameAttribute : Attribute\n    {\n    }\n\n    [AttributeUsage(AttributeTargets.Parameter)]\n    internal sealed class NoEnumerationAttribute : Attribute\n    {\n    }\n\n    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]\n    internal sealed class ContractAnnotationAttribute : Attribute\n    {\n        public string Contract { get; }\n\n        public bool ForceFullStates { get; }\n\n        public ContractAnnotationAttribute([NotNull] string contract)\n            : this(contract, false)\n        {\n        }\n\n        public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates)\n        {\n            Contract = contract;\n            ForceFullStates = forceFullStates;\n        }\n    }\n\n    [AttributeUsage(AttributeTargets.All)]\n    internal sealed class UsedImplicitlyAttribute : Attribute\n    {\n        public UsedImplicitlyAttribute()\n            : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)\n        {\n        }\n\n        public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)\n            : this(useKindFlags, ImplicitUseTargetFlags.Default)\n        {\n        }\n\n        public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)\n            : this(ImplicitUseKindFlags.Default, targetFlags)\n        {\n        }\n\n        public UsedImplicitlyAttribute(\n            ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)\n        {\n            UseKindFlags = useKindFlags;\n            TargetFlags = targetFlags;\n        }\n\n        public ImplicitUseKindFlags UseKindFlags { get; }\n        public ImplicitUseTargetFlags TargetFlags { get; }\n    }\n\n    [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate)]\n    internal sealed class StringFormatMethodAttribute : Attribute\n    {\n        public StringFormatMethodAttribute([NotNull] string formatParameterName)\n        {\n            FormatParameterName = formatParameterName;\n        }\n\n        [NotNull]\n        public string FormatParameterName { get; }\n    }\n\n    [Flags]\n    internal enum ImplicitUseKindFlags\n    {\n        Default = Access | Assign | InstantiatedWithFixedConstructorSignature,\n        Access = 1,\n        Assign = 2,\n        InstantiatedWithFixedConstructorSignature = 4,\n        InstantiatedNoFixedConstructorSignature = 8\n    }\n\n    [Flags]\n    internal enum ImplicitUseTargetFlags\n    {\n        Default = Itself,\n        Itself = 1,\n        Members = 2,\n        WithMembers = Itself | Members\n    }\n}\n"
  },
  {
    "path": "src/Shared/MemberInfoExtensions.cs",
    "content": "// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nnamespace System.Reflection\n{\n    internal static class MemberInfoExtensions\n    {\n        public static Type GetMemberType(this MemberInfo memberInfo)\n            => (memberInfo as PropertyInfo)?.PropertyType ?? ((FieldInfo)memberInfo)?.FieldType;\n    }\n}\n"
  },
  {
    "path": "src/Shared/PropertyInfoExtensions.cs",
    "content": "// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Diagnostics;\nusing System.Linq;\nusing JetBrains.Annotations;\n\n// ReSharper disable once CheckNamespace\nnamespace System.Reflection\n{\n    [DebuggerStepThrough]\n    internal static class PropertyInfoExtensions\n    {\n        public static bool IsStatic(this PropertyInfo property)\n            => (property.GetMethod ?? property.SetMethod).IsStatic;\n\n        public static bool IsCandidateProperty(this PropertyInfo propertyInfo, bool needsWrite = true)\n            => !propertyInfo.IsStatic()\n               && propertyInfo.GetIndexParameters().Length == 0\n               && propertyInfo.CanRead\n               && (!needsWrite || propertyInfo.CanWrite)\n               && propertyInfo.GetMethod != null && propertyInfo.GetMethod.IsPublic;\n\n        public static Type FindCandidateNavigationPropertyType(this PropertyInfo propertyInfo, Func<Type, bool> isPrimitiveProperty)\n        {\n            var targetType = propertyInfo.PropertyType;\n            var targetSequenceType = targetType.TryGetSequenceType();\n            if (!propertyInfo.IsCandidateProperty(targetSequenceType == null))\n            {\n                return null;\n            }\n\n            targetType = targetSequenceType ?? targetType;\n            targetType = targetType.UnwrapNullableType();\n\n            if (isPrimitiveProperty(targetType)\n                || targetType.GetTypeInfo().IsInterface\n                || targetType.GetTypeInfo().IsValueType\n                || targetType == typeof(object))\n            {\n                return null;\n            }\n\n            return targetType;\n        }\n\n        public static PropertyInfo FindGetterProperty([NotNull] this PropertyInfo propertyInfo)\n            => propertyInfo.DeclaringType\n                .GetPropertiesInHierarchy(propertyInfo.Name)\n                .FirstOrDefault(p => p.GetMethod != null);\n\n        public static PropertyInfo FindSetterProperty([NotNull] this PropertyInfo propertyInfo)\n            => propertyInfo.DeclaringType\n                .GetPropertiesInHierarchy(propertyInfo.Name)\n                .FirstOrDefault(p => p.SetMethod != null);\n    }\n}\n"
  },
  {
    "path": "src/Shared/SharedTypeExtensions.cs",
    "content": "using System.Collections.Generic;\nusing System.Diagnostics;\nusing System.Linq;\nusing System.Reflection;\n\n// ReSharper disable once CheckNamespace\nnamespace System\n{\n    [DebuggerStepThrough]\n    internal static class SharedTypeExtensions\n    {\n        public static Type UnwrapNullableType(this Type type) => Nullable.GetUnderlyingType(type) ?? type;\n\n        public static bool IsNullableType(this Type type)\n        {\n            var typeInfo = type.GetTypeInfo();\n\n            return !typeInfo.IsValueType\n                   || (typeInfo.IsGenericType\n                       && (typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>)));\n        }\n        public static bool IsValidEntityType(this Type type)\n            => type.GetTypeInfo().IsClass;\n\n        public static Type MakeNullable(this Type type)\n            => type.IsNullableType()\n                ? type\n                : typeof(Nullable<>).MakeGenericType(type);\n\n        public static bool IsInteger(this Type type)\n        {\n            type = type.UnwrapNullableType();\n\n            return (type == typeof(int))\n                   || (type == typeof(long))\n                   || (type == typeof(short))\n                   || (type == typeof(byte))\n                   || (type == typeof(uint))\n                   || (type == typeof(ulong))\n                   || (type == typeof(ushort))\n                   || (type == typeof(sbyte))\n                   || (type == typeof(char));\n        }\n\n        public static PropertyInfo GetAnyProperty(this Type type, string name)\n        {\n            var props = type.GetRuntimeProperties().Where(p => p.Name == name).ToList();\n            if (props.Count > 1)\n            {\n                throw new AmbiguousMatchException();\n            }\n\n            return props.SingleOrDefault();\n        }\n\n        private static bool IsNonIntegerPrimitive(this Type type)\n        {\n            type = type.UnwrapNullableType();\n\n            return (type == typeof(bool))\n                   || (type == typeof(byte[]))\n                   || (type == typeof(DateTime))\n                   || (type == typeof(DateTimeOffset))\n                   || (type == typeof(decimal))\n                   || (type == typeof(double))\n                   || (type == typeof(float))\n                   || (type == typeof(Guid))\n                   || (type == typeof(string))\n                   || (type == typeof(TimeSpan))\n                   || type.GetTypeInfo().IsEnum;\n        }\n\n        public static bool IsPrimitive(this Type type)\n            => type.IsInteger() || type.IsNonIntegerPrimitive();\n\n        public static bool IsInstantiable(this Type type) => IsInstantiable(type.GetTypeInfo());\n\n        private static bool IsInstantiable(TypeInfo type)\n            => !type.IsAbstract\n               && !type.IsInterface\n               && (!type.IsGenericType || !type.IsGenericTypeDefinition);\n\n        public static bool IsGrouping(this Type type) => IsGrouping(type.GetTypeInfo());\n\n        private static bool IsGrouping(TypeInfo type)\n            => type.IsGenericType\n               && (type.GetGenericTypeDefinition() == typeof(IGrouping<,>)\n                   || type.GetGenericTypeDefinition() == typeof(IAsyncGrouping<,>));\n\n        public static Type UnwrapEnumType(this Type type)\n        {\n            var isNullable = type.IsNullableType();\n            var underlyingNonNullableType = isNullable ? type.UnwrapNullableType() : type;\n            if (!underlyingNonNullableType.GetTypeInfo().IsEnum)\n            {\n                return type;\n            }\n\n            var underlyingEnumType = Enum.GetUnderlyingType(underlyingNonNullableType);\n            return isNullable ? MakeNullable(underlyingEnumType) : underlyingEnumType;\n        }\n\n        public static Type GetSequenceType(this Type type)\n        {\n            var sequenceType = TryGetSequenceType(type);\n            if (sequenceType == null)\n            {\n                // TODO: Add exception message\n                throw new ArgumentException();\n            }\n\n            return sequenceType;\n        }\n\n        public static Type TryGetSequenceType(this Type type)\n            => type.IsArray\n                ? type.GetElementType()\n                : type.TryGetElementType(typeof(IDictionary<,>), 1)\n                   ?? type.TryGetElementType(typeof(IEnumerable<>))\n                   ?? type.TryGetElementType(typeof(IAsyncEnumerable<>));\n\n        public static Type TryGetElementType(this Type type, Type interfaceOrBaseType, int elementIndex = 0)\n        {\n            if (!type.GetTypeInfo().IsGenericTypeDefinition)\n            {\n                var types = GetGenericTypeImplementations(type, interfaceOrBaseType).ToList();\n\n                return types.Count == 1 ? types[0].GetTypeInfo().GenericTypeArguments[elementIndex] : null;\n            }\n\n            return null;\n        }\n\n        public static IEnumerable<Type> GetGenericTypeImplementations(this Type type, Type interfaceOrBaseType)\n        {\n            var typeInfo = type.GetTypeInfo();\n            if (!typeInfo.IsGenericTypeDefinition)\n            {\n                return (interfaceOrBaseType.GetTypeInfo().IsInterface ? typeInfo.ImplementedInterfaces : type.GetBaseTypes())\n                    .Union(new[] { type })\n                    .Where(\n                        t => t.GetTypeInfo().IsGenericType\n                             && (t.GetGenericTypeDefinition() == interfaceOrBaseType));\n            }\n\n            return Enumerable.Empty<Type>();\n        }\n\n        public static IEnumerable<Type> GetImplementationTypes(this Type type, Type interfaceOrBaseType)\n        {\n            TypeInfo typeInfo = type.GetTypeInfo();\n            return (interfaceOrBaseType.GetTypeInfo().IsInterface ? typeInfo.ImplementedInterfaces : type.GetBaseTypes())\n                .Union(new[] { type })\n                .Where(\n                    t => t.GetTypeInfo().IsGenericType\n                         && (t.GetGenericTypeDefinition() == interfaceOrBaseType));\n        }\n\n        public static Type GetImplementationType(this Type type, Type interfaceOrBaseType)\n            => type.GetGenericTypeImplementations(interfaceOrBaseType)\n                .FirstOrDefault();\n\n        public static bool TryGetImplementationType(this Type type, Type interfaceOrBaseType, out Type implementedInterfaceType)\n            => (implementedInterfaceType = type.GetImplementationType(interfaceOrBaseType)) != null;\n\n        public static IEnumerable<Type> GetBaseTypes(this Type type)\n        {\n            type = type.GetTypeInfo().BaseType;\n\n            while (type != null)\n            {\n                yield return type;\n\n                type = type.GetTypeInfo().BaseType;\n            }\n        }\n\n        public static IEnumerable<Type> GetTypesInHierarchy(this Type type)\n        {\n            while (type != null)\n            {\n                yield return type;\n\n                type = type.GetTypeInfo().BaseType;\n            }\n        }\n\n        public static ConstructorInfo GetDeclaredConstructor(this Type type, Type[] types)\n        {\n            types = types ?? new Type[0];\n\n            return type.GetTypeInfo().DeclaredConstructors\n                .SingleOrDefault(\n                    c => !c.IsStatic\n                         && c.GetParameters().Select(p => p.ParameterType).SequenceEqual(types));\n        }\n\n        public static IEnumerable<PropertyInfo> GetPropertiesInHierarchy(this Type type, string name)\n        {\n            do\n            {\n                var typeInfo = type.GetTypeInfo();\n                var propertyInfo = typeInfo.GetDeclaredProperty(name);\n                if (propertyInfo != null\n                    && !(propertyInfo.GetMethod ?? propertyInfo.SetMethod).IsStatic)\n                {\n                    yield return propertyInfo;\n                }\n                type = typeInfo.BaseType;\n            }\n            while (type != null);\n        }\n\n        public static IEnumerable<MemberInfo> GetMembersInHierarchy(this Type type, string name)\n        {\n            // Do the whole hierarchy for properties first since looking for fields is slower.\n            var currentType = type;\n            do\n            {\n                var typeInfo = currentType.GetTypeInfo();\n                var propertyInfo = typeInfo.GetDeclaredProperty(name);\n                if (propertyInfo != null\n                    && !(propertyInfo.GetMethod ?? propertyInfo.SetMethod).IsStatic)\n                {\n                    yield return propertyInfo;\n                }\n                currentType = typeInfo.BaseType;\n            }\n            while (currentType != null);\n\n            currentType = type;\n            do\n            {\n                var fieldInfo = currentType.GetRuntimeFields().FirstOrDefault(f => f.Name == name && !f.IsStatic);\n                if (fieldInfo != null)\n                {\n                    yield return fieldInfo;\n                }\n                currentType = currentType.GetTypeInfo().BaseType;\n            }\n            while (currentType != null);\n        }\n\n        private static readonly Dictionary<Type, object> CommonTypeDictionary = new Dictionary<Type, object>\n        {\n            { typeof(int), default(int) },\n            { typeof(Guid), default(Guid) },\n            { typeof(DateTime), default(DateTime) },\n            { typeof(DateTimeOffset), default(DateTimeOffset) },\n            { typeof(long), default(long) },\n            { typeof(bool), default(bool) },\n            { typeof(double), default(double) },\n            { typeof(short), default(short) },\n            { typeof(float), default(float) },\n            { typeof(byte), default(byte) },\n            { typeof(char), default(char) },\n            { typeof(uint), default(uint) },\n            { typeof(ushort), default(ushort) },\n            { typeof(ulong), default(ulong) },\n            { typeof(sbyte), default(sbyte) }\n        };\n\n        public static object GetDefaultValue(this Type type)\n        {\n            if (!type.GetTypeInfo().IsValueType)\n            {\n                return null;\n            }\n\n            // A bit of perf code to avoid calling Activator.CreateInstance for common types and\n            // to avoid boxing on every call. This is about 50% faster than just calling CreateInstance\n            // for all value types.\n            object value;\n            return CommonTypeDictionary.TryGetValue(type, out value)\n                ? value\n                : Activator.CreateInstance(type);\n        }\n\n        public static IEnumerable<TypeInfo> GetConstructableTypes(this Assembly assembly)\n            => assembly.GetLoadableDefinedTypes().Where(\n                t => !t.IsAbstract\n                     && !t.IsGenericTypeDefinition);\n\n        public static IEnumerable<TypeInfo> GetLoadableDefinedTypes(this Assembly assembly)\n        {\n            try\n            {\n                return assembly.DefinedTypes;\n            }\n            catch (ReflectionTypeLoadException ex)\n            {\n                return ex.Types.Where(t => t != null).Select(IntrospectionExtensions.GetTypeInfo);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Shared/StringBuilderExtensions.cs",
    "content": "// Copyright (c) .NET Foundation. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Collections.Generic;\n\nnamespace System.Text\n{\n    internal static class StringBuilderExtensions\n    {\n        public static StringBuilder AppendJoin(\n            this StringBuilder stringBuilder, IEnumerable<string> values, string separator = \", \")\n            => stringBuilder.AppendJoin(values, (sb, value) => sb.Append(value), separator);\n\n        public static StringBuilder AppendJoin(\n            this StringBuilder stringBuilder, string separator, params string[] values)\n            => stringBuilder.AppendJoin(values, (sb, value) => sb.Append(value), separator);\n\n        public static StringBuilder AppendJoin<T>(\n            this StringBuilder stringBuilder,\n            IEnumerable<T> values,\n            Action<StringBuilder, T> joinAction,\n            string separator = \", \")\n        {\n            var appended = false;\n\n            foreach (var value in values)\n            {\n                joinAction(stringBuilder, value);\n                stringBuilder.Append(separator);\n                appended = true;\n            }\n\n            if (appended)\n            {\n                stringBuilder.Length -= separator.Length;\n            }\n\n            return stringBuilder;\n        }\n\n        public static StringBuilder AppendJoin<T, TParam>(\n            this StringBuilder stringBuilder,\n            IEnumerable<T> values,\n            TParam param,\n            Action<StringBuilder, T, TParam> joinAction,\n            string separator = \", \")\n        {\n            var appended = false;\n\n            foreach (var value in values)\n            {\n                joinAction(stringBuilder, value, param);\n                stringBuilder.Append(separator);\n                appended = true;\n            }\n\n            if (appended)\n            {\n                stringBuilder.Length -= separator.Length;\n            }\n\n            return stringBuilder;\n        }\n\n        public static StringBuilder AppendJoin<T, TParam1, TParam2>(\n            this StringBuilder stringBuilder,\n            IEnumerable<T> values,\n            TParam1 param1,\n            TParam2 param2,\n            Action<StringBuilder, T, TParam1, TParam2> joinAction,\n            string separator = \", \")\n        {\n            var appended = false;\n\n            foreach (var value in values)\n            {\n                joinAction(stringBuilder, value, param1, param2);\n                stringBuilder.Append(separator);\n                appended = true;\n            }\n\n            if (appended)\n            {\n                stringBuilder.Length -= separator.Length;\n            }\n\n            return stringBuilder;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Conventions/AbstractClassConventionTest.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson.Serialization;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Conventions\n{\n    public class AbstractClassConventionTest\n    {\n        [Theory]\n        [InlineData(typeof(Animal))]\n        [InlineData(typeof(Tiger))]\n        [InlineData(typeof(PolarBear))]\n        [InlineData(typeof(Otter))]\n        [InlineData(typeof(SeaOtter))]\n        [InlineData(typeof(EurasianOtter))]\n        [InlineData(typeof(Employee))]\n        public void Sets_is_root_class_and_discriminator_required_true_for_abstract_type(Type type)\n        {\n            var classMap = new BsonClassMap(type);\n            var abstractClassMapConvention = new AbstractBaseClassConvention();\n            abstractClassMapConvention.Apply(classMap);\n            Assert.Equal(type.GetTypeInfo().IsAbstract, classMap.DiscriminatorIsRequired);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Conventions/IgnoreEmptyEnumerablesConventionTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson.Serialization;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Conventions\n{\n    public class IgnoreEmptyEnumerablesConventionTests\n    {\n        [Fact]\n        public void Should_not_serialize_empty_enumerables()\n        {\n            var bsonClassMap = new BsonClassMap<Employee>();\n            BsonMemberMap bsonMemberMap = bsonClassMap.MapMember(e => e.Specialties);\n            var ignoreEmptyEnumerableConvention = new IgnoreEmptyEnumerablesConvention();\n            ignoreEmptyEnumerableConvention.Apply(bsonMemberMap);\n            var employee = new Employee();\n            employee.Specialties.Clear();\n            Assert.False(bsonMemberMap.ShouldSerialize(employee, employee.Specialties));\n        }\n\n        [Fact]\n        public void Should_serialize_non_empty_enumerables()\n        {\n            var bsonClassMap = new BsonClassMap<Employee>();\n            BsonMemberMap bsonMemberMap = bsonClassMap.MapMember(e => e.Specialties);\n            var ignoreEmptyEnumerableConvention = new IgnoreEmptyEnumerablesConvention();\n            ignoreEmptyEnumerableConvention.Apply(bsonMemberMap);\n            var employee = new Employee\n            {\n                Specialties =\n                {\n                    new Specialty { AnimalType = nameof(Tiger), Task = ZooTask.Feeding },\n                    new Specialty { AnimalType = nameof(PolarBear), Task = ZooTask.Feeding },\n                    new Specialty { AnimalType = nameof(Otter), Task = ZooTask.Feeding }\n                }\n            };\n            Assert.True(bsonMemberMap.ShouldSerialize(employee, employee.Specialties));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Conventions/IgnoreNullOrEmptyStringsConventionTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson.Serialization;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Conventions\n{\n    public class IgnoreNullOrEmptyStringsConventionTests\n    {\n        [Theory]\n        [InlineData(null)]\n        [InlineData(\"\")]\n        [InlineData(\" \\t\\v\\r\\n\")]\n        [InlineData(\"TestData\")]\n        public void Should_not_serialize_null_or_empty_strings(string value)\n        {\n            var bsonClassMap = new BsonClassMap<Employee>();\n            BsonMemberMap bsonMemberMap = bsonClassMap.MapMember(e => e.FirstName);\n            var ignoreNullOrEmptyStringsConvention = new IgnoreNullOrEmptyStringsConvention();\n            ignoreNullOrEmptyStringsConvention.Apply(bsonMemberMap);\n            var employee = new Employee\n            {\n                FirstName = value\n            };\n            Assert.Equal(!string.IsNullOrEmpty(value), bsonMemberMap.ShouldSerialize(employee, employee.FirstName));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Conventions/KeyAttributeConventionTests.cs",
    "content": "﻿using System;\nusing System.ComponentModel.DataAnnotations;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson.Serialization;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Conventions\n{\n    public class KeyAttributeConventionTests\n    {\n        [Fact]\n        public void Should_set_id_member_when_key_attribute_present()\n        {\n            MemberInfo memberInfo = typeof(Animal)\n                .GetTypeInfo()\n                .GetProperty(nameof(Animal.AnimalId));\n            Assert.NotNull(memberInfo);\n            Assert.True(memberInfo.IsDefined(typeof(KeyAttribute), false));\n            var keyAttributeConvention = new KeyAttributeConvention();\n            var bsonClasspMap = new BsonClassMap<Animal>();\n            BsonMemberMap bsonMemberMap = bsonClasspMap.MapMember(memberInfo);\n            keyAttributeConvention.Apply(bsonMemberMap);\n            Assert.Same(bsonMemberMap, bsonClasspMap.IdMemberMap);\n        }\n\n        [Theory]\n        [InlineData(nameof(Employee.FirstName))]\n        [InlineData(nameof(Employee.Age))]\n        public void Should_not_set_id_member_when_key_attribute_present(string memberName)\n        {\n            MemberInfo memberInfo = typeof(Employee)\n                .GetTypeInfo()\n                .GetProperty(memberName);\n            Assert.NotNull(memberInfo);\n            Assert.False(memberInfo.IsDefined(typeof(KeyAttribute), false));\n            var keyAttributeConvention = new KeyAttributeConvention();\n            var bsonClasspMap = new BsonClassMap<Employee>();\n            BsonMemberMap bsonMemberMap = bsonClasspMap.MapMember(memberInfo);\n            keyAttributeConvention.Apply(bsonMemberMap);\n            Assert.NotSame(bsonMemberMap, bsonClasspMap.IdMemberMap);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/EntityFrameworkConventionPackTests.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Conventions;\nusing MongoDB.Bson.Serialization.Conventions;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter\n{\n    public class EntityFrameworkConventionPackTests\n    {\n        [Theory]\n        [InlineData(typeof(AbstractBaseClassConvention))]\n        [InlineData(typeof(KeyAttributeConvention))]\n        [InlineData(typeof(NavigationSrializationMemberMapConvention))]\n        [InlineData(typeof(NotMappedAttributeConvention))]\n        public void Singleton_contains_default_convention_set(Type conventionType)\n        {\n            ConventionPack conventionPack = EntityFrameworkConventionPack.Instance;\n            Assert.Contains(conventionPack, conventionType.GetTypeInfo().IsInstanceOfType);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Serialization/BsonSerializerExtensionsTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Collections.ObjectModel;\nusing System.Linq;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson;\nusing MongoDB.Bson.Serialization;\nusing MongoDB.Bson.Serialization.Conventions;\nusing MongoDB.Bson.Serialization.Serializers;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Serialization\n{\n    public class BsonSerializerExtensionsTests : IClassFixture<ZooEntityFixture>\n    {\n        private readonly ZooEntities _zooEntities;\n\n        public BsonSerializerExtensionsTests(ZooEntityFixture zooEntityFixture)\n        {\n            _zooEntities = zooEntityFixture.Entities;\n        }\n\n        private static readonly IDiscriminatorConvention DiscriminatorConvention =\n            BsonSerializer.LookupDiscriminatorConvention(typeof(Animal));\n\n        private static string GetDiscriminator(Animal animal)\n            => $\"\\\"{DiscriminatorConvention.ElementName}\\\" : {DiscriminatorConvention.GetDiscriminator(typeof(Animal), animal.GetType()).ToJson()}\";\n\n        private static readonly string[] DenormalizedMemberNames =\n        {\n            nameof(Animal.Age),\n            nameof(Animal.Height),\n            nameof(Animal.Weight)\n        };\n\n        private static void VerifyChildSerialier(IBsonSerializer bsonSerializer)\n        {\n            var childSerializerConfigurable = bsonSerializer as IChildSerializerConfigurable;\n            while (childSerializerConfigurable?.ChildSerializer is IChildSerializerConfigurable)\n            {\n                childSerializerConfigurable = (IChildSerializerConfigurable)childSerializerConfigurable.ChildSerializer;\n            }\n            var navigationBsonDocumentSerializer =\n                childSerializerConfigurable?.ChildSerializer as DenormalizingBsonClassMapSerializer<Animal>;\n            Assert.NotNull(navigationBsonDocumentSerializer);\n            IEnumerable<string> denormalizedMemberNames = navigationBsonDocumentSerializer.DenormalizedMemberMaps\n                .Select(bsonMemberMap => bsonMemberMap.MemberName)\n                .OrderBy(memberName => memberName)\n                .ToList();\n            Assert.Equal(DenormalizedMemberNames, denormalizedMemberNames);\n        }\n\n        [Theory]\n        [InlineData(typeof(Queue<Animal>))]\n        [InlineData(typeof(Stack<Animal>))]\n        [InlineData(typeof(SortedSet<Animal>))]\n        [InlineData(typeof(List<Animal>))]\n        [InlineData(typeof(HashSet<Animal>))]\n        public void Can_denormalize_enumerables(Type enumerableType)\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(enumerableType);\n            IBsonSerializer bsonSerializer = defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            VerifyChildSerialier(bsonSerializer);\n\n            var originalEnumerable = (IEnumerable<Animal>)(enumerableType == typeof(SortedSet<Animal>)\n                ? Activator.CreateInstance(enumerableType, _zooEntities.Animals, new AnimalComparer())\n                : Activator.CreateInstance(enumerableType, _zooEntities.Animals));\n            if (enumerableType == typeof(Stack<Animal>))\n            {\n                originalEnumerable = originalEnumerable.Reverse();\n            }\n            IEnumerable<string> documents = originalEnumerable\n                .Select(animal => $\"{{ \\\"_id\\\" : ObjectId(\\\"{animal.AnimalId}\\\"), {GetDiscriminator(animal)}, \\\"Age\\\" : \\\"{animal.Age}\\\", \\\"Height\\\" : \\\"{animal.Height}\\\", \\\"Weight\\\" : \\\"{animal.Weight}\\\" }}\");\n            string expectedDocument =\n                $\"[{string.Join(\", \", documents)}]\";\n\n            var testEnumerable = (IEnumerable<Animal>)(enumerableType == typeof(SortedSet<Animal>)\n                ? Activator.CreateInstance(enumerableType, _zooEntities.Animals, new AnimalComparer())\n                : Activator.CreateInstance(enumerableType, _zooEntities.Animals));\n\n            Assert.Equal(expectedDocument, testEnumerable.ToJson(enumerableType, serializer: bsonSerializer));\n        }\n\n        [Theory]\n        [InlineData(typeof(IEnumerable<Animal>), typeof(List<Animal>))]\n        [InlineData(typeof(ICollection<Animal>), typeof(List<Animal>))]\n        [InlineData(typeof(IList<Animal>), typeof(List<Animal>))]\n        [InlineData(typeof(ISet<Animal>), typeof(HashSet<Animal>))]\n        public void Can_denormalize_enumerable_interfaces(Type enumerableInterface, Type concreteType)\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(enumerableInterface);\n            IBsonSerializer bsonSerializer = defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            VerifyChildSerialier(bsonSerializer);\n\n            var enumerable = (IEnumerable<Animal>)Activator.CreateInstance(concreteType, _zooEntities.Animals);\n            IEnumerable<string> documents = enumerable\n                .Select(animal => $\"{{ \\\"_id\\\" : ObjectId(\\\"{animal.AnimalId}\\\"), {GetDiscriminator(animal)}, \\\"Age\\\" : \\\"{animal.Age}\\\", \\\"Height\\\" : \\\"{animal.Height}\\\", \\\"Weight\\\" : \\\"{animal.Weight}\\\" }}\");\n            string expectedDocument =\n                $\"[{string.Join(\", \", documents)}]\";\n\n            Assert.Equal(expectedDocument, enumerable.ToJson(enumerableInterface, serializer: bsonSerializer));\n        }\n\n        [Theory]\n        [InlineData(typeof(Dictionary<string, Animal>))]\n        [InlineData(typeof(IDictionary<string, Animal>))]\n        public void Can_denormalize_dictionaries(Type type)\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(type);\n            IBsonSerializer bsonSerializer = defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            VerifyChildSerialier(bsonSerializer);\n\n            Dictionary<string, Animal> dictionary = _zooEntities.Animals.ToDictionary(animal => animal.Name);\n            IEnumerable<string> documents = dictionary\n                .OrderBy(kvp => kvp.Key)\n                .ThenBy(kvp => kvp.Value.Height)\n                .Select(kvp => kvp.Value)\n                .Select(animal => $\"\\\"{animal.Name}\\\" : {{ \\\"_id\\\" : ObjectId(\\\"{animal.AnimalId}\\\"), {GetDiscriminator(animal)}, \\\"Age\\\" : \\\"{animal.Age}\\\", \\\"Height\\\" : \\\"{animal.Height}\\\", \\\"Weight\\\" : \\\"{animal.Weight}\\\" }}\");\n            string expectedDocument =\n                $\"{{ {string.Join(\", \", documents)} }}\";\n\n            Assert.Equal(expectedDocument, dictionary.ToJson(type, serializer: bsonSerializer));\n        }\n\n        [Theory]\n        [InlineData(typeof(Animal[]))]\n        [InlineData(typeof(Animal[,]))]\n        [InlineData(typeof(Animal[,,]))]\n        public void Can_denormalize_array(Type type)\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(type);\n            IBsonSerializer bsonSerializer = defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            VerifyChildSerialier(bsonSerializer);\n        }\n\n        [Fact]\n        public void Can_denormalize_ReadOnlyCollection()\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(typeof(ReadOnlyCollection<Animal>));\n            var bsonSerializer = (ReadOnlyCollectionSerializer<Animal>)defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            Assert.IsType<DenormalizingBsonClassMapSerializer<Animal>>(bsonSerializer.ItemSerializer);\n\n            var readOnlyCollection = new ReadOnlyCollection<Animal>(_zooEntities.Animals.ToList());\n            IEnumerable<string> documents = readOnlyCollection\n                .Select(animal => $\"{{ \\\"_id\\\" : ObjectId(\\\"{animal.AnimalId}\\\"), {GetDiscriminator(animal)}, \\\"Age\\\" : \\\"{animal.Age}\\\", \\\"Height\\\" : \\\"{animal.Height}\\\", \\\"Weight\\\" : \\\"{animal.Weight}\\\" }}\");\n            string expectedDocument =\n                $\"[{string.Join(\", \", documents)}]\";\n\n            Assert.Equal(expectedDocument, readOnlyCollection.ToJson(typeof(ReadOnlyCollection<Animal>), serializer: bsonSerializer));\n        }\n\n        [Fact]\n        public void Can_denormalize_ReadOnlyCollection_sub_class()\n        {\n            IBsonSerializer defaultSerializer = BsonSerializer.LookupSerializer(typeof(ReadOnlyObservableCollection<Animal>));\n            var bsonSerializer = (ReadOnlyCollectionSubclassSerializer< ReadOnlyObservableCollection<Animal>, Animal>)defaultSerializer\n                .AsDenormalizingBsonClassMapSerializer(DenormalizedMemberNames);\n            Assert.NotNull(bsonSerializer);\n            Assert.IsType(defaultSerializer.GetType(), bsonSerializer);\n            Assert.IsType<DenormalizingBsonClassMapSerializer<Animal>>(bsonSerializer.ItemSerializer);\n\n            var observableCollection = new ObservableCollection<Animal>(_zooEntities.Animals.ToList());\n            var readOnlyObservableCollection = new ReadOnlyObservableCollection<Animal>(observableCollection);\n            IEnumerable<string> documents = readOnlyObservableCollection\n                .Select(animal => $\"{{ \\\"_id\\\" : ObjectId(\\\"{animal.AnimalId}\\\"), {GetDiscriminator(animal)}, \\\"Age\\\" : \\\"{animal.Age}\\\", \\\"Height\\\" : \\\"{animal.Height}\\\", \\\"Weight\\\" : \\\"{animal.Weight}\\\" }}\");\n            string expectedDocument =\n                $\"[{string.Join(\", \", documents)}]\";\n\n            Assert.Equal(expectedDocument, readOnlyObservableCollection.ToJson(typeof(ReadOnlyObservableCollection<Animal>), serializer: bsonSerializer));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Serialization/DenormalizingBsonClassMapSerializerTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Adapter.Serialization;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing MongoDB.Bson;\nusing MongoDB.Bson.IO;\nusing MongoDB.Bson.Serialization;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Serialization\n{\n    public class DenormalizingBsonClassMapSerializerTests : IClassFixture<ZooEntityFixture>\n    {       \n        private static readonly string[] DenormalizedMemberNames =\n        {\n            nameof(Animal.Age),\n            nameof(Animal.Height),\n            nameof(Animal.Weight)\n        };\n\n        private readonly ZooEntities _zooEntities;\n\n        public DenormalizingBsonClassMapSerializerTests(ZooEntityFixture zooEntityFixture)\n        {\n            _zooEntities = zooEntityFixture.Entities;\n        }\n\n        [Fact]\n        public void Correctly_Serializes_Entity_Reference()\n        {\n            BsonClassMap<Animal> animalClassMap = (BsonClassMap<Animal>) BsonClassMap.LookupClassMap(typeof(Animal));\n            var animalNavigationSerializer = new DenormalizingBsonClassMapSerializer<Animal>(animalClassMap);\n            Tiger tigger = _zooEntities.Tigger;\n            string tiggerJson = tigger.ToJson(typeof(Animal), serializer: animalNavigationSerializer);\n            Assert.Equal($\"{{ \\\"_id\\\" : ObjectId(\\\"{tigger.AnimalId}\\\"), \\\"_t\\\" : [\\\"Animal\\\", \\\"panthera tigris\\\"] }}\", tiggerJson);\n            Assert.DoesNotContain($\"\\\"Name\\\": \\\"${tigger.Name}\\\"\", tiggerJson);\n            Assert.DoesNotContain($\"\\\"Age\\\": \\\"${tigger.Age}\\\"\", tiggerJson);\n            Assert.DoesNotContain($\"\\\"Height\\\": \\\"${tigger.Height}\\\"\", tiggerJson);\n            Assert.DoesNotContain($\"\\\"Weight\\\": \\\"${tigger.Weight}\\\"\", tiggerJson);\n        }\n\n        [Fact]\n        public void Correctly_Serializes_Entity_Reference_With_Denormalized_Properties()\n        {\n            BsonClassMap<Animal> animalClassMap = (BsonClassMap<Animal>)BsonClassMap.LookupClassMap(typeof(Animal));\n            var animalNavigationSerializer = new DenormalizingBsonClassMapSerializer<Animal>(animalClassMap, DenormalizedMemberNames);\n            Animal tigger = _zooEntities.Tigger;\n            string tiggerJson = tigger.ToJson(typeof(Animal), serializer: animalNavigationSerializer);\n            Assert.Equal($\"{{ \\\"_id\\\" : ObjectId(\\\"{tigger.AnimalId}\\\"), \\\"_t\\\" : [\\\"Animal\\\", \\\"panthera tigris\\\"], \\\"Age\\\" : \\\"{tigger.Age}\\\", \\\"Height\\\" : \\\"{tigger.Height}\\\", \\\"Weight\\\" : \\\"{tigger.Weight}\\\" }}\", tiggerJson);\n            Assert.DoesNotContain($\"\\\"Name\\\": \\\"${tigger.Name}\\\"\", tiggerJson);\n        }\n\n        [Fact]\n        public void Deserialize_uses_default_deserializer()\n        {\n            BsonClassMap<Animal> animalClassMap = (BsonClassMap<Animal>)BsonClassMap.LookupClassMap(typeof(Animal));\n            Animal tigger = _zooEntities.Tigger;\n            BsonDocument bsonDocument = tigger.ToBsonDocument();\n\n            var animalNavigationSerializer = new DenormalizingBsonClassMapSerializer<Animal>(animalClassMap);\n            Animal animal;\n            using (var bsonReader = new BsonDocumentReader(bsonDocument))\n            {\n                BsonDeserializationContext bsonDeserializationContext = BsonDeserializationContext.CreateRoot(bsonReader);\n                var bsonDeserializationArgs = new BsonDeserializationArgs() { NominalType = typeof(Animal) };\n                animal = animalNavigationSerializer.Deserialize(bsonDeserializationContext, bsonDeserializationArgs);\n            }\n            Assert.Equal(tigger, animal, new AnimalEqualityComparer());\n        }\n\n        [Fact]\n        public void Deserialize_can_deserialize_partial_class()\n        {\n            BsonClassMap<Animal> animalClassMap = (BsonClassMap<Animal>)BsonClassMap.LookupClassMap(typeof(Animal));\n            var animalNavigationSerializer = new DenormalizingBsonClassMapSerializer<Animal>(animalClassMap);\n            Animal tigger = _zooEntities.Tigger;\n            BsonDocument bsonDocument = tigger.ToBsonDocument(serializer: animalNavigationSerializer);\n            Animal animal;\n            using (var bsonReader = new BsonDocumentReader(bsonDocument))\n            {\n                BsonDeserializationContext bsonDeserializationContext = BsonDeserializationContext.CreateRoot(bsonReader);\n                var bsonDeserializationArgs = new BsonDeserializationArgs() { NominalType = typeof(Animal) };\n                animal = animalNavigationSerializer.Deserialize(bsonDeserializationContext, bsonDeserializationArgs);\n            }\n            Assert.NotNull(animal);\n            Assert.IsType<Tiger>(animal);\n            Assert.Equal(tigger.AnimalId, animal.AnimalId);\n            Assert.Null(animal.Name);\n            Assert.Equal(0, animal.Age);\n            Assert.Equal(0, animal.Height);\n            Assert.Equal(0, animal.Weight);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Adapter/Update/MongoDbWriteModelFactoryTests.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Bson;\nusing MongoDB.Driver;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Adapter.Update\n{\n    public class MongoDbWriteModelFactoryTests\n    {\n        private IUpdateEntry GetUpdateEntry(EntityState entityState, object entity)\n        {\n            var zooDbContext = new ZooDbContext();\n            var entityEntry = zooDbContext.Add(entity);\n\n            entityEntry.State = entityState;\n            return ((IInfrastructure<InternalEntityEntry>)entityEntry).Instance;\n        }\n\n        private IMongoDbWriteModelFactory<TEntity> CreateMongoDbWriteModelFactory<TEntity>(IUpdateEntry updateEntry)\n            => new MongoDbWriteModelFactorySelector(\n                    new ValueGeneratorSelector(\n                        new ValueGeneratorSelectorDependencies(\n                            new ValueGeneratorCache(\n                                new ValueGeneratorCacheDependencies()))),\n                    new MongoDbWriteModelFactoryCache())\n                .Select<TEntity>(updateEntry);\n\n        [Fact]\n        public void Creates_insert_one_model_for_added_entity()\n        {\n            var employee = new Employee();\n            var updateEntry = GetUpdateEntry(EntityState.Added, employee);\n            var mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Employee>(updateEntry);\n            var insertOneModel = mongoDbWriteModelFactory.CreateWriteModel(updateEntry) as InsertOneModel<Employee>;\n            Assert.NotNull(insertOneModel);\n            Assert.Same(employee, insertOneModel.Document);\n        }\n\n        [Fact]\n        public void Creates_insert_one_model_for_added_entity_and_updates_concurrency_field()\n        {\n            var tiger = new Tiger() { Name = \"Pantheris\" };\n            Assert.Null(tiger.ConcurrencyField);\n            var entityEntry = GetUpdateEntry(EntityState.Added, tiger);\n            var mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Animal>(entityEntry);\n            var insertOneModel = mongoDbWriteModelFactory.CreateWriteModel(entityEntry) as InsertOneModel<Animal>;\n            Assert.NotNull(insertOneModel);\n            Assert.Same(tiger, insertOneModel.Document);\n            Assert.NotNull(tiger.ConcurrencyField);\n            Assert.NotEmpty(tiger.ConcurrencyField);\n        }\n\n        [Fact]\n        public void Creates_ReplaceOneModel_for_modified_entity_referencing_only_id()\n        {\n            var employee = new Employee();\n            var updateEntry = GetUpdateEntry(EntityState.Modified, employee);\n            employee.FirstName = \"Bob\";\n            IMongoDbWriteModelFactory<Employee> mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Employee>(updateEntry);\n\n            ReplaceOneModel<Employee> replaceOneModel = mongoDbWriteModelFactory.CreateWriteModel(updateEntry) as ReplaceOneModel<Employee>;\n            FilterDefinition<Employee> filter = Builders<Employee>.Filter.Eq(record => record.EmployeeId, employee.EmployeeId);\n            Assert.NotNull(replaceOneModel);\n            Assert.Equal(replaceOneModel.Filter.ToJson(), filter.ToJson());\n            Assert.Same(employee, replaceOneModel.Replacement);\n        }\n\n        [Fact]\n        public void Creates_ReplaceOneModel_for_modified_entity_referencing_concurrency_field()\n        {\n            var tiger = new Tiger() { Name = \"Pantheris\" };\n            var updtaeEntry = GetUpdateEntry(EntityState.Modified, tiger);\n            var concurrencyToken = Guid.NewGuid().ToString();\n            typeof(Animal).GetProperty(nameof(Animal.ConcurrencyField)).SetValue(tiger, concurrencyToken);\n\n            Assert.Equal(concurrencyToken, tiger.ConcurrencyField);\n            var mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Animal>(updtaeEntry);\n            var replaceOneModel = mongoDbWriteModelFactory.CreateWriteModel(updtaeEntry) as ReplaceOneModel<Animal>;\n            FilterDefinition<Animal> filter = Builders<Animal>.Filter.And(\n                Builders<Animal>.Filter.Eq(record => record.AnimalId, tiger.AnimalId),\n                Builders<Animal>.Filter.Eq(record => record.ConcurrencyField, tiger.ConcurrencyField));\n\n            Assert.NotNull(replaceOneModel);\n            Assert.Equal(replaceOneModel.Filter.ToJson(), filter.ToJson());\n            Assert.Same(tiger, replaceOneModel.Replacement);\n        }\n\n        [Fact]\n        public void Creates_DeleteOneModel_for_deleted_entity_referencing_only_id()\n        {\n            var employee = new Employee();\n            var updateEntry = GetUpdateEntry(EntityState.Deleted, employee);\n            var mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Employee>(updateEntry);\n            var deleteOneModel = mongoDbWriteModelFactory.CreateWriteModel(updateEntry) as DeleteOneModel<Employee>;\n            FilterDefinition<Employee> filter = Builders<Employee>.Filter.Eq(record => record.EmployeeId, employee.EmployeeId);\n            Assert.NotNull(deleteOneModel);\n            Assert.Equal(filter.ToJson(), deleteOneModel.Filter.ToJson());\n        }\n\n        [Fact]\n        public void Creates_DeleteOneModel_for_deleted_entity_referencing_concurrency_field()\n        {\n            var tiger = new Tiger() { Name = \"Pantheris\" };\n            var concurrencyToken = Guid.NewGuid().ToString();\n\n            typeof(Animal).GetProperty(nameof(Animal.ConcurrencyField)).SetValue(tiger, concurrencyToken);\n\n            Assert.Equal(concurrencyToken, tiger.ConcurrencyField);\n            var updateEntry = GetUpdateEntry(EntityState.Deleted, tiger);\n            var mongoDbWriteModelFactory = CreateMongoDbWriteModelFactory<Animal>(updateEntry);\n            var deleteOneModel = mongoDbWriteModelFactory.CreateWriteModel(updateEntry) as DeleteOneModel<Animal>;\n            FilterDefinition<Animal> filter = Builders<Animal>.Filter.And(\n                Builders<Animal>.Filter.Eq(record => record.AnimalId, tiger.AnimalId),\n                Builders<Animal>.Filter.Eq(record => record.ConcurrencyField, tiger.ConcurrencyField));\n            Assert.NotNull(deleteOneModel);\n            Assert.Equal(filter.ToJson(), deleteOneModel.Filter.ToJson());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/ApiConsistencyTest.cs",
    "content": "//using System.Reflection;\n//using Microsoft.EntityFrameworkCore.Storage;\n//using Microsoft.EntityFrameworkCore.Tests;\n\n//namespace Blueshift.EntityFrameworkCore.MongoDB.Tests\n//{\n//    public class ApiConsistencyTest : ApiConsistencyTestBase\n//    {\n//        protected override Assembly TargetAssembly => typeof(MongoDbDatabase).GetTypeInfo().Assembly;\n//    }\n//}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Blueshift.EntityFrameworkCore.MongoDB.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestFrameworks)</TargetFrameworks>\n    <TestGroupName>MongoDb.EFCore.Tests</TestGroupName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\..\\src\\Shared\\CodeAnnotations.cs\" Link=\"CodeAnnotations.cs\" />\n    <Compile Include=\"..\\..\\src\\Shared\\PropertyInfoExtensions.cs\" Link=\"PropertyInfoExtensions.cs\" />\n    <Compile Include=\"..\\..\\src\\Shared\\SharedTypeExtensions.cs\" Link=\"SharedTypeExtensions.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.Specification.Tests\" Version=\"$(MicrosoftEntityFrameworkCoreSpecificationTestsPackageVersion)\" NoWarn=\"KRB4002\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Blueshift.EntityFrameworkCore.MongoDB.SampleDomain\\Blueshift.EntityFrameworkCore.MongoDB.SampleDomain.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Blueshift.EntityFrameworkCore.MongoDB\\Blueshift.EntityFrameworkCore.MongoDB.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Service Include=\"{82a7f48d-3b50-4b1e-b82e-3ada8210c358}\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Metadata/Conventions/MongoDatabaseConventionTests.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.Annotations;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Metadata.Conventions\n{\n    public class MongoDatabaseConventionTests\n    {\n        [Theory]\n        [InlineData(typeof(ZooDb), \"zoo\")]\n        [InlineData(typeof(ZooDbContext), \"zoo\")]\n        [InlineData(typeof(ZooContext), \"zoo\")]\n        [InlineData(typeof(ZooMongo), \"zoo\")]\n        [InlineData(typeof(ZooMongoDb), \"zoo\")]\n        [InlineData(typeof(ZooMongoDbContext), \"zoo\")]\n        [InlineData(typeof(ZooMongoContext), \"zoo\")]\n        [InlineData(typeof(AnnodatedZooContext), \"zoo\")]\n        [InlineData(typeof(DifferentlyAnnodatedZooContext), \"zhou\")]\n        public void Should_set_expected_database_name(Type dbContextType, string expectedName)\n        {\n            DbContext dbContext = (DbContext) Activator.CreateInstance(dbContextType);\n            Assert.Equal(expectedName, dbContext.Model.MongoDb().Database);\n        }\n\n        private class MongoDatabaseAttributeDbContextBase : DbContext\n        {\n            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n            {\n                optionsBuilder\n                    .UseMongoDb(\"mongodb://localhost:27017\");\n                base.OnConfiguring(optionsBuilder);\n            }\n        }\n\n        private class ZooDb : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooDbContext : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooContext : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooMongo : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooMongoDb : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooMongoDbContext : MongoDatabaseAttributeDbContextBase { }\n\n        private class ZooMongoContext : MongoDatabaseAttributeDbContextBase { }\n\n        [MongoDatabase(\"zoo\")]\n        private class AnnodatedZooContext : MongoDatabaseAttributeDbContextBase { }\n\n        [MongoDatabase(\"zhou\")]\n        private class DifferentlyAnnodatedZooContext : MongoDatabaseAttributeDbContextBase { }\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Metadata/MongoDbEntityTypeAnnotationsTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Metadata;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Metadata\n{\n    public class MongoDbEntityTypeAnnotationsTests\n    {\n        [Fact]\n        public void Collection_name_is_pluralized_camel_cased_entity_type_by_default()\n        {\n            var model = new Model();\n            var entityType = new EntityType(typeof(Animal), model, ConfigurationSource.Explicit);\n            var mongoDbEntityTypeAnnotations = new MongoDbEntityTypeAnnotations(entityType);\n            Assert.Equal(MongoDbUtilities.Pluralize(MongoDbUtilities.ToLowerCamelCase(nameof(Animal))),\n                mongoDbEntityTypeAnnotations.CollectionName);\n        }\n\n        [Fact]\n        public void Can_write_collection_name()\n        {\n            var collectionName = \"myCollection\";\n            var model = new Model();\n            var entityType = new EntityType(typeof(Animal), model, ConfigurationSource.Explicit);\n            var mongoDbEntityTypeAnnotations = new MongoDbEntityTypeAnnotations(entityType)\n            {\n                CollectionName = collectionName\n            };\n            Assert.Equal(collectionName, mongoDbEntityTypeAnnotations.CollectionName);\n        }\n\n        [Fact]\n        public void Discriminator_is_type_name_by_default()\n        {\n            var model = new Model();\n            var entityType = new EntityType(typeof(Animal), model, ConfigurationSource.Explicit);\n            var mongoDbEntityTypeAnnotations = new MongoDbEntityTypeAnnotations(entityType);\n            Assert.Equal(typeof(Animal).Name, mongoDbEntityTypeAnnotations.Discriminator);\n        }\n\n        [Fact]\n        public void Can_write_discriminator()\n        {\n            var discriminator = \"discriminator\";\n            var model = new Model();\n            var entityType = new EntityType(typeof(Animal), model, ConfigurationSource.Explicit);\n            var mongoDbEntityTypeAnnotations = new MongoDbEntityTypeAnnotations(entityType)\n            {\n                Discriminator = discriminator\n            };\n            Assert.Equal(discriminator, mongoDbEntityTypeAnnotations.Discriminator);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Metadata/MongoDbModelAnnotationsTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Metadata\n{\n    public class MongoDbModelAnnotationsTests\n    {\n        [Fact]\n        public void Database_name_null_by_default()\n        {\n            var mongoDbModelAnnotations = new MongoDbModelAnnotations(new Model());\n            Assert.Null(mongoDbModelAnnotations.Database);\n        }\n\n        [Fact]\n        public void Can_write_database_name()\n        {\n            var mongoDbModelAnnotations = new MongoDbModelAnnotations(new Model()) { Database = \"test\" };\n            Assert.Equal(expected: \"test\", actual: mongoDbModelAnnotations.Database);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/MongoDbContextTestBase.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests\n{\n    public abstract class MongoDbContextTestBase : IDisposable\n    {\n        private const string MongoUrl = \"mongodb://localhost:27017\";\n\n        protected IServiceProvider ServiceProvider;\n\n        protected MongoDbContextTestBase()\n        {\n            ServiceProvider = new ServiceCollection()\n                .AddDbContext<ZooDbContext>(options => options\n                    .UseMongoDb(MongoUrl)\n                    .EnableSensitiveDataLogging(true))\n                .BuildServiceProvider();\n\n            ExecuteUnitOfWork(zooDbContext => zooDbContext.Database.EnsureCreated());\n        }\n\n        public void Dispose()\n        {\n            ExecuteUnitOfWork(zooDbContext => zooDbContext.Database.EnsureDeleted());\n        }\n\n        protected void ExecuteUnitOfWork(Action<ZooDbContext> unitOfWork)\n        {\n            using (IServiceScope serviceScope = ServiceProvider.CreateScope())\n            {\n                ZooDbContext zooDbContext = serviceScope.ServiceProvider.GetService<ZooDbContext>();\n                unitOfWork(zooDbContext);\n            }\n        }\n\n        protected async Task ExecuteUnitOfWorkAsync(Func<ZooDbContext, Task> unitOfWork)\n        {\n            using (IServiceScope serviceScope = ServiceProvider.CreateScope())\n            {\n                ZooDbContext zooDbContext = serviceScope.ServiceProvider.GetService<ZooDbContext>();\n                await unitOfWork(zooDbContext);\n            }\n        }\n\n        protected async Task<TResult> ExecuteUnitOfWorkAsync<TResult>(Func<ZooDbContext, Task<TResult>> unitOfWork)\n        {\n            using (IServiceScope serviceScope = ServiceProvider.CreateScope())\n            {\n                ZooDbContext zooDbContext = serviceScope.ServiceProvider.GetService<ZooDbContext>();\n                return await unitOfWork(zooDbContext);\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/MongoDbContextTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing MongoDB.Driver.Linq;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests\n{\n    public class MongoDbContextTests : MongoDbContextTestBase, IClassFixture<ZooEntityFixture>\n    {\n        private readonly ZooEntities _zooEntities;\n\n        public MongoDbContextTests(ZooEntityFixture zooEntityFixture)\n        {\n            _zooEntities = zooEntityFixture.Entities;\n        }\n\n        [Fact]\n        public async Task Can_query_from_mongodb()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Empty(await zooDbContext.Animals.ToListAsync());\n                Assert.Empty(await zooDbContext.Employees.ToListAsync());\n                Assert.Empty(await zooDbContext.Enclosures.ToListAsync());\n            });\n        }\n\n        [Fact]\n        public async Task Can_write_simple_record()\n        {\n            var employee = new Employee { FirstName = \"Taiga\", LastName = \"Masuta\", Age = 31.7M };\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Add(employee);\n                Assert.Equal(1, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(employee, await zooDbContext.Employees.SingleAsync(), new EmployeeEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_write_complex_record()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Add(_zooEntities.TaigaMasuta);\n                Assert.Equal(\n                    1 + _zooEntities.TaigaMasuta.Manager.DirectReports.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n        }\n\n        [Fact]\n        public async Task Can_write_polymorphic_records()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IList<Animal> queriedEntities = await zooDbContext.Animals\n                    .OrderBy(animal => animal.Name)\n                    .ThenBy(animal => animal.Height)\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Animals,\n                    queriedEntities,\n                    new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_update_existing_entity()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                EntityEntry entityEntry = zooDbContext.Add(_zooEntities.Tigger);\n                Assert.Equal(EntityState.Added, entityEntry.State);\n                Assert.Equal(7, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n                Assert.Equal(EntityState.Unchanged, entityEntry.State);\n                Assert.NotNull(_zooEntities.Tigger.ConcurrencyField);\n\n                Assert.NotNull(entityEntry.OriginalValues[nameof(_zooEntities.Tigger.ConcurrencyField)]);\n\n                _zooEntities.Tigger.Name = \"Tigra\";\n                zooDbContext.ChangeTracker.DetectChanges();\n                Assert.Equal(EntityState.Modified, entityEntry.State);\n                Assert.Equal(1, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Tigger,\n                    await zooDbContext.Animals.OfType<Tiger>().FirstOrDefaultAsync(),\n                    new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_update_sub_document()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                EntityEntry entityEntry = zooDbContext.Add(_zooEntities.TaigaMasuta);\n                Assert.Equal(EntityState.Added, entityEntry.State);\n                Assert.Equal(5, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n                Assert.Equal(EntityState.Unchanged, entityEntry.State);\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Employee taigaMasuta = await zooDbContext.Employees\n                    .FirstAsync(employee => employee.LastName == _zooEntities.TaigaMasuta.LastName\n                                            && employee.FirstName == _zooEntities.TaigaMasuta.FirstName);\n\n                EntityEntry<Employee> entityEntry = zooDbContext.Entry(taigaMasuta);\n\n                Specialty firstSpecialty = taigaMasuta.Specialties[0];\n                EntityEntry<Specialty> specialtyEntry = zooDbContext.Entry(firstSpecialty);\n                Assert.Equal(EntityState.Unchanged, specialtyEntry.State);\n\n                firstSpecialty.AnimalType = nameof(PolarBear);\n\n                zooDbContext.ChangeTracker.DetectChanges();\n\n                Assert.Equal(EntityState.Modified, specialtyEntry.State);\n\n                Assert.Equal(1, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Employee taigaMasuta = await zooDbContext.Employees\n                    .FirstOrDefaultAsync(employee => employee.LastName == _zooEntities.TaigaMasuta.LastName\n                                                     && employee.FirstName == _zooEntities.TaigaMasuta.FirstName\n                                                     && employee.Specialties.Any(specialty =>\n                                                         specialty.AnimalType == nameof(PolarBear)));\n\n                Assert.NotNull(taigaMasuta);\n            });\n        }\n\n        [Fact]\n        public async Task Concurrency_field_prevents_updates()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Add(_zooEntities.Tigger);\n                Assert.Equal(\n                    3 + _zooEntities.TigerEnclosure.WeeklySchedule.Approver.DirectReports.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n                Assert.False(string.IsNullOrWhiteSpace(_zooEntities.Tigger.ConcurrencyField));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                EntityEntry entityEntry = zooDbContext.Update(_zooEntities.Tigger);\n                string newConcurrencyToken = Guid.NewGuid().ToString();\n                PropertyEntry propertyEntry = entityEntry.Property(nameof(Animal.ConcurrencyField));\n                propertyEntry.OriginalValue = newConcurrencyToken;\n                propertyEntry.Metadata.GetSetter().SetClrValue(_zooEntities.Tigger, newConcurrencyToken);\n\n                Assert.Equal(0, await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n\n                Assert.False(string.IsNullOrWhiteSpace(_zooEntities.Tigger.ConcurrencyField));\n            });\n        }\n\n        [Fact]\n        public async Task Can_query_complex_record()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Add(_zooEntities.TaigaMasuta);\n                Assert.Equal(\n                    _zooEntities.Employees.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.TaigaMasuta,\n                    await zooDbContext.Employees\n                        .SingleAsync(searchedEmployee => searchedEmployee.Specialties\n                            .Any(specialty => specialty.AnimalType == nameof(Tiger)\n                                              && specialty.Task == ZooTask.Feeding))\n                    , new EmployeeEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_query_polymorphic_sub_types()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Animals.OfType<Tiger>().Single(),\n                    await zooDbContext.Animals.OfType<Tiger>().SingleAsync(),\n                    new AnimalEqualityComparer());\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Animals.OfType<PolarBear>().Single(),\n                    await zooDbContext.Animals.OfType<PolarBear>().SingleAsync(),\n                    new AnimalEqualityComparer());\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Animals.OfType<SeaOtter>().Single(),\n                    await zooDbContext.Animals.OfType<SeaOtter>().SingleAsync(),\n                    new AnimalEqualityComparer());\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Animals.OfType<EurasianOtter>().Single(),\n                    await zooDbContext.Animals.OfType<EurasianOtter>().SingleAsync(),\n                    new AnimalEqualityComparer());\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IList<Otter> originalOtters = _zooEntities.Animals\n                    .OfType<Otter>()\n                    .OrderBy(otter => otter.Name)\n                    .ToList();\n                IList<Otter> queriedOtters = await zooDbContext.Animals\n                    .OfType<Otter>()\n                    .OrderBy(otter => otter.Name)\n                    .ToListAsync();\n                Assert.Equal(originalOtters, queriedOtters, new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_list_async()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(_zooEntities.Animals,\n                    await zooDbContext.Animals\n                        .OrderBy(animal => animal.Name)\n                        .ThenBy(animal => animal.Height)\n                        .ToListAsync(),\n                    new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_query_first_or_default_async()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(\n                    _zooEntities.Animals.OfType<Tiger>().Single(),\n                    await zooDbContext.Animals.OfType<Tiger>().FirstOrDefaultAsync(),\n                    new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact]\n        public async Task Can_include_direct_collection()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Enclosures.AddRange(_zooEntities.Enclosures);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Enclosure> queriedEnclosures = await zooDbContext.Enclosures\n                    .Include(enclosure => enclosure.Animals)\n                    .OrderBy(enclosure => enclosure.AnimalEnclosureType)\n                    .ThenBy(enclosure => enclosure.Name)\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Enclosures,\n                    queriedEnclosures,\n                    new EnclosureEqualityComparer()\n                        .WithAnimalEqualityComparer(animalEqualityComparer => animalEqualityComparer\n                            .WithEnclosureEqualityComparer()));\n            });\n        }\n\n        [Fact]\n        public async Task Can_include_direct_reference()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Animal> queriedAnimals = await zooDbContext.Animals\n                    .Include(animal => animal.Enclosure)\n                    .OrderBy(animal => animal.Name)\n                    .ThenBy(animal => animal.Age)\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Animals,\n                    queriedAnimals,\n                    new AnimalEqualityComparer()\n                        .WithEnclosureEqualityComparer(enclosureEqualityComparer =>\n                            enclosureEqualityComparer.WithAnimalEqualityComparer()));\n            });\n        }\n\n        [Fact(Skip = \"Test currently fails.\")]\n        public async Task Can_include_self_reference()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.AddRange(_zooEntities.Employees);\n                Assert.Equal(\n                    _zooEntities.Employees.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Employee> queriedEmployees = await zooDbContext.Employees\n                    .Include(employee => employee.Manager)\n                    .OrderBy(employee => employee.FullName)\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Employees,\n                    queriedEmployees,\n                    new EmployeeEqualityComparer()\n                        .WithManagerComparer(managerEqualityComparer =>\n                            managerEqualityComparer.WithDirectReportsComparer()));\n            });\n        }\n\n        [Fact(Skip = \"IncludeCompiler does not currently support DI or being independently overriden.\")]\n        public async Task Can_include_owned_collection()\n        {\n            // IncludeCompiler uses the entity metadata to generate the underlying join clauses,\n            // however it currently does not properly support being injected through DI, being created\n            // by a factory, or being independently overriden without also having to override several\n            // other query-generation-related classes. This makes it virtually impossible to generate\n            // the correct MongoDb-side query syntax for supporting Join and GroupJoin statements\n            // against owned collections where the ownership requires a level of indirection to get to\n            // the foreign key.\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Enclosures.AddRange(_zooEntities.Enclosures);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Enclosure> queriedEnclosures = await zooDbContext.Enclosures\n                    .Include(enclosure => enclosure.Animals)\n                    .Include(enclosure => enclosure.WeeklySchedule.Assignments)\n                    .ThenInclude(zooAssignment => zooAssignment.Assignee)\n                    .OrderBy(enclosure => enclosure.AnimalEnclosureType)\n                    .ThenBy(enclosure => enclosure.Name)\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Enclosures,\n                    queriedEnclosures,\n                    new EnclosureEqualityComparer()\n                        .WithAnimalEqualityComparer(animalEqualityComparer => animalEqualityComparer\n                            .WithEnclosureEqualityComparer())\n                        .ConfigureWeeklyScheduleEqualityComparer(\n                            scheduleEqualityComparer => scheduleEqualityComparer.ConfigureZooAssignmentEqualityComparer(\n                                zooAssignmentEqualityComparer => zooAssignmentEqualityComparer.WithEmployeeEqualityComparer())));\n            });\n        }\n\n        [Fact]\n        public async Task Can_include_owned_reference()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Enclosures.AddRange(_zooEntities.Enclosures);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Enclosure> queriedEnclosures = await zooDbContext.Enclosures\n                    .Include(enclosure => enclosure.Animals)\n                    .Include(enclosure => enclosure.WeeklySchedule.Approver)\n                    .OrderBy(enclosure => enclosure.AnimalEnclosureType)\n                    .ThenBy(enclosure => enclosure.Name)\n                    .ToListAsync();\n\n                Assert.Equal(_zooEntities.Enclosures,\n                    queriedEnclosures,\n                    new EnclosureEqualityComparer()\n                        .WithAnimalEqualityComparer(animalEqualityComparer => animalEqualityComparer\n                            .WithEnclosureEqualityComparer())\n                        .ConfigureWeeklyScheduleEqualityComparer(\n                            scheduleEqualityComparer => scheduleEqualityComparer\n                                .WithApproverEqualityComparer()));\n            });\n        }\n\n        [Fact]\n        public async Task Can_execute_group_join_without_includes()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Enclosures.AddRange(_zooEntities.Enclosures);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IEnumerable<Enclosure> queriedEnclosures = await zooDbContext.Enclosures\n                    .GroupJoin(\n                        zooDbContext.Employees\n                            .Join(\n                                zooDbContext.Enclosures.SelectMany(\n                                    enclosure => enclosure.WeeklySchedule.Assignments,\n                                    (enclosure, assignment) => new\n                                    {\n                                        EnclosureId = enclosure.EnclosureId,\n                                        Assignment = assignment\n                                    }),\n                                employee => employee.EmployeeId,\n                                enclosureAssignment => enclosureAssignment.Assignment.Assignee.EmployeeId,\n                                (employee, enclosureAssignment) => new\n                                {\n                                    enclosureAssignment.EnclosureId,\n                                    Assignment = AssignAssignee(enclosureAssignment.Assignment, employee)\n                                }),\n                        enclosure => enclosure.EnclosureId,\n                        enclosureAssignment => enclosureAssignment.EnclosureId,\n                        (enclosure, enclosureAssignments) => AssignAssignments(\n                            enclosure,\n                            enclosureAssignments.Select(enclosureAssignment => enclosureAssignment.Assignment)))\n                    .ToListAsync();\n                Assert.Equal(_zooEntities.Enclosures,\n                    queriedEnclosures,\n                    new EnclosureEqualityComparer()\n                        .ConfigureWeeklyScheduleEqualityComparer(\n                            scheduleEqualityComparer => scheduleEqualityComparer\n                                .ConfigureZooAssignmentEqualityComparer(\n                                    zooAssignmentEqualityComparer => zooAssignmentEqualityComparer\n                                        .WithEmployeeEqualityComparer())));\n            });\n        }\n\n        private static Enclosure AssignAssignments(Enclosure enclosure, IEnumerable<ZooAssignment> zooAssignments)\n        {\n            foreach (var pair in enclosure.WeeklySchedule.Assignments\n                .Join(\n                    zooAssignments,\n                    includedAssignment => includedAssignment.Assignee.EmployeeId,\n                    denormalizedAssignment => denormalizedAssignment.Assignee.EmployeeId,\n                    (denormalizedAssignment, includedAssignment) => new\n                    {\n                        Assignment = denormalizedAssignment,\n                        includedAssignment.Assignee\n                    }))\n            {\n                pair.Assignment.Assignee = pair.Assignee;\n            };\n            return enclosure;\n        }\n\n        private static ZooAssignment AssignAssignee(ZooAssignment assignment, Employee assignee)\n        {\n            assignment.Assignee = assignee;\n            return assignment;\n        }\n\n        [Fact]\n        public async Task Concurrent_query()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Employees.AddRange(_zooEntities.Employees);\n                Assert.Equal(\n                    _zooEntities.Employees.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            Employee[] employees = await ExecuteUnitOfWorkAsync(\n                zooDbContext => Task.WhenAll(\n                    zooDbContext.Employees.SingleAsync(employee => employee.FullName == _zooEntities.ManAgier.FullName),\n                    zooDbContext.Employees.SingleAsync(employee => employee.FullName == _zooEntities.BearOCreary.FullName),\n                    zooDbContext.Employees.SingleAsync(employee => employee.FullName == _zooEntities.OttoVonEssenmacher.FullName),\n                    zooDbContext.Employees.SingleAsync(employee => employee.FullName == _zooEntities.TaigaMasuta.FullName),\n                    zooDbContext.Employees.SingleAsync(employee => employee.FullName == _zooEntities.TurGuidry.FullName)\n                ));\n\n            Employee[] expectedEmployees = \n            {\n                _zooEntities.ManAgier,\n                _zooEntities.BearOCreary,\n                _zooEntities.OttoVonEssenmacher,\n                _zooEntities.TaigaMasuta,\n                _zooEntities.TurGuidry\n            };\n\n            Assert.All(employees, Assert.NotNull);\n            Assert.Equal(expectedEmployees, employees, new EmployeeEqualityComparer());\n        }\n\n        [Fact(Skip = \"Test currently fails.\")]\n        public async Task Can_list_async_twice()\n        {\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Animals.AddRange(_zooEntities.Animals);\n                Assert.Equal(\n                    _zooEntities.Entities.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(_zooEntities.Animals,\n                    await zooDbContext.Animals\n                        .OrderBy(animal => animal.Name)\n                        .ThenBy(animal => animal.Height)\n                        .ToListAsync(),\n                    new AnimalEqualityComparer());\n            });\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                Assert.Equal(_zooEntities.Animals,\n                    await zooDbContext.Animals\n                        .OrderBy(animal => animal.Name)\n                        .ThenBy(animal => animal.Height)\n                        .ToListAsync(),\n                    new AnimalEqualityComparer());\n            });\n        }\n\n        [Fact(Skip = \"This test is a performance test and take a long time to execute.\")]\n        public async Task Can_query_multiple_concurrent_items_from_large_data_set()\n        {\n            IList<Employee> tigerFodderEmployees = Enumerable\n                .Range(1, 100000)\n                .Select(index => new Employee\n                {\n                    Age = 34.7M,\n                    FirstName = \"Fodder\",\n                    LastName = index.ToString()\n                })\n                .ToList();\n\n            await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                zooDbContext.Employees.AddRange(tigerFodderEmployees);\n                Assert.Equal(\n                    tigerFodderEmployees.Count,\n                    await zooDbContext.SaveChangesAsync(acceptAllChangesOnSuccess: true));\n            });\n\n            Employee[] employees = await ExecuteUnitOfWorkAsync(async zooDbContext =>\n            {\n                IList<Task<Employee>> tasks = Enumerable\n                    .Range(1, 100)\n                    .Select(index =>\n                        zooDbContext.Employees\n                            .FirstOrDefaultAsync(e => e.LastName == (index * 1000).ToString())\n                    )\n                    .ToList();\n                return await Task.WhenAll(tasks);\n            });\n\n            Assert.All(employees, Assert.NotNull);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/MongoDbUtilitiesTests.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests\n{\n    public class MongoDbUtilitiesTests\n    {\n        [Theory]\n        [InlineData(\"monkey\", \"monkeys\")]\n        [InlineData(\"laptop\", \"laptops\")]\n        [InlineData(\"cpu\", \"cpus\")]\n        [InlineData(\"horse\", \"horses\")]\n        [InlineData(\"pony\", \"ponies\")]\n        public void Pluralize_singular_strings(string value, string expected)\n            => Assert.Equal(expected, MongoDbUtilities.Pluralize(value));\n\n        [Theory]\n        [InlineData(\"monkeys\")]\n        [InlineData(\"horses\")]\n        [InlineData(\"ponies\")]\n        public void Pluralize_doesnt_change_plurals(string value)\n            => Assert.Equal(value, MongoDbUtilities.Pluralize(value));\n\n        [Theory]\n        [InlineData(\"CPU\", \"cpu\")]\n        [InlineData(\"ETA\", \"eta\")]\n        [InlineData(\"EPA\", \"epa\")]\n        [InlineData(\"TLA\", \"tla\")]\n        public void Camel_case_uppercase_strings(string value, string expected)\n            => Assert.Equal(expected, MongoDbUtilities.ToLowerCamelCase(value));\n\n        [Theory]\n        [InlineData(\"EFTests\", \"efTests\")]\n        [InlineData(\"NYCity\", \"nyCity\")]\n        [InlineData(\"TLAcronym\", \"tlAcronym\")]\n        [InlineData(\"ThreeLetterAcronym\", \"threeLetterAcronym\")]\n        public void Camel_case_doesnt_change_trailing_words(string value, string expected)\n            => Assert.Equal(expected, MongoDbUtilities.ToLowerCamelCase(value));\n\n        [Theory]\n        [InlineData(typeof(Animal), typeof(Animal))]\n        [InlineData(typeof(Tiger), typeof(Animal))]\n        [InlineData(typeof(PolarBear), typeof(Animal))]\n        [InlineData(typeof(Otter), typeof(Animal))]\n        [InlineData(typeof(EurasianOtter), typeof(Animal))]\n        [InlineData(typeof(SeaOtter), typeof(Animal))]\n        [InlineData(typeof(Employee), typeof(Employee))]\n        [InlineData(typeof(Enclosure), typeof(Enclosure))]\n        public void GetCollectionEntityType_returns_least_derived_entity_type(Type documentType, Type expectedType)\n        {\n            var zooDbContext = new ZooDbContext();\n            IEntityType documentEntityType = zooDbContext.Model.FindEntityType(documentType);\n            IEntityType expectedEntityType = zooDbContext.Model.FindEntityType(expectedType);\n\n            Assert.Equal(expectedEntityType, documentEntityType.GetMongoDbCollectionEntityType());\n        }\n\n        [Theory]\n        [InlineData(typeof(Animal))]\n        [InlineData(typeof(Tiger))]\n        [InlineData(typeof(PolarBear))]\n        [InlineData(typeof(Otter))]\n        [InlineData(typeof(EurasianOtter))]\n        [InlineData(typeof(SeaOtter))]\n        [InlineData(typeof(Employee))]\n        [InlineData(typeof(Enclosure))]\n        public void IsDocumentRootEntityType_returns_true_for_root_entity_types(Type documentType)\n        {\n            var zooDbContext = new ZooDbContext();\n            IEntityType documentEntityType = zooDbContext.Model.FindEntityType(documentType);\n\n            Assert.True(documentEntityType.IsDocumentRootEntityType());\n        }\n\n        [Theory]\n        [InlineData(typeof(Schedule))]\n        [InlineData(typeof(Specialty))]\n        [InlineData(typeof(ZooAssignment))]\n        public void IsDocumentRootEntityType_returns_false_for_owned_entity_types(Type documentType)\n        {\n            var zooDbContext = new ZooDbContext();\n            IEntityType documentEntityType = zooDbContext.Model.FindEntityType(documentType);\n\n            Assert.False(documentEntityType.IsDocumentRootEntityType());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Properties/AssemblyInfo.cs",
    "content": "﻿// Copyright (c) Blueshift Software, LLC. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Reflection;\nusing System.Resources;\nusing Xunit;\n\n[assembly: NeutralResourcesLanguage(\"en-US\")]\n[assembly: AssemblyMetadata(\"Serviceable\", \"True\")]\n\n[assembly: TestFramework(\"Microsoft.EntityFrameworkCore.Specification.Tests.TestUtilities.Xunit.ConditionalTestFramework\", \"Microsoft.EntityFrameworkCore.Specification.Tests\")]\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Storage/MongoDbConnectionTests.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing MongoDB.Driver;\nusing Moq;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Storage\n{\n    public class MongoDbConnectionTests\n    {\n        private readonly Mock<IMongoDatabase> _mockMongoDatabase;\n        private readonly Mock<IMongoClient> _mockMongoClient;\n        private readonly Mock<IMongoCollection<Employee>> _mockEmployee;\n        private readonly Mock<IMongoDbTypeMappingSource> _mockMongoDbTypeMappingSource;\n        private readonly IModel _model;\n\n        public MongoDbConnectionTests()\n        {\n            _mockMongoDbTypeMappingSource = MockMongoDbTypeMappingSource();\n            _model = GetModel();\n            _mockMongoClient = MockMongoClient();\n            _mockMongoDatabase = MockMongoDatabase();\n            _mockEmployee = MockEmployee();\n        }\n\n        private IModel GetModel()\n        {\n            var model = new ModelBuilder(\n                new MongoDbConventionSetBuilder(\n                    new MongoDbConventionSetBuilderDependencies(\n                        new CurrentDbContext(\n                            new ZooDbContext(\n                                new DbContextOptions<ZooDbContext>())),\n                        _mockMongoDbTypeMappingSource.Object,\n                        Mock.Of<IMemberClassifier>(),\n                        Mock.Of<IDiagnosticsLogger<DbLoggerCategory.Model>>()))\n                    .AddConventions(\n                        new CoreConventionSetBuilder(\n                            new CoreConventionSetBuilderDependencies(\n                                _mockMongoDbTypeMappingSource.Object,\n                                null,\n                                null,\n                                null,\n                                null))\n                            .CreateConventionSet()))\n                .ForMongoDbFromDatabase(\"zooDb\")\n                .Model\n                .AsModel();\n            new EntityTypeBuilder(model.Builder\n                .Entity(typeof(Employee), ConfigurationSource.Explicit))\n                .ForMongoDbFromCollection(\"employees\");\n            return model;\n        }\n\n        private Mock<IMongoClient> MockMongoClient()\n        {\n            var mockMongoClient = new Mock<IMongoClient>();\n            mockMongoClient\n                .Setup(mongoClient => mongoClient.GetDatabase(\"zooDb\", It.IsAny<MongoDatabaseSettings>()))\n                .Returns(() => _mockMongoDatabase.Object)\n                .Verifiable();\n            mockMongoClient\n                .Setup(mongoClient => mongoClient.DropDatabase(\"zooDb\", It.IsAny<CancellationToken>()))\n                .Verifiable();\n            return mockMongoClient;\n        }\n\n        private Mock<IMongoDatabase> MockMongoDatabase()\n        {\n            var mockMongoDatabase = new Mock<IMongoDatabase>();\n            mockMongoDatabase\n                .Setup(mongoDatabase => mongoDatabase.GetCollection<Employee>(\"employees\", It.IsAny<MongoCollectionSettings>()))\n                .Returns(() => _mockEmployee.Object)\n                .Verifiable();\n            return mockMongoDatabase;\n        }\n\n        private Mock<IMongoCollection<Employee>> MockEmployee()\n            => new Mock<IMongoCollection<Employee>>();\n\n        private Mock<IMongoDbTypeMappingSource> MockMongoDbTypeMappingSource()\n            => new Mock<IMongoDbTypeMappingSource>();\n\n        [Fact]\n        public void Get_database_calls_mongo_client_get_database()\n        {\n            IMongoDbConnection mongoDbConnection = new MongoDbConnection(_mockMongoClient.Object, _model);\n            Assert.Equal(_mockMongoDatabase.Object, mongoDbConnection.GetDatabase());\n            _mockMongoClient\n                .Verify(mongoClient => mongoClient.GetDatabase(\"zooDb\", It.IsAny<MongoDatabaseSettings>()), Times.Once);\n        }\n\n        [Fact]\n        public async Task Get_database_async_calls_mongo_client_get_database()\n        {\n            IMongoDbConnection mongoDbConnection = new MongoDbConnection(_mockMongoClient.Object, _model);\n            Assert.Equal(_mockMongoDatabase.Object, await mongoDbConnection.GetDatabaseAsync());\n            _mockMongoClient\n                .Verify(mongoClient => mongoClient.GetDatabase(\"zooDb\", It.IsAny<MongoDatabaseSettings>()), Times.Once);\n        }\n\n        [Fact]\n        public void Drop_database_calls_mongo_client_drop_database()\n        {\n            IMongoDbConnection mongoDbConnection = new MongoDbConnection(_mockMongoClient.Object, _model);\n            mongoDbConnection.DropDatabase();\n            _mockMongoClient\n                .Verify(mongoClient => mongoClient.DropDatabase(\"zooDb\", It.IsAny<CancellationToken>()), Times.Once);\n        }\n\n        [Fact]\n        public async Task Drop_database_async_calls_mongo_client_drop_database_async()\n        {\n            IMongoDbConnection mongoDbConnection = new MongoDbConnection(_mockMongoClient.Object, _model);\n            await mongoDbConnection.DropDatabaseAsync();\n            _mockMongoClient\n                .Verify(mongoClient => mongoClient.DropDatabaseAsync(\"zooDb\", It.IsAny<CancellationToken>()), Times.Once);\n        }\n\n        [Fact]\n        public void Get_collection_calls_mongo_database_get_collection()\n        {\n            IMongoDbConnection mongoDbConnection = new MongoDbConnection(_mockMongoClient.Object, _model);\n            Assert.Equal(_mockEmployee.Object, mongoDbConnection.GetCollection<Employee>());\n            _mockMongoDatabase\n                .Verify(mongoDatabase => mongoDatabase.GetCollection<Employee>(\"employees\", It.IsAny<MongoCollectionSettings>()), Times.Once);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Storage/MongoDbDatabaseCreatorTests.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing MongoDB.Driver;\nusing Moq;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Storage\n{\n    public class MongoDbDatabaseCreatorTests\n    {\n        [Fact]\n        public void Ensure_created_returns_false()\n        {\n            var mockMongoDbConnection = new Mock<IMongoDbConnection>();\n            mockMongoDbConnection\n                .Setup(mongoDbConnection => mongoDbConnection.GetDatabase())\n                .Returns(new Mock<IMongoDatabase>().Object)\n                .Verifiable();\n            var mongoDbDatabaseCreator = new MongoDbDatabaseCreator(mockMongoDbConnection.Object);\n            Assert.False(mongoDbDatabaseCreator.EnsureCreated());\n            mockMongoDbConnection.Verify(\n                mongoDbConnection => mongoDbConnection.GetDatabase(),\n                Times.Exactly(callCount: 1));\n        }\n\n        [Fact]\n        public async Task Ensure_created_async_returns_false()\n        {\n            var mockMongoDbConnection = new Mock<IMongoDbConnection>();\n            mockMongoDbConnection\n                .Setup(mongoDbConnection => mongoDbConnection.GetDatabaseAsync(It.IsAny<CancellationToken>()))\n                .Returns(Task.FromResult(new Mock<IMongoDatabase>().Object))\n                .Verifiable();\n            var mongoDbDatabaseCreator = new MongoDbDatabaseCreator(mockMongoDbConnection.Object);\n            Assert.False(await mongoDbDatabaseCreator.EnsureCreatedAsync());\n            mockMongoDbConnection.Verify(\n                mongoDbConnection => mongoDbConnection.GetDatabaseAsync(It.IsAny<CancellationToken>()),\n                Times.Exactly(callCount: 1));\n        }\n\n        [Fact]\n        public void Ensure_deleted_succeeds()\n        {\n            var mockMongoDbConnection = new Mock<IMongoDbConnection>();\n            mockMongoDbConnection\n                .Setup(mongoDbConnection => mongoDbConnection.DropDatabase())\n                .Verifiable();\n            var mongoDbDatabaseCreator = new MongoDbDatabaseCreator(mockMongoDbConnection.Object);\n            Assert.True(mongoDbDatabaseCreator.EnsureDeleted());\n            mockMongoDbConnection.Verify(\n                mongoDbConnection => mongoDbConnection.DropDatabase(),\n                Times.Exactly(callCount: 1));\n        }\n\n        [Fact]\n        public async Task Ensure_deleted_async_succeeds()\n        {\n            var mockMongoDbConnection = new Mock<IMongoDbConnection>();\n            mockMongoDbConnection\n                .Setup(mongoDbConnection => mongoDbConnection.DropDatabaseAsync(It.IsAny<CancellationToken>()))\n                .Returns(Task.FromResult(result: 0))\n                .Verifiable();\n            var mongoDbDatabaseCreator = new MongoDbDatabaseCreator(mockMongoDbConnection.Object);\n            Assert.True(await mongoDbDatabaseCreator.EnsureDeletedAsync());\n            mockMongoDbConnection.Verify(\n                mongoDbConnection => mongoDbConnection.DropDatabaseAsync(It.IsAny<CancellationToken>()),\n                Times.Exactly(callCount: 1));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Storage/MongoDbDatabaseTests.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nusing System.Reflection;\nusing System.Threading;\nusing Blueshift.EntityFrameworkCore.MongoDB.Adapter.Update;\nusing Blueshift.EntityFrameworkCore.MongoDB.Metadata.Builders;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.ChangeTracking;\nusing Microsoft.EntityFrameworkCore.ChangeTracking.Internal;\nusing Microsoft.EntityFrameworkCore.Diagnostics;\nusing Microsoft.EntityFrameworkCore.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.Query;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Update;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing MongoDB.Driver;\nusing Moq;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Storage\n{\n    public class MongoDbDatabaseTests\n    {\n        [Fact]\n        public void Save_changes_returns_requested_document_count()\n        {\n            var queryCompilationContextFactory = Mock.Of<IQueryCompilationContextFactory>();\n            var mockMongoDbConnection = new Mock<IMongoDbConnection>();\n            var mockMongoCollection = new Mock<IMongoCollection<Animal>>();\n            var mockMongoDbTypeMappingSource = new Mock<IMongoDbTypeMappingSource>();\n\n            mockMongoCollection.Setup(mongoCollection => mongoCollection.BulkWrite(\n                    It.IsAny<IEnumerable<WriteModel<Animal>>>(),\n                    It.IsAny<BulkWriteOptions>(),\n                    It.IsAny<CancellationToken>()))\n                .Returns((IEnumerable<WriteModel<Animal>> list, BulkWriteOptions options, CancellationToken token)\n                    => new BulkWriteResult<Animal>.Acknowledged(\n                        list.Count(),\n                        matchedCount: 0,\n                        deletedCount: list.OfType<DeleteOneModel<Animal>>().Count(),\n                        insertedCount: list.OfType<InsertOneModel<Animal>>().Count(),\n                        modifiedCount: list.OfType<ReplaceOneModel<Animal>>().Count(),\n                        processedRequests: list,\n                        upserts: new List<BulkWriteUpsert>()));\n\n            mockMongoDbConnection.Setup(mockedMongoDbConnection => mockedMongoDbConnection.GetCollection<Animal>())\n                .Returns(() => mockMongoCollection.Object);\n\n            var databaseDepedencies = new DatabaseDependencies(queryCompilationContextFactory);\n\n            IMongoDbWriteModelFactorySelector writeModelFactorySelector =\n                new MongoDbWriteModelFactorySelector(\n                    new MongoDbValueGeneratorSelector(\n                        new ValueGeneratorSelectorDependencies(\n                            new ValueGeneratorCache(\n                                new ValueGeneratorCacheDependencies()))), \n                    new MongoDbWriteModelFactoryCache());\n            var mongoDbDatabase = new MongoDbDatabase(\n                databaseDepedencies,\n                mockMongoDbConnection.Object,\n                writeModelFactorySelector);\n\n            var model = new Model(\n                new MongoDbConventionSetBuilder(\n                        new MongoDbConventionSetBuilderDependencies(\n                            new CurrentDbContext(\n                                new ZooDbContext(\n                                    new DbContextOptions<ZooDbContext>())),\n                            mockMongoDbTypeMappingSource.Object,\n                            Mock.Of<IMemberClassifier>(),\n                            Mock.Of<IDiagnosticsLogger<DbLoggerCategory.Model>>()))\n                    .AddConventions(\n                        new CoreConventionSetBuilder(\n                                new CoreConventionSetBuilderDependencies(\n                                    mockMongoDbTypeMappingSource.Object,\n                                    null,\n                                    null,\n                                    null,\n                                    null))\n                            .CreateConventionSet()));\n\n            EntityType animalEntityType = model.AddEntityType(typeof(Animal));\n            animalEntityType.Builder\n                .GetOrCreateProperties(typeof(Animal).GetTypeInfo().GetProperties(), ConfigurationSource.Explicit);\n            EntityType tigerEntityType = model.GetOrAddEntityType(typeof(Tiger));\n\n            IReadOnlyList<IUpdateEntry> entityEntries = new[] { EntityState.Added, EntityState.Deleted, EntityState.Modified }\n                .Select(entityState =>\n                    {\n                        var entity = new Tiger();\n                        var mockUpdateEntry = new Mock<InternalEntityEntry>(\n                            null,\n                            tigerEntityType);\n\n                        mockUpdateEntry\n                            .SetupGet(updateEntry => updateEntry.EntityState)\n                            .Returns(entityState);\n                        mockUpdateEntry\n                            .SetupGet(updateEntry => updateEntry.EntityType)\n                            .Returns(tigerEntityType);\n                        mockUpdateEntry\n                            .SetupGet(updateEntry => updateEntry.Entity)\n                            .Returns(entity);\n                        mockUpdateEntry\n                            .Setup(updateEntry => updateEntry.ToEntityEntry())\n                            .Returns(new EntityEntry(mockUpdateEntry.Object));\n\n                        return mockUpdateEntry.Object;\n                    })\n                .ToList();\n\n            Assert.Equal(entityEntries.Count, mongoDbDatabase.SaveChanges(entityEntries));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/Storage/MongoDbTypeMappingSourceTests.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Blueshift.EntityFrameworkCore.MongoDB.Storage;\nusing Microsoft.EntityFrameworkCore.Storage;\nusing Microsoft.EntityFrameworkCore.Storage.ValueConversion;\nusing MongoDB.Bson;\nusing Moq;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.Storage\n{\n    public class MongoDbTypeMappingSourceTests\n    {\n        private readonly MongoDbTypeMappingSource _mongoDbTypeMappingSource = new MongoDbTypeMappingSource(\n            new TypeMappingSourceDependencies(\n                Mock.Of<IValueConverterSelector>()));\n\n        [Theory]\n        [InlineData(typeof(int))]\n        [InlineData(typeof(long))]\n        [InlineData(typeof(short))]\n        [InlineData(typeof(byte))]\n        [InlineData(typeof(uint))]\n        [InlineData(typeof(ulong))]\n        [InlineData(typeof(ushort))]\n        [InlineData(typeof(sbyte))]\n        [InlineData(typeof(char))]\n        [InlineData(typeof(bool))]\n        [InlineData(typeof(byte[]))]\n        [InlineData(typeof(DateTime))]\n        [InlineData(typeof(DateTimeOffset))]\n        [InlineData(typeof(decimal))]\n        [InlineData(typeof(double))]\n        [InlineData(typeof(float))]\n        [InlineData(typeof(Guid))]\n        [InlineData(typeof(string))]\n        [InlineData(typeof(TimeSpan))]\n        [InlineData(typeof(ZooTask))]\n        [InlineData(typeof(ObjectId))]\n        [InlineData(typeof(IEnumerable<int>))]\n        [InlineData(typeof(IEnumerable<long>))]\n        [InlineData(typeof(IEnumerable<short>))]\n        [InlineData(typeof(IEnumerable<byte>))]\n        [InlineData(typeof(IEnumerable<uint>))]\n        [InlineData(typeof(IEnumerable<ulong>))]\n        [InlineData(typeof(IEnumerable<ushort>))]\n        [InlineData(typeof(IEnumerable<sbyte>))]\n        [InlineData(typeof(IEnumerable<char>))]\n        [InlineData(typeof(IEnumerable<bool>))]\n        [InlineData(typeof(IEnumerable<byte[]>))]\n        [InlineData(typeof(IEnumerable<DateTime>))]\n        [InlineData(typeof(IEnumerable<DateTimeOffset>))]\n        [InlineData(typeof(IEnumerable<decimal>))]\n        [InlineData(typeof(IEnumerable<double>))]\n        [InlineData(typeof(IEnumerable<float>))]\n        [InlineData(typeof(IEnumerable<ObjectId>))]\n        [InlineData(typeof(IEnumerable<Guid>))]\n        [InlineData(typeof(IEnumerable<string>))]\n        [InlineData(typeof(IEnumerable<TimeSpan>))]\n        [InlineData(typeof(IEnumerable<ZooTask>))]\n        [InlineData(typeof(IDictionary<string, ZooTask>))]\n        public void Primitives_and_enumerables_of_primitives_are_mapped(Type type)\n        {\n            Assert.NotNull(_mongoDbTypeMappingSource.FindMapping(type));\n        }\n\n        [Theory]\n        [InlineData(typeof(Employee))]\n        [InlineData(typeof(Animal))]\n        [InlineData(typeof(Tiger))]\n        [InlineData(typeof(PolarBear))]\n        [InlineData(typeof(Otter))]\n        [InlineData(typeof(SeaOtter))]\n        [InlineData(typeof(EurasianOtter))]\n        [InlineData(typeof(Specialty))]\n        [InlineData(typeof(IEnumerable<Specialty>))]\n        [InlineData(typeof(IDictionary<string, Specialty>))]\n        public void Entities_and_complex_types_are_not_mapped(Type type)\n        {\n            Assert.Null(_mongoDbTypeMappingSource.FindMapping(type));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/ValueGeneration/MongoDbValueGeneratorSelectorTests.cs",
    "content": "﻿using System.Reflection;\nusing Blueshift.EntityFrameworkCore.MongoDB.SampleDomain;\nusing Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration;\nusing Microsoft.EntityFrameworkCore.Metadata.Internal;\nusing Microsoft.EntityFrameworkCore.ValueGeneration;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.ValueGeneration\n{\n    public class MongoDbValueGeneratorSelectorTests\n    {\n        [Fact]\n        public void X()\n        {\n            var model = new Model();\n            EntityType entityType = model.AddEntityType(typeof(Employee));\n            Property property = entityType.AddProperty(typeof(Employee)\n                .GetTypeInfo()\n                .GetProperty(nameof(Employee.EmployeeId)));\n\n            var valueGeneratorCacheDependencies = new ValueGeneratorCacheDependencies();\n            var valueGeneratorCache = new ValueGeneratorCache(valueGeneratorCacheDependencies);\n            var valueGeneratorSelectorDependencies = new ValueGeneratorSelectorDependencies(valueGeneratorCache);\n            var mongoDbValueGeneratorSelector = new MongoDbValueGeneratorSelector(valueGeneratorSelectorDependencies);\n            ValueGenerator valueGenerator = mongoDbValueGeneratorSelector.Select(property, entityType);\n            Assert.IsAssignableFrom<ObjectIdValueGenerator>(valueGenerator);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/ValueGeneration/ObjectIdValueGeneratorTests.cs",
    "content": "﻿using Blueshift.EntityFrameworkCore.MongoDB.ValueGeneration;\nusing MongoDB.Bson;\nusing Xunit;\n\nnamespace Blueshift.EntityFrameworkCore.MongoDB.Tests.ValueGeneration\n{\n    public class ObjectIdValueGeneratorTests\n    {\n        [Fact]\n        public void Generates_temporary_values_returns_false()\n        {\n            var objectIdValueGenerator = new ObjectIdValueGenerator();\n            Assert.False(objectIdValueGenerator.GeneratesTemporaryValues);\n        }\n\n        [Fact]\n        public void Does_not_generate_empty_object_id()\n        {\n            var objectIdValueGenerator = new ObjectIdValueGenerator();\n            Assert.NotEqual(ObjectId.Empty, objectIdValueGenerator.Next(entry: null));\n        }\n\n        [Fact]\n        public void Generates_unique_object_ids()\n        {\n            var objectIdValueGenerator = new ObjectIdValueGenerator();\n            ObjectId id = ObjectId.Empty;\n            for (var i = 0; i < 100; i++)\n            {\n                Assert.NotEqual(id, id = objectIdValueGenerator.Next(entry: null));\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.EntityFrameworkCore.MongoDB.Tests/xunit.runner.json",
    "content": "﻿{\n  \"longRunningTestSeconds\": 30,\n  \"parallelizeAssembly\": false\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/Blueshift.Identity.MongoDB.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFrameworks>$(TestFrameworks)</TargetFrameworks>\n    <TestGroupName>MongoDb.EFCore.Identity.Tests</TestGroupName>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Include=\"..\\..\\src\\Shared\\CodeAnnotations.cs\" Link=\"CodeAnnotations.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Blueshift.EntityFrameworkCore.MongoDB\\Blueshift.EntityFrameworkCore.MongoDB.csproj\" />\n    <ProjectReference Include=\"..\\..\\src\\Blueshift.Identity.MongoDB\\Blueshift.Identity.MongoDB.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Service Include=\"{82a7f48d-3b50-4b1e-b82e-3ada8210c358}\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"xunit.runner.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbIdentityFixture.cs",
    "content": "﻿using System;\nusing Blueshift.EntityFrameworkCore.MongoDB.Infrastructure;\nusing Microsoft.Extensions.DependencyInjection;\nusing MongoDB.Bson;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbIdentityFixture : IDisposable\n    {\n        private const string MongoUrl = \"mongodb://localhost:27017\";\n\n        protected IServiceProvider ServiceProvider;\n        private IdentityMongoDbContext _identityDbContext;\n\n        public MongoDbIdentityFixture()\n        {\n            ServiceProvider = new ServiceCollection()\n                .AddDbContext<IdentityMongoDbContext>(options => options\n                    .UseMongoDb(\n                        connectionString: MongoUrl,\n                        mongoDbOptionsAction: optionsBuilder => optionsBuilder.UseDatabase(\"__test_identities\"))\n                    .EnableSensitiveDataLogging(true))\n                .AddIdentity<MongoDbIdentityUser, MongoDbIdentityRole>()\n                .AddEntityFrameworkMongoDbStores<IdentityMongoDbContext>()\n                .Services\n                .BuildServiceProvider();\n            _identityDbContext = ServiceProvider.GetRequiredService<IdentityMongoDbContext>();\n            _identityDbContext.Database.EnsureCreated();\n        }\n\n        public T GetService<T>()\n            => ServiceProvider.GetRequiredService<T>();\n\n        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        protected virtual void Dispose(bool disposing)\n        {\n            if (disposing)\n            {\n                if (_identityDbContext != null)\n                {\n                    _identityDbContext.Database.EnsureDeleted();\n                    _identityDbContext = null;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbIdentityTestBase.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    [Collection(\"MongoDB.Identity.Tests\")]\n    public abstract class MongoDbIdentityStoreTestBase\n    {\n        protected static readonly string RoleName = \"TestRole\";\n        protected static readonly string RoleNameNormalized = RoleName.ToUpper();\n\n        protected static readonly string UserName = \"user.name@domain.com\";\n        protected static readonly string UserNameNormalized = UserName.ToUpper();\n\n        private readonly IUserStore<MongoDbIdentityUser> _userStore;\n        private readonly IRoleStore<MongoDbIdentityRole> _roleStore;\n\n        protected MongoDbIdentityStoreTestBase(MongoDbIdentityFixture mongoDbIdentityFixture)\n        {\n            _userStore = mongoDbIdentityFixture.GetService<IUserStore<MongoDbIdentityUser>>();\n            _roleStore = mongoDbIdentityFixture.GetService<IRoleStore<MongoDbIdentityRole>>();\n        }\n\n        protected virtual MongoDbIdentityRole CreateRole()\n            => new MongoDbIdentityRole\n            {\n                RoleName = RoleName,\n                NormalizedRoleName = RoleNameNormalized\n            };\n\n        protected async Task<MongoDbIdentityRole> CreateRoleInDatabase()\n        {\n            MongoDbIdentityRole role = CreateRole();\n            Assert.Equal(IdentityResult.Success, await _roleStore.CreateAsync(role, new CancellationToken()));\n            return role;\n        }\n\n        protected virtual MongoDbIdentityUser CreateUser()\n            => new MongoDbIdentityUser\n            {\n                UserName = UserName,\n                NormalizedUserName = UserNameNormalized\n            };\n\n        protected async Task<MongoDbIdentityUser> CreateUserInDatabase()\n        {\n            MongoDbIdentityUser user = CreateUser();\n            Assert.Equal(IdentityResult.Success, await _userStore.CreateAsync(user, new CancellationToken()));\n            return user;\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbIdentityTestCollection.cs",
    "content": "﻿using Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    [CollectionDefinition(\"MongoDB.Identity.Tests\")]\n    public class MongoDdIdentityTestCollection : ICollectionFixture<MongoDbIdentityFixture>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbRoleClaimStoreTests.cs",
    "content": "﻿using System.Linq;\nusing System.Security.Claims;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing MongoDB.Bson;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbRoleClaimStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string Claim1Type = nameof(Claim1Type);\n        private const string Claim1Value = nameof(Claim1Value);\n        private const string Claim2Type = nameof(Claim2Type);\n        private const string Claim2Value = nameof(Claim2Value);\n        private const string Claim3Type = nameof(Claim3Type);\n        private const string Claim3Value = nameof(Claim3Value);\n\n        private static readonly Claim Claim1 = new Claim(Claim1Type, Claim1Value);\n        private static readonly Claim Claim2 = new Claim(Claim2Type, Claim2Value);\n        private static readonly Claim Claim3 = new Claim(Claim3Type, Claim3Value);\n\n        private readonly IRoleClaimStore<MongoDbIdentityRole> _mongoDbRoleClaimStore;\n\n        public MongoDbRoleClaimStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbRoleClaimStore = mongoDbIdentityFixture.GetService<IRoleClaimStore<MongoDbIdentityRole>>();\n        }\n\n        protected override MongoDbIdentityRole CreateRole()\n        {\n            var role = base.CreateRole();\n            role.Claims.Add(new MongoDbIdentityClaim(Claim1));\n            role.Claims.Add(new MongoDbIdentityClaim(Claim2));\n            return role;\n        }\n\n        [Fact]\n        public async Task Can_add_claim_async()\n        {\n            var role = CreateRole();\n            await _mongoDbRoleClaimStore.AddClaimAsync(role, Claim3);\n            var newClaims = new [] { Claim1, Claim2, Claim3 };\n            Assert.Equal(newClaims, role.Claims.Select(claim => claim.ToClaim()), new ClaimComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_claims_async()\n        {\n            var role = CreateRole();\n            var claims = new [] { Claim1, Claim2 };\n            Assert.Equal(claims, await _mongoDbRoleClaimStore.GetClaimsAsync(role), new ClaimComparer());\n        }\n\n        [Fact]\n        public async Task Can_remove_claims_async()\n        {\n            var role = CreateRole();\n            await _mongoDbRoleClaimStore.RemoveClaimAsync(role, Claim1);\n            Assert.Equal(Claim2, role.Claims.Select(claim => claim.ToClaim()).Single(), new ClaimComparer());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbRoleStoreTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbRoleStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private readonly IRoleStore<MongoDbIdentityRole> _mongoDbRoleStore;\n\n        public MongoDbRoleStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbRoleStore = mongoDbIdentityFixture.GetService<IRoleStore<MongoDbIdentityRole>>();\n        }\n\n        [Fact]\n        public async Task Can_create_role_async()\n        {\n            Assert.NotNull(await CreateRoleInDatabase());\n        }\n\n        [Fact]\n        public async Task Can_delete_role_async()\n        {\n            var role = await CreateRoleInDatabase();\n            Assert.Equal(IdentityResult.Success, await _mongoDbRoleStore.DeleteAsync(role, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_find_by_id_async()\n        {\n            var role = await CreateRoleInDatabase();\n            Assert.Equal(role, await _mongoDbRoleStore.FindByIdAsync(role.Id.ToString(), new CancellationToken()), new MongoDbIdentityRoleComparer());\n        }\n\n        [Fact]\n        public async Task Can_find_by_name_async()\n        {\n            var role = await CreateRoleInDatabase();\n            Assert.Equal(role, await _mongoDbRoleStore.FindByNameAsync(role.NormalizedRoleName, new CancellationToken()), new MongoDbIdentityRoleComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_normalized_role_name_async()\n        {\n            var role = CreateRole();\n            Assert.Equal(role.NormalizedRoleName, await _mongoDbRoleStore.GetNormalizedRoleNameAsync(role, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_role_id_async()\n        {\n            var role = await CreateRoleInDatabase();\n            Assert.Equal(role.Id.ToString(), await _mongoDbRoleStore.GetRoleIdAsync(role, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_user_name_async()\n        {\n            var role = CreateRole();\n            Assert.Equal(role.RoleName, await _mongoDbRoleStore.GetRoleNameAsync(role, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_normalized_role_name_async()\n        {\n            var role = await CreateRoleInDatabase();\n            string newNormalizedRoleName = nameof(newNormalizedRoleName).ToUpper();\n            await _mongoDbRoleStore.SetNormalizedRoleNameAsync(role, newNormalizedRoleName, new CancellationToken());\n            Assert.Equal(newNormalizedRoleName, role.NormalizedRoleName, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_role_name_async()\n        {\n            var role = await CreateRoleInDatabase();\n            string newRoleName = nameof(newRoleName);\n            await _mongoDbRoleStore.SetRoleNameAsync(role, newRoleName, new CancellationToken());\n            Assert.Equal(newRoleName, role.RoleName, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_update_role_async()\n        {\n            var role = await CreateRoleInDatabase();\n            var newRoleName = \"New.Role.Name\";\n            var newNormalizedRoleName = newRoleName.ToUpper();\n            role.RoleName = newRoleName;\n            role.NormalizedRoleName = newNormalizedRoleName;\n            Assert.Equal(IdentityResult.Success, await _mongoDbRoleStore.UpdateAsync(role, new CancellationToken()));\n            Assert.Equal(role, await _mongoDbRoleStore.FindByNameAsync(newNormalizedRoleName, new CancellationToken()), new MongoDbIdentityRoleComparer());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserAuthenticationTokenStoreTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserAuthenticationTokenStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string Token1Name = nameof(Token1Name);\n        private const string Token2Name = nameof(Token2Name);\n        private const string Token1Value = nameof(Token1Value);\n        private const string Token2Value = nameof(Token2Value);\n\n        private readonly IUserAuthenticationTokenStore<MongoDbIdentityUser> _mongoDbUserAuthenticationTokenStore;\n\n        public MongoDbUserAuthenticationTokenStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserAuthenticationTokenStore = mongoDbIdentityFixture.GetService<IUserAuthenticationTokenStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Logins.Add(new MongoDbIdentityUserLogin\n            {\n                LoginProvider = \"Google\",\n                ProviderKey = new Guid().ToString(),\n                ProviderDisplayName = \"Google+\",\n                UserTokens =\n                {\n                    new MongoDbIdentityUserToken() { Name = Token1Name, Value = Token1Value },\n                    new MongoDbIdentityUserToken() { Name = Token2Name, Value = Token2Value }\n                }\n            });\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_token_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(Token1Value, await _mongoDbUserAuthenticationTokenStore.GetTokenAsync(user, \"Google\", Token1Name, new CancellationToken()), StringComparer.Ordinal);\n            Assert.Equal(Token2Value, await _mongoDbUserAuthenticationTokenStore.GetTokenAsync(user, \"Google\", Token2Name, new CancellationToken()), StringComparer.Ordinal);\n            Assert.Null(await _mongoDbUserAuthenticationTokenStore.GetTokenAsync(user, \"Google\", \"Token3\", new CancellationToken()));\n            Assert.Null(await _mongoDbUserAuthenticationTokenStore.GetTokenAsync(user, \"Facebook\", Token1Name, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_token_async()\n        {\n            var user = CreateUser();\n            string newTokenValue = nameof(newTokenValue);\n            await _mongoDbUserAuthenticationTokenStore.SetTokenAsync(user, \"Google\", Token1Name, newTokenValue, new CancellationToken());\n            Assert.Equal(newTokenValue, user.Logins\n                   .First(login => login.LoginProvider == \"Google\")\n                   .UserTokens\n                   .First(userToken => userToken.Name == Token1Name).Value,\n                StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_remove_token_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserAuthenticationTokenStore.RemoveTokenAsync(user, \"Google\", Token1Name, new CancellationToken());\n            var userTokens = user.Logins\n                   .First(login => login.LoginProvider == \"Google\")\n                   .UserTokens;\n            Assert.DoesNotContain(userTokens, userToken => userToken.Name == Token1Name);\n            Assert.Equal(Token2Value,\n                userTokens.First(userToken => userToken.Name == Token2Name).Value,\n                StringComparer.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserAuthenticatorKeyStoreTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserAuthenticatorKeyStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private static readonly string AuthenticatorKey = new Guid().ToString();\n\n        private readonly IUserAuthenticatorKeyStore<MongoDbIdentityUser> _mongoDbUserAuthenticatorKeyStore;\n\n        public MongoDbUserAuthenticatorKeyStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserAuthenticatorKeyStore = mongoDbIdentityFixture.GetService<IUserAuthenticatorKeyStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Logins.Add(new MongoDbIdentityUserLogin\n            {\n                LoginProvider = \"[BlueshiftMongoDbUserStore]\",\n                ProviderKey = new Guid().ToString(),\n                ProviderDisplayName = \"Blueshift MongoDb Provider\",\n                UserTokens =\n                {\n                    new MongoDbIdentityUserToken() { Name = \"AuthenticatorKey\", Value = AuthenticatorKey }\n                }\n            });\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_authenticator_key_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(AuthenticatorKey, await _mongoDbUserAuthenticatorKeyStore.GetAuthenticatorKeyAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_token_async()\n        {\n            var user = CreateUser();\n            var newAuthenticatorKey = new Guid().ToString();\n            await _mongoDbUserAuthenticatorKeyStore.SetAuthenticatorKeyAsync(user, newAuthenticatorKey, new CancellationToken());\n            Assert.Equal(newAuthenticatorKey, user.Logins\n                   .First(login => login.LoginProvider == \"[BlueshiftMongoDbUserStore]\")\n                   .UserTokens\n                   .First(userToken => userToken.Name == \"AuthenticatorKey\").Value,\n                StringComparer.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserClaimStoreTests.cs",
    "content": "﻿using System.Linq;\nusing System.Security.Claims;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserClaimStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string Claim1Type = nameof(Claim1Type);\n        private const string Claim1Value = nameof(Claim1Value);\n        private const string Claim2Type = nameof(Claim2Type);\n        private const string Claim2Value = nameof(Claim2Value);\n        private const string Claim3Type = nameof(Claim3Type);\n        private const string Claim3Value = nameof(Claim3Value);\n\n        private static readonly Claim Claim1 = new Claim(Claim1Type, Claim1Value);\n        private static readonly Claim Claim2 = new Claim(Claim2Type, Claim2Value);\n        private static readonly Claim Claim3 = new Claim(Claim3Type, Claim3Value);\n\n        private readonly IUserClaimStore<MongoDbIdentityUser> _mongoDbUserClaimStore;\n\n        public MongoDbUserClaimStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserClaimStore = mongoDbIdentityFixture.GetService<IUserClaimStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Claims.Add(new MongoDbIdentityClaim(Claim1));\n            user.Claims.Add(new MongoDbIdentityClaim(Claim2));\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_add_claim_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserClaimStore.AddClaimsAsync(user, new[] { Claim3 }, new CancellationToken());\n            var newClaims = new [] { Claim1, Claim2, Claim3 };\n            Assert.Equal(newClaims, user.Claims.Select(claim => claim.ToClaim()), new ClaimComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_claims_async()\n        {\n            var user = CreateUser();\n            var claims = new [] { Claim1, Claim2 };\n            Assert.Equal(claims, await _mongoDbUserClaimStore.GetClaimsAsync(user, new CancellationToken()), new ClaimComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_users_for_claim_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, (await _mongoDbUserClaimStore.GetUsersForClaimAsync(Claim1, new CancellationToken())).Single(), new MongoDbIdentityUserComparer());\n            Assert.Equal(user, (await _mongoDbUserClaimStore.GetUsersForClaimAsync(Claim2, new CancellationToken())).Single(), new MongoDbIdentityUserComparer());\n            Assert.Empty(await _mongoDbUserClaimStore.GetUsersForClaimAsync(Claim3, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_remove_claims_async()\n        {\n            var user = CreateUser();\n            var claimsToRemove = new [] { Claim1, Claim2 };\n            await _mongoDbUserClaimStore.RemoveClaimsAsync(user, claimsToRemove, new CancellationToken());\n            Assert.Empty(user.Claims);\n        }\n\n        [Fact]\n        public async Task Can_replace_claims_async()\n        {\n            var user = CreateUser();\n            var newClaims = new [] { Claim3, Claim2 };\n            await _mongoDbUserClaimStore.ReplaceClaimAsync(user, Claim1, Claim3, new CancellationToken());\n            Assert.Equal(newClaims, user.Claims.Select(claim => claim.ToClaim()), new ClaimComparer());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserEmailStoreTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserEmailStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string EmailAddress = \"test.user@domain.com\";\n        private static readonly string EmailAddressNormalized = EmailAddress.ToUpper();\n\n        private readonly IUserEmailStore<MongoDbIdentityUser> _mongoDbUserEmailStore;\n\n        public MongoDbUserEmailStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserEmailStore = mongoDbIdentityFixture.GetService<IUserEmailStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Email = EmailAddress;\n            user.NormalizedEmail = EmailAddressNormalized;\n            user.EmailConfirmed = false;\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_email_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(EmailAddress, await _mongoDbUserEmailStore.GetEmailAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_email_async()\n        {\n            var user = CreateUser();\n            var newEmail = \"new.email@address.com\";\n            await _mongoDbUserEmailStore.SetEmailAsync(user, newEmail, new CancellationToken());\n            Assert.Equal(newEmail, user.Email, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_normalized_email_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(EmailAddressNormalized, await _mongoDbUserEmailStore.GetNormalizedEmailAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_normalized_email_async()\n        {\n            var user = CreateUser();\n            var newEmailNormalized = \"new.email@address.com\".ToUpper();\n            await _mongoDbUserEmailStore.SetNormalizedEmailAsync(user, newEmailNormalized, new CancellationToken());\n            Assert.Equal(newEmailNormalized, user.NormalizedEmail, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_check_email_confirmed_async()\n        {\n            var user = CreateUser();\n            user.EmailConfirmed = false;\n            Assert.False(await _mongoDbUserEmailStore.GetEmailConfirmedAsync(user, new CancellationToken()));\n            user.EmailConfirmed = true;\n            Assert.True(await _mongoDbUserEmailStore.GetEmailConfirmedAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_email_confirmed_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserEmailStore.SetEmailConfirmedAsync(user, false, new CancellationToken());\n            Assert.False(user.EmailConfirmed);\n            await _mongoDbUserEmailStore.SetEmailConfirmedAsync(user, true, new CancellationToken());\n            Assert.True(user.EmailConfirmed);\n        }\n\n        [Fact]\n        public async Task Can_find_by_email_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, await _mongoDbUserEmailStore.FindByEmailAsync(EmailAddressNormalized, new CancellationToken()), new MongoDbIdentityUserComparer());\n            Assert.Null(await _mongoDbUserEmailStore.FindByEmailAsync(\"DNE@EMAIL.COM\", new CancellationToken()));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserLockoutStoreTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserLockoutStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private static readonly DateTime LockoutEndDate = DateTime.Now.AddDays(1);\n\n        private readonly IUserLockoutStore<MongoDbIdentityUser> _mongoDbUserLockoutStore;\n\n        public MongoDbUserLockoutStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserLockoutStore = mongoDbIdentityFixture.GetService<IUserLockoutStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.LockoutEnd = LockoutEndDate;\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_access_failed_count_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(user.AccessFailedCount, await _mongoDbUserLockoutStore.GetAccessFailedCountAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_check_lockout_enabled_async()\n        {\n            var user = CreateUser();\n            user.LockoutEnabled = false;\n            Assert.False(await _mongoDbUserLockoutStore.GetLockoutEnabledAsync(user, new CancellationToken()));\n            user.LockoutEnabled = true;\n            Assert.True(await _mongoDbUserLockoutStore.GetLockoutEnabledAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_lockout_enabled_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserLockoutStore.SetLockoutEnabledAsync(user, false, new CancellationToken());\n            Assert.False(user.LockoutEnabled);\n            await _mongoDbUserLockoutStore.SetLockoutEnabledAsync(user, true, new CancellationToken());\n            Assert.True(user.LockoutEnabled);\n        }\n\n        [Fact]\n        public async Task Can_get_lockout_end_date_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(user.LockoutEnd, await _mongoDbUserLockoutStore.GetLockoutEndDateAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_lockout_end_date_async()\n        {\n            var user = CreateUser();\n            var lockoutEndDate = DateTime.Now.AddDays(3);\n            await _mongoDbUserLockoutStore.SetLockoutEndDateAsync(user, lockoutEndDate, new CancellationToken());\n            Assert.Equal(lockoutEndDate, user.LockoutEnd);\n        }\n\n        [Fact]\n        public async Task Can_reset_access_failed_count_async()\n        {\n            var user = CreateUser();\n            user.AccessFailedCount = 10;\n            await _mongoDbUserLockoutStore.ResetAccessFailedCountAsync(user, new CancellationToken());\n            Assert.Equal(0, user.AccessFailedCount);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserLoginStoreTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserLoginStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private readonly IUserLoginStore<MongoDbIdentityUser> _mongoDbUserLoginStore;\n\n        private const string ProviderName = nameof(ProviderName);\n        private static readonly string ProviderKey = new Guid().ToString();\n        private const string ProviderDisplayName = nameof(ProviderDisplayName);\n\n        public MongoDbUserLoginStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserLoginStore = mongoDbIdentityFixture.GetService<IUserLoginStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Logins.Add(new MongoDbIdentityUserLogin\n            {\n                LoginProvider = ProviderName,\n                ProviderKey = ProviderKey,\n                ProviderDisplayName = ProviderDisplayName\n            });\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_add_login_async()\n        {\n            var user = CreateUser();\n            var userLoginInfo = new UserLoginInfo(\"Google\", \"1234567890abcdef\", \"Google+\");\n            await _mongoDbUserLoginStore.AddLoginAsync(user, userLoginInfo, new CancellationToken());\n            Assert.NotNull(user.Logins\n                .SingleOrDefault(identityUserLogin =>\n                    userLoginInfo.LoginProvider == identityUserLogin.LoginProvider\n                    && userLoginInfo.ProviderKey == identityUserLogin.ProviderKey\n                    && userLoginInfo.ProviderDisplayName == identityUserLogin.ProviderDisplayName));\n        }\n\n        [Fact]\n        public async Task Can_remove_login_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserLoginStore.RemoveLoginAsync(user, ProviderName, ProviderKey, new CancellationToken());\n            Assert.Empty(user.Logins);\n        }\n\n        [Fact]\n        public async Task Can_find_by_login_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, await _mongoDbUserLoginStore.FindByLoginAsync(ProviderName, ProviderKey, new CancellationToken()), new MongoDbIdentityUserComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_logins_async()\n        {\n            var user = CreateUser();\n            var login = (await _mongoDbUserLoginStore.GetLoginsAsync(user, new CancellationToken())).Single();\n            Assert.Equal(ProviderName, login.LoginProvider, StringComparer.Ordinal);\n            Assert.Equal(ProviderKey, login.ProviderKey, StringComparer.Ordinal);\n            Assert.Equal(ProviderDisplayName, login.ProviderDisplayName, StringComparer.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserPasswordStoreTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserPasswordStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private static readonly string PasswordHash = new Guid().ToString();\n\n        private readonly IUserPasswordStore<MongoDbIdentityUser> _mongoDbUserPasswordStore;\n\n        public MongoDbUserPasswordStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserPasswordStore = mongoDbIdentityFixture.GetService<IUserPasswordStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.PasswordHash = PasswordHash;\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_password_hash_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(PasswordHash, await _mongoDbUserPasswordStore.GetPasswordHashAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_password_hash_async()\n        {\n            var user = CreateUser();\n            var newPassword = new Guid().ToString();\n            await _mongoDbUserPasswordStore.SetPasswordHashAsync(user, newPassword, new CancellationToken());\n            Assert.Equal(newPassword, user.PasswordHash, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_check_has_password_async()\n        {\n            var user = CreateUser();\n            Assert.True(await _mongoDbUserPasswordStore.HasPasswordAsync(user, new CancellationToken()));\n            user.PasswordHash = null;\n            Assert.False(await _mongoDbUserPasswordStore.HasPasswordAsync(user, new CancellationToken()));\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserPhoneNumberStoreTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserPhoneNumberStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string PhoneNumber = \"+1.123.456.7890\";\n\n        private readonly IUserPhoneNumberStore<MongoDbIdentityUser> _mongoDbUserPhoneNumberStore;\n\n        public MongoDbUserPhoneNumberStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserPhoneNumberStore = mongoDbIdentityFixture.GetService<IUserPhoneNumberStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.PhoneNumber = PhoneNumber;\n            user.PhoneNumberConfirmed = true;\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_phone_number_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(PhoneNumber, await _mongoDbUserPhoneNumberStore.GetPhoneNumberAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_phone_number_async()\n        {\n            var user = CreateUser();\n            string newPhoneNumber = \"+1.987.654.3210\";\n            await _mongoDbUserPhoneNumberStore.SetPhoneNumberAsync(user, newPhoneNumber, new CancellationToken());\n            Assert.Equal(newPhoneNumber, user.PhoneNumber, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_check_phone_number_confirmed_async()\n        {\n            var user = CreateUser();\n            user.PhoneNumberConfirmed = false;\n            Assert.False(await _mongoDbUserPhoneNumberStore.GetPhoneNumberConfirmedAsync(user, new CancellationToken()));\n            user.PhoneNumberConfirmed = true;\n            Assert.True(await _mongoDbUserPhoneNumberStore.GetPhoneNumberConfirmedAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_phone_number_confirmed_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserPhoneNumberStore.SetPhoneNumberConfirmedAsync(user, false, new CancellationToken());\n            Assert.False(user.PhoneNumberConfirmed);\n            await _mongoDbUserPhoneNumberStore.SetPhoneNumberConfirmedAsync(user, true, new CancellationToken());\n            Assert.True(user.PhoneNumberConfirmed);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserRoleStoreTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserRoleStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private static readonly string RoleName1 = nameof(RoleName1);\n        private static readonly string NormalizedRoleName1 = RoleName1.ToUpper();\n        private static readonly string RoleName2 = nameof(RoleName2);\n        private static readonly string NormalizedRoleName2 = RoleName2.ToUpper();\n\n        private readonly IUserRoleStore<MongoDbIdentityUser> _mongoDbUserRoleStore;\n\n        public MongoDbUserRoleStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserRoleStore = mongoDbIdentityFixture.GetService<IUserRoleStore<MongoDbIdentityUser>>();\n            var roleStore = mongoDbIdentityFixture .GetService<IRoleStore<MongoDbIdentityRole>>();\n            if (roleStore.FindByNameAsync(NormalizedRoleName1, new CancellationToken()).Result == null)\n            {\n                roleStore.CreateAsync(new MongoDbIdentityRole\n                {\n                    RoleName = RoleName1,\n                    NormalizedRoleName = NormalizedRoleName1\n                }, new CancellationToken())\n                .Wait();\n            }\n            if (roleStore.FindByNameAsync(NormalizedRoleName2, new CancellationToken()).Result == null)\n            {\n                roleStore.CreateAsync(new MongoDbIdentityRole\n                {\n                    RoleName = RoleName2,\n                    NormalizedRoleName = NormalizedRoleName2\n                }, new CancellationToken())\n                .Wait();\n            }\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Roles.Add(new MongoDbIdentityUserRole()\n            {\n                RoleName = RoleName2,\n                NormalizedRoleName = NormalizedRoleName2\n            });\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_add_to_role_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserRoleStore.AddToRoleAsync(user, NormalizedRoleName1, new CancellationToken());\n            var userRoles = user.Roles.Select(role => role.RoleName).ToList();\n            Assert.Contains(RoleName1, userRoles, StringComparer.Ordinal);\n            Assert.Contains(RoleName2, userRoles, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_roles_async()\n        {\n            var user = CreateUser();\n            var roles = await _mongoDbUserRoleStore.GetRolesAsync(user, new CancellationToken());\n            Assert.DoesNotContain(RoleName1, roles, StringComparer.Ordinal);\n            Assert.Contains(RoleName2, roles, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_users_in_role_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, (await _mongoDbUserRoleStore.GetUsersInRoleAsync(NormalizedRoleName2, new CancellationToken())).Single(), new MongoDbIdentityUserComparer());\n        }\n\n        [Fact]\n        public async Task Can_remove_from_role_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserRoleStore.RemoveFromRoleAsync(user, NormalizedRoleName2, new CancellationToken());\n            Assert.Empty(user.Roles);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserSecurityStampStoreTests.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserSecurityStampStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private static readonly string SecurityStamp = new Guid().ToString();\n\n        private readonly IUserSecurityStampStore<MongoDbIdentityUser> _mongoDbUserSecurityStampStore;\n\n        public MongoDbUserSecurityStampStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserSecurityStampStore = mongoDbIdentityFixture.GetService<IUserSecurityStampStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.SecurityStamp = SecurityStamp;\n            return user;\n        }\n\n        [Fact]\n        public async Task Can_get_security_stamp_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(SecurityStamp, await _mongoDbUserSecurityStampStore.GetSecurityStampAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_security_stamp_async()\n        {\n            var user = CreateUser();\n            string newSecurityStamp = new Guid().ToString();\n            await _mongoDbUserSecurityStampStore.SetSecurityStampAsync(user, newSecurityStamp, new CancellationToken());\n            Assert.Equal(newSecurityStamp, user.SecurityStamp, StringComparer.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserStoreTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private readonly IUserStore<MongoDbIdentityUser> _mongoDbUserStore;\n\n        public MongoDbUserStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserStore = mongoDbIdentityFixture.GetService<IUserStore<MongoDbIdentityUser>>();\n        }\n\n        [Fact]\n        public async Task Can_create_user_async()\n        {\n            Assert.NotNull(await CreateUserInDatabase());\n        }\n\n        [Fact]\n        public async Task Can_delete_user_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(IdentityResult.Success, await _mongoDbUserStore.DeleteAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_find_by_id_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, await _mongoDbUserStore.FindByIdAsync(user.Id.ToString(), new CancellationToken()), new MongoDbIdentityUserComparer());\n        }\n\n        [Fact]\n        public async Task Can_find_by_name_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user, await _mongoDbUserStore.FindByNameAsync(user.NormalizedUserName, new CancellationToken()), new MongoDbIdentityUserComparer());\n        }\n\n        [Fact]\n        public async Task Can_get_normalized_user_name_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(user.NormalizedUserName, await _mongoDbUserStore.GetNormalizedUserNameAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_user_id_async()\n        {\n            var user = await CreateUserInDatabase();\n            Assert.Equal(user.Id.ToString(), await _mongoDbUserStore.GetUserIdAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_get_user_name_async()\n        {\n            var user = CreateUser();\n            Assert.Equal(user.UserName, await _mongoDbUserStore.GetUserNameAsync(user, new CancellationToken()), StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_normalized_user_name_async()\n        {\n            var user = await CreateUserInDatabase();\n            var newNormalizedUserName = \"NORMALIZED.TEST.USER\";\n            await _mongoDbUserStore.SetNormalizedUserNameAsync(user, newNormalizedUserName, new CancellationToken());\n            Assert.Equal(newNormalizedUserName, user.NormalizedUserName, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_set_user_name_async()\n        {\n            var user = await CreateUserInDatabase();\n            var newUserName = \"another.user@different.com\";\n            await _mongoDbUserStore.SetUserNameAsync(user, newUserName, new CancellationToken());\n            Assert.Equal(newUserName, user.UserName, StringComparer.Ordinal);\n        }\n\n        [Fact]\n        public async Task Can_update_user_async()\n        {\n            var user = await CreateUserInDatabase();\n            var newUserName = \"another.user@different.com\";\n            var newNormalizedUserName = \"NORMALIZED.TEST.USER\";\n            user.UserName = newUserName;\n            user.NormalizedUserName = newNormalizedUserName;\n            Assert.Equal(IdentityResult.Success, await _mongoDbUserStore.UpdateAsync(user, new CancellationToken()));\n            Assert.Equal(user, await _mongoDbUserStore.FindByNameAsync(newNormalizedUserName, new CancellationToken()), new MongoDbIdentityUserComparer());\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserTwoFactorRecoveryCodeStoreTests.cs",
    "content": "﻿using System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserTwoFactorRecoveryCodeStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private const string RecoveryCode1 = nameof(RecoveryCode1);\n        private const string RecoveryCode2 = nameof(RecoveryCode2);\n        private const string RecoveryCode3 = nameof(RecoveryCode3);\n        private static readonly string[] RecoveryCodes = new string[]\n        {\n            RecoveryCode1, RecoveryCode2, RecoveryCode3\n        };\n\n        private readonly IUserTwoFactorRecoveryCodeStore<MongoDbIdentityUser> _mongoDbUserTwoFactorRecoveryCodeStore;\n\n        public MongoDbUserTwoFactorRecoveryCodeStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserTwoFactorRecoveryCodeStore = mongoDbIdentityFixture.GetService<IUserTwoFactorRecoveryCodeStore<MongoDbIdentityUser>>();\n        }\n\n        protected override MongoDbIdentityUser CreateUser()\n        {\n            var user = base.CreateUser();\n            user.Logins.Add(new MongoDbIdentityUserLogin\n            {\n                LoginProvider = \"[BlueshiftMongoDbUserStore]\",\n                ProviderKey = new Guid().ToString(),\n                ProviderDisplayName = \"[BlueshiftMongoDbUserStore]\",\n                UserTokens =\n                {\n                    new MongoDbIdentityUserToken() { Name = \"RecoveryCodes\", Value = string.Join(\";\", RecoveryCodes) }\n                }\n            });\n            return user;\n        }\n\n        [Theory]\n        [InlineData(RecoveryCode1)]\n        [InlineData(RecoveryCode2)]\n        [InlineData(RecoveryCode3)]\n        public async Task Can_redeem_codes_exactly_once_async(string recoveryCode)\n        {\n            var user = CreateUser();\n            Assert.True(await _mongoDbUserTwoFactorRecoveryCodeStore.RedeemCodeAsync(user, recoveryCode, new CancellationToken()));\n            Assert.False(await _mongoDbUserTwoFactorRecoveryCodeStore.RedeemCodeAsync(user, recoveryCode, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_replace_codes_async()\n        {\n            var user = CreateUser();\n            var newRecoveryCodes = new [] { \"New Code 1\", \"New Code 2\", \"New Code 3\" };\n            await _mongoDbUserTwoFactorRecoveryCodeStore.ReplaceCodesAsync(user, newRecoveryCodes, new CancellationToken());\n            var recoveryCodes = user.Logins\n                   .First(login => login.LoginProvider == \"[BlueshiftMongoDbUserStore]\")\n                   .UserTokens\n                   .First(userToken => userToken.Name == \"RecoveryCodes\").Value;\n            Assert.DoesNotContain(RecoveryCode1, recoveryCodes, StringComparison.Ordinal);\n            Assert.DoesNotContain(RecoveryCode2, recoveryCodes, StringComparison.Ordinal);\n            Assert.DoesNotContain(RecoveryCode3, recoveryCodes, StringComparison.Ordinal);\n            Assert.Equal(string.Join(\";\", newRecoveryCodes), recoveryCodes, StringComparer.Ordinal);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/MongoDbUserTwoFactorStoreTests.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Identity;\nusing Xunit;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class MongoDbUserTwoFactorStoreTests : MongoDbIdentityStoreTestBase\n    {\n        private readonly IUserTwoFactorStore<MongoDbIdentityUser> _mongoDbUserTwoFactorStore;\n\n        public MongoDbUserTwoFactorStoreTests(MongoDbIdentityFixture mongoDbIdentityFixture)\n            : base(mongoDbIdentityFixture)\n        {\n            _mongoDbUserTwoFactorStore = mongoDbIdentityFixture.GetService<IUserTwoFactorStore<MongoDbIdentityUser>>();\n        }\n\n        [Fact]\n        public async Task Can_check_two_factor_enabled_async()\n        {\n            var user = CreateUser();\n            user.TwoFactorEnabled = false;\n            Assert.False(await _mongoDbUserTwoFactorStore.GetTwoFactorEnabledAsync(user, new CancellationToken()));\n            user.TwoFactorEnabled = true;\n            Assert.True(await _mongoDbUserTwoFactorStore.GetTwoFactorEnabledAsync(user, new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task Can_set_two_factor_enabled_async()\n        {\n            var user = CreateUser();\n            await _mongoDbUserTwoFactorStore.SetTwoFactorEnabledAsync(user, false, new CancellationToken());\n            Assert.False(user.TwoFactorEnabled);\n            await _mongoDbUserTwoFactorStore.SetTwoFactorEnabledAsync(user, true, new CancellationToken());\n            Assert.True(user.TwoFactorEnabled);\n        }\n    }\n}"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/Properties/AssemblyInfo.cs",
    "content": "﻿// Copyright (c) Blueshift Software, LLC. All rights reserved.\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\n\nusing System.Reflection;\nusing System.Resources;\nusing Xunit;\n\n[assembly: NeutralResourcesLanguage(\"en-US\")]\n[assembly: AssemblyMetadata(\"Serviceable\", \"True\")]\n\n[assembly: TestFramework(\"Microsoft.EntityFrameworkCore.Specification.Tests.TestUtilities.Xunit.ConditionalTestFramework\", \"Microsoft.EntityFrameworkCore.Specification.Tests\")]"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/_Comparers.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Security.Claims;\nusing Blueshift.Identity.MongoDB;\n\nnamespace Blueshift.Identity.MongoDB.Tests\n{\n    public class ClaimComparer : EqualityComparer<Claim>\n    {\n        public override bool Equals(Claim claim1, Claim claim2)\n            => (claim1 != null && claim2 != null)\n               || string.Equals(claim1.Type, claim2.Type, StringComparison.Ordinal)\n               && string.Equals(claim1.Value, claim2.Value, StringComparison.Ordinal);\n\n        public override int GetHashCode(Claim obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n\n    public class MongoDbIdentityRoleComparer : EqualityComparer<MongoDbIdentityRole>\n    {\n        public override bool Equals(MongoDbIdentityRole role1, MongoDbIdentityRole role2)\n            => (role1 != null && role2 != null)\n                || role1.Id == role2.Id\n                && string.Equals(role1.RoleName, role2.RoleName, StringComparison.Ordinal)\n                && string.Equals(role1.NormalizedRoleName, role2.NormalizedRoleName, StringComparison.Ordinal)\n                && role1.Claims.Count == role2.Claims.Count\n                && role1.Claims.All(item => role2.Claims.Contains(item, new MongoDbIdentityClaimComparer()))\n                && role1.Claims.All(item => role2.Claims.Contains(item, new MongoDbIdentityClaimComparer()));\n\n        public override int GetHashCode(MongoDbIdentityRole obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n\n    public class MongoDbIdentityUserComparer : EqualityComparer<MongoDbIdentityUser>\n    {\n        public override bool Equals(MongoDbIdentityUser user1, MongoDbIdentityUser user2)\n            => (user1 != null && user2 != null)\n                || user1.Id == user2.Id\n                && string.Equals(user1.UserName, user2.UserName, StringComparison.Ordinal)\n                && string.Equals(user1.NormalizedUserName, user2.NormalizedUserName, StringComparison.Ordinal)\n                && user1.Logins.Count == user2.Logins.Count\n                && user1.Logins.All(item => user2.Logins.Contains(item, new MongoDbIdentityUserLoginComparer()))\n                && user1.Logins.All(item => user2.Logins.Contains(item, new MongoDbIdentityUserLoginComparer()))\n                && user1.Claims.Count == user2.Claims.Count\n                && user1.Claims.All(item => user2.Claims.Contains(item, new MongoDbIdentityClaimComparer()))\n                && user1.Claims.All(item => user2.Claims.Contains(item, new MongoDbIdentityClaimComparer()));\n\n        public override int GetHashCode(MongoDbIdentityUser obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n\n    public class MongoDbIdentityUserLoginComparer : EqualityComparer<MongoDbIdentityUserLogin>\n    {\n        public override bool Equals(MongoDbIdentityUserLogin userLogin1, MongoDbIdentityUserLogin userLogin2)\n            => (userLogin1 != null && userLogin2 != null)\n                || string.Equals(userLogin1.LoginProvider, userLogin2.LoginProvider, StringComparison.Ordinal)\n                && string.Equals(userLogin1.ProviderKey, userLogin2.ProviderKey, StringComparison.Ordinal)\n                && string.Equals(userLogin1.ProviderDisplayName, userLogin2.ProviderDisplayName, StringComparison.Ordinal)\n                && userLogin1.UserTokens.Count == userLogin2.UserTokens.Count\n                && userLogin1.UserTokens.All(item => userLogin2.UserTokens.Contains(item, new MongoDbIdentityUserTokenComparer()))\n                && userLogin1.UserTokens.All(item => userLogin2.UserTokens.Contains(item, new MongoDbIdentityUserTokenComparer()));\n\n        public override int GetHashCode(MongoDbIdentityUserLogin obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n\n    public class MongoDbIdentityUserTokenComparer : EqualityComparer<MongoDbIdentityUserToken>\n    {\n        public override bool Equals(MongoDbIdentityUserToken userToken1, MongoDbIdentityUserToken userToken2)\n            => (userToken1 != null && userToken2 != null)\n                || string.Equals(userToken1.Name, userToken2.Name, StringComparison.Ordinal)\n                && string.Equals(userToken1.Value, userToken2.Value, StringComparison.Ordinal);\n\n        public override int GetHashCode(MongoDbIdentityUserToken obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n\n    public class MongoDbIdentityClaimComparer : EqualityComparer<MongoDbIdentityClaim>\n    {\n        public override bool Equals(MongoDbIdentityClaim claim1, MongoDbIdentityClaim claim2)\n            => (claim1 != null && claim2 != null)\n                || string.Equals(claim1.ClaimType, claim2.ClaimType, StringComparison.Ordinal)\n                && string.Equals(claim1.ClaimValue, claim2.ClaimValue, StringComparison.Ordinal);\n\n        public override int GetHashCode(MongoDbIdentityClaim obj)\n            => obj?.GetHashCode() ?? throw new ArgumentNullException(nameof(obj));\n    }\n}\n"
  },
  {
    "path": "test/Blueshift.Identity.MongoDB.Tests/xunit.runner.json",
    "content": "﻿{\n  \"longRunningTestSeconds\": 30,\n  \"parallelizeAssembly\": false\n}"
  },
  {
    "path": "test/Directory.Build.props",
    "content": "<Project>\n  <Import Project=\"..\\Directory.Build.props\" />\n\n  <PropertyGroup>\n    <DeveloperTestFrameworks>netcoreapp2.1</DeveloperTestFrameworks>\n    <TestFrameworks>$(DeveloperTestFrameworks)</TestFrameworks>\n    <TestFrameworks Condition=\" '$(DeveloperBuild)' != 'True' \">netcoreapp2.0;netcoreapp2.1</TestFrameworks>\n    <TestFrameworks Condition=\" '$(DeveloperBuild)' != 'True' AND '$(CoreOnly)' != 'True' AND '$(OS)' == 'Windows_NT' \">net461;$(TestFrameworks)</TestFrameworks>\n  </PropertyGroup>\n\n  <PropertyGroup>\n    <NoWarn>$(NoWarn);CA1822;xUnit1004</NoWarn>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"$(MicrosoftNETTestSdkPackageVersion)\" NoWarn=\"KRB4002\" />\n    <PackageReference Include=\"Moq\" Version=\"$(MoqPackageVersion)\" NoWarn=\"KRB4002\" />\n    <PackageReference Include=\"xunit\" Version=\"$(XunitPackageVersion)\" NoWarn=\"KRB4002\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"$(XunitRunnerVisualstudioPackageVersion)\" NoWarn=\"KRB4002\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "version.props",
    "content": "<!-- This file may be overwritten by automation. -->\n<Project>\n  <PropertyGroup>\n    <VersionPrefix>2.1.0</VersionPrefix>\n    <VersionSuffix>preview2</VersionSuffix>\n    <PackageVersion Condition=\"'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' \">$(VersionPrefix)</PackageVersion>\n    <PackageVersion Condition=\"'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' \">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>\n    <VersionSuffix Condition=\"'$(VersionSuffix)' != '' And '$(BuildNumber)' != ''\">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>\n  </PropertyGroup>\n</Project>\n"
  }
]