Introduce CommunityToolkit.VectorData.CosmosNoSql#21
Conversation
Port Cosmos DB NoSQL MEVD provider from roji/azure-cosmos-dotnet-v3@bc9919f5 into this repository. - Source in MEVD/src/Cosmos with CommunityToolkit.VectorData.Cosmos namespace - Unit tests in MEVD/test/Cosmos.UnitTests (xunit) - Conformance tests in MEVD/test/Cosmos.ConformanceTests - .NET Foundation copyright headers - Add Microsoft.Azure.Cosmos 3.61.0 to Directory.Packages.props - Update MEVD.slnf and CommunityToolkit.AI.slnx
…lator - Add Testcontainers.CosmosDb package reference - Rewrite CosmosNoSqlTestStore to use CosmosDbContainer with vnext-latest image - Add CosmosNoSqlTestEnvironment for external connection string support - Fix indexing policy path from '/' to '/*' for vNext compatibility - Replace SELECT VALUE(c.id) with SELECT c.id + ContainerIdResult class - Change DefaultIndexKind to DiskAnn (only type supported by vNext) - Override SearchAsync_with_Skip (OFFSET not supported with DiskANN) - Use thread-safe initialization with SemaphoreSlim
- move test classes into separate files - disable failing tests
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Azure Cosmos DB for NoSQL provider implementation for Microsoft.Extensions.VectorData under CommunityToolkit.VectorData.Cosmos, along with unit + conformance test projects and solution/package wiring to build and validate it within the MEVD repo.
Changes:
- Added the
CommunityToolkit.VectorData.Cosmosprovider (vector store, collections, mapping, filter translation, DI extensions, options, and supporting utilities). - Added Cosmos-specific unit tests and conformance tests (including Testcontainers-based emulator support).
- Wired the new projects into solution filters/solution and added required package versions (Cosmos SDK + Testcontainers.CosmosDb).
Reviewed changes
Copilot reviewed 46 out of 46 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| MEVD/test/Cosmos.UnitTests/CosmosNoSqlOptionsTests.cs | Adds unit tests for configuring Cosmos NoSQL options objects. |
| MEVD/test/Cosmos.UnitTests/Cosmos.UnitTests.csproj | New unit test project for the Cosmos provider. |
| MEVD/test/Cosmos.ConformanceTests/Support/CosmosNoSqlTestStore.cs | Test store bootstrapping Cosmos emulator / connection, and collection creation helpers. |
| MEVD/test/Cosmos.ConformanceTests/Support/CosmosNoSqlTestEnvironment.cs | Loads Cosmos test connection settings from JSON/environment. |
| MEVD/test/Cosmos.ConformanceTests/Support/CosmosNoSqlFixture.cs | Provides a shared fixture for Cosmos conformance tests. |
| MEVD/test/Cosmos.ConformanceTests/Support/CosmosNoSqlConformanceTestHelpers.cs | Helper to adjust vector storage name casing for Cosmos behaviors. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlTestSuiteImplementationTests.cs | Declares Cosmos conformance suite implementation and ignored bases. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlNoVectorModelTests.cs | Cosmos conformance tests for “no vector” record model scenario. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlNoDataModelTests.cs | Cosmos conformance tests for “no data” record model scenario. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlMultiVectorModelTests.cs | Cosmos conformance tests for multi-vector record models. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlKeyTypeTests.cs | Cosmos conformance tests for supported key types. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlIndexKindTests.cs | Cosmos conformance tests for index kind behaviors/limitations. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlHybridSearchTests.cs | Cosmos hybrid search conformance tests (currently disabled/internal due to emulator limits). |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlFilterTests.cs | Cosmos filter conformance tests (currently disabled/internal due to emulator limits). |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlEmbeddingTypeTests.cs | Cosmos conformance tests for embedding vector types and schema generation. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlEmbeddingGenerationTests.cs | Cosmos conformance tests for embedding generation + DI registration paths. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlDynamicModelTests.cs | Cosmos conformance tests for dynamic (dictionary-based) models. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlDistanceFunctionTests.cs | Cosmos conformance tests for supported/unsupported distance functions. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlDependencyInjectionTests.cs | Cosmos conformance tests for DI registration of vector store/collections. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlDataTypeTests.cs | Cosmos conformance tests for supported default data types. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlCollectionManagementTests.cs | Cosmos conformance tests for collection lifecycle management. |
| MEVD/test/Cosmos.ConformanceTests/CosmosNoSqlBasicModelTests.cs | Cosmos conformance tests for basic record models and query behaviors. |
| MEVD/test/Cosmos.ConformanceTests/Cosmos.ConformanceTests.csproj | New conformance test project for Cosmos provider. |
| MEVD/src/Cosmos/README.md | Adds package README with install + usage + DI snippets. |
| MEVD/src/Cosmos/ICosmosNoSQLMapper.cs | Defines internal mapping contract between data model and Cosmos JSON model. |
| MEVD/src/Cosmos/ErrorHandlingFeedIterator.cs | Wraps Cosmos FeedIterator to route exceptions through vector-store error handling. |
| MEVD/src/Cosmos/CosmosNoSqlVectorStoreOptions.cs | Adds vector store options (serializer options + embedding generator). |
| MEVD/src/Cosmos/CosmosNoSqlVectorStore.cs | Implements Cosmos-backed VectorStore (collections, metadata, listing/deletion helpers). |
| MEVD/src/Cosmos/CosmosNoSqlServiceCollectionExtensions.cs | Adds DI registration extensions for vector store and collections (keyed + non-keyed). |
| MEVD/src/Cosmos/CosmosNoSqlModelBuilder.cs | Builds collection models and validates supported key/data/vector property types. |
| MEVD/src/Cosmos/CosmosNoSqlMapper.cs | Maps typed records to/from Cosmos JSON, including embedding serialization behavior. |
| MEVD/src/Cosmos/CosmosNoSqlKey.cs | Introduces composite key type (document id + partition key). |
| MEVD/src/Cosmos/CosmosNoSqlFilterTranslator.cs | Translates filter expressions into Cosmos SQL WHERE clauses with parameters. |
| MEVD/src/Cosmos/CosmosNoSqlDynamicMapper.cs | Maps dynamic Dictionary<string, object?> records to/from Cosmos JSON. |
| MEVD/src/Cosmos/CosmosNoSqlDynamicCollection.cs | Provides a dynamic collection wrapper specialized for dictionary records. |
| MEVD/src/Cosmos/CosmosNoSqlConstants.cs | Centralizes Cosmos provider constants (system name, id key, alias). |
| MEVD/src/Cosmos/CosmosNoSqlCollectionQueryBuilder.cs | Builds Cosmos SQL queries for vector + hybrid search and filtered retrieval. |
| MEVD/src/Cosmos/CosmosNoSqlCollectionOptions.cs | Adds collection options (partition key properties, indexing mode, automatic indexing). |
| MEVD/src/Cosmos/CosmosNoSqlCollection.cs | Implements Cosmos-backed VectorStoreCollection with CRUD/search, indexing, PK building. |
| MEVD/src/Cosmos/Cosmos.csproj | Adds the new Cosmos provider package project (multi-targeted). |
| MEVD/src/Cosmos/ClientWrapper.cs | Manages CosmosClient ownership and reference-counted sharing/disposal. |
| MEVD/src/Cosmos/ByteArrayJsonConverter.cs | Adds JSON converters to serialize byte vectors as numeric arrays (Cosmos requirement). |
| MEVD/src/Cosmos/AssemblyInfo.cs | Adds assembly-level license header file. |
| MEVD/MEVD.slnf | Adds Cosmos projects to the MEVD solution filter. |
| Directory.Packages.props | Adds package versions for Cosmos SDK and Testcontainers.CosmosDb. |
| CommunityToolkit.AI.slnx | Adds Cosmos projects to the main solution structure. |
…d solution references
| // Embedding<T> is stored as a simple JSON array, so convert it to the expected object shape for deserialization | ||
| if (vectorProperty.Type == typeof(Embedding<float>) | ||
| || vectorProperty.Type == typeof(Embedding<byte>) | ||
| || vectorProperty.Type == typeof(Embedding<sbyte>)) | ||
| { | ||
| storageModel[vectorProperty.StorageName] = new JsonObject |
adamsitnik
left a comment
There was a problem hiding this comment.
LGTM, ready for review
| private readonly Lazy<CosmosNoSqlTestStore> _store = new(() => new CosmosNoSqlTestStore(nameof(CosmosNoSqlFixture))); | ||
|
|
||
| public override TestStore TestStore => _store.Value; |
There was a problem hiding this comment.
To other reviewers: typically VectorStoreFixture.TestStore returns a static, cached singleton of TestStore. The Cosmos emulator struggles today if we run multiple queries against it, even sequentially. What works best is if we have a dedicated Database for every test class. So this and other fixtures create their own CosmosNoSqlTestStore instances.
Thanks to the fact that each of them uses a different container instance, we can run tests in parallel and reduce the time it takes to run them from 100s to 20s (at least on my machine)
| { | ||
| public override Task SearchAsync_with_Skip() | ||
| { | ||
| // The vNext emulator's DiskANN index does not support OFFSET in vector search. |
There was a problem hiding this comment.
To other code reviewers: as soon as dotnet/extensions migrates to xUnit 3 (dotnet/extensions#7607), we are going to be able to use Assert.Skip here and have a "proper" way to skip the tests
| namespace CosmosNoSql.ConformanceTests; | ||
|
|
||
| // The type is internal to disable the tests due to emulator limitations | ||
| internal sealed class CosmosNoSqlDataTypeTests(CosmosNoSqlDataTypeTests.Fixture fixture) |
There was a problem hiding this comment.
to other code reviewers: this is a workaround. The emulator simply can't handle it today, so instead of removing/commenting out the code I've marked this and two other classes as internal. I intend to log dedicated emulator bugs once this repo becomes public.
| public override async Task<bool> CollectionExistsAsync(CancellationToken cancellationToken = default) | ||
| { | ||
| const string OperationName = "ListCollectionNamesAsync"; | ||
| const string Query = "SELECT c.id FROM c WHERE c.id = @collectionName"; |
There was a problem hiding this comment.
To other code reviewers: this is a product change in order to get tests passing on emulator. The change was introduced by copilot in 2476214
What it did was more or less:
-"SELECT VALUE(c.id) FROM c WHERE c.id = @collectionName"
+"SELECT c.id FROM c WHERE c.id = @collectionName"I've verified and the tests are not going to pass without it. It may be just an emulator limitation (https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux).
@roji PTAL
There was a problem hiding this comment.
OK, that's slightly uglier but if CollectionExistsAsync continues to work reliably, it should be fine. Though it's a super, super basic query form - very odd that it doesn't work. If you have a moment to actually try it (the emulator has a local web interface you can run queries on) that would confirm, because this is slightly fishy.
I'd suggest reporting with a minimal repro on https://github.com/Azure/azure-cosmos-db-emulator-docker, as I'm 99% sure this was working on the Windows emulator.
There was a problem hiding this comment.
I've created #23, will start reporting as soon as I've some free cycles. I wanted to do it ASAP but currently I have hard time creating Cosmos DB instance via Azure Portal (to verify my repros)
There was a problem hiding this comment.
It might be easier to just use the Windows emulator locally for that, in case Azure gives you trouble.
| } | ||
|
|
||
| // Adding special mandatory indexing path. | ||
| indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" }); |
There was a problem hiding this comment.
To other code reviewers: this is another product change in order to get tests passing on emulator. The change was introduced by copilot in 2476214
What it did was more or less:
-indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/" });
+indexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });I've verified and the tests are not going to pass without it. It may be just an emulator limitation (https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux).
@roji PTAL
There was a problem hiding this comment.
I'm no expert in Cosmos indexing policies, but this does look a bit odd... If the docs say the two are the same then no problem of course, but I'd signal this to the Linux emulator folks as well (everything was working with the Windows one).
| /// <inheritdoc /> | ||
| public override async IAsyncEnumerable<string> ListCollectionNamesAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) | ||
| { | ||
| const string Query = "SELECT c.id FROM c"; |
There was a problem hiding this comment.
To other code reviewers: this is another product change in order to get tests passing on emulator. The change was introduced by copilot in 2476214
What it did was more or less:
-"SELECT VALUE(c.id) FROM c"
+"SELECT c.id FROM c"I've verified and the tests are not going to pass without it. It may be just an emulator limitation (https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux).
@roji PTAL
roji
left a comment
There was a problem hiding this comment.
Rubber-stamping as this is essentially just moving of existing code.
No description provided.