Apache.Calcite.Cosmos.Adapter
1.0.0-pre.1
dotnet add package Apache.Calcite.Cosmos.Adapter --version 1.0.0-pre.1
NuGet\Install-Package Apache.Calcite.Cosmos.Adapter -Version 1.0.0-pre.1
<PackageReference Include="Apache.Calcite.Cosmos.Adapter" Version="1.0.0-pre.1" />
<PackageVersion Include="Apache.Calcite.Cosmos.Adapter" Version="1.0.0-pre.1" />
<PackageReference Include="Apache.Calcite.Cosmos.Adapter" />
paket add Apache.Calcite.Cosmos.Adapter --version 1.0.0-pre.1
#r "nuget: Apache.Calcite.Cosmos.Adapter, 1.0.0-pre.1"
#:package Apache.Calcite.Cosmos.Adapter@1.0.0-pre.1
#addin nuget:?package=Apache.Calcite.Cosmos.Adapter&version=1.0.0-pre.1&prerelease
#tool nuget:?package=Apache.Calcite.Cosmos.Adapter&version=1.0.0-pre.1&prerelease
Apache.Calcite.Cosmos.Adapter
Apache.Calcite.Cosmos.Adapter lets Apache Calcite treat Azure Cosmos DB containers as first-class relational schemas.
Rather than going through ADO.NET or JDBC, the adapter translates the relational plan into Cosmos SQL — the query dialect the Cosmos DB engine natively accepts — and executes it against the container.
How it works
- A Cosmos database is registered with Calcite as a schema, one table per container.
- Calcite's planner converts as much of the plan as possible into the Cosmos calling convention (
CosmosConvention). - Nodes in that convention are rendered to Cosmos SQL and executed by the Cosmos query engine.
- Results leave the convention as an
IAsyncEnumerable, into theClrAsyncEnumerableConventionprovided byApache.Calcite.Extensions. - Anything Cosmos cannot express is executed in-process by Calcite, under that convention.
Queries are asynchronous
A query over a Cosmos table plans only when the root is asked for in ClrAsyncEnumerableConvention.
This is a property of the service, not a limitation of the adapter. The Cosmos v3 SDK has no synchronous data-plane API — a page of results arrives only by awaiting FeedIterator.ReadNextAsync — so a synchronous plan could do nothing but block a thread for a network round trip per continuation. Rather than hide that behind an IEnumerable, the adapter offers only the asynchronous exit.
A container has no row schema, so a table is modelled as one map column carrying the whole document, plus promoted scalar columns for paths the service guarantees or the container declares — id, _ts, _etag, and the partition key. Nothing is inferred from sampling documents.
Install
dotnet add package Apache.Calcite.Cosmos.Adapter
Register a database
{
"name": "COSMOS",
"type": "custom",
"factory": "Apache.Calcite.Cosmos.Adapter.CosmosSchemaFactory, Apache.Calcite.Cosmos.Adapter",
"operand": {
"endpoint": "https://account.documents.azure.com:443/",
"key": "…",
"database": "inventory",
"containers": [ "products", "orders" ]
}
}
Omit containers to expose every container in the database.
Pushdown
| Operator | Rendered as |
|---|---|
| Filter | WHERE |
| Project | SELECT VALUE { … } |
| Sort | ORDER BY, OFFSET/LIMIT |
| Array traversal | JOIN alias IN path |
Relational joins, UNION/INTERSECT/EXCEPT, and HAVING have no Cosmos equivalent and are evaluated in-process by Calcite. Multi-property ORDER BY is pushed down only when the container declares a matching composite index, since the service rejects it otherwise.
Full text search
Cosmos has full text search and SQL does not, so the functions come from this adapter. Chain its operator table into the one the validator is built with:
SqlOperatorTables.chain(SqlStdOperatorTable.instance(), CosmosOperators.Instance)
FULLTEXTCONTAINS, FULLTEXTCONTAINSALL and FULLTEXTCONTAINSANY are then usable in a WHERE clause and push down to the service. The first argument must be a property path.
Ranking works too. ORDER BY FULLTEXTSCORE(c."_MAP"['name'], 'steel') FETCH FIRST 10 ROWS ONLY becomes ORDER BY RANK, and RRF(...) fuses two scores for hybrid search. The score is never projected — the service forbids it — so it ranks the rows and does not appear in the result. See DESIGN.md.
What a query cost
Cosmos charges in request units and reports the charge on every response. The adapter records it, on a Meter and an ActivitySource both named Apache.Calcite.Cosmos.Adapter:
cosmos.request_charge |
Request units, one measurement per response |
cosmos.responses |
Responses received |
cosmos.query (span) |
One statement, first request to last page |
Both instruments are tagged with cosmos.container and with cosmos.request_kind, which is query or point_read — so a point read can be told from the query it replaced. Collect them however you already collect .NET telemetry:
builder.Services.AddOpenTelemetry()
.WithMetrics(m => m.AddMeter("Apache.Calcite.Cosmos.Adapter"))
.WithTracing(t => t.AddSource("Apache.Calcite.Cosmos.Adapter"));
Add "indexMetrics": true to the operand to have the service report which indexes each statement used; it lands on the span as cosmos.index_metrics. Off by default, because the service computes it per query.
Status
Under development. Statement generation, container metadata, the schema and table layer, the scan/filter/project/sort/unnest/aggregate/rank nodes, and execution inside a Calcite plan are in place and tested. INSERT and DELETE are supported — Cosmos SQL has no DML, so a write is item CRUD over the rows a TableModify supplies rather than generated text; UPDATE is declined until it can be a patch rather than a read-modify-write. What an insert writes when the map column and a promoted column describe the same document is recorded in DESIGN.md under What an insert writes. Every emitted statement form is executed against a live service, and the suite runs against a real account when COSMOS_TEST_ENDPOINT and COSMOS_TEST_KEY name one — which the emulator is not a substitute for, it having been found to accept statements the service rejects and reject features the service implements. See DESIGN.md, including its record of assumptions still to be settled.
Further reading
- Apache Calcite documentation
- Calcite adapters overview
- Cosmos DB SQL query reference
- Source repository
License
Apache License 2.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Apache.Calcite.Extensions (>= 2.0.0-pre.7)
- Azure.Identity (>= 1.21.0)
- IKVM (>= 8.15.0)
- IKVM.Java.Extensions (>= 8.15.0)
- Microsoft.Azure.Cosmos (>= 3.62.1)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-pre.1 | 39 | 8/14/2026 |