CosmosQuery 0.2.0

dotnet add package CosmosQuery --version 0.2.0                
NuGet\Install-Package CosmosQuery -Version 0.2.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CosmosQuery" Version="0.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add CosmosQuery --version 0.2.0                
#r "nuget: CosmosQuery, 0.2.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install CosmosQuery as a Cake Addin
#addin nuget:?package=CosmosQuery&version=0.2.0

// Install CosmosQuery as a Cake Tool
#tool nuget:?package=CosmosQuery&version=0.2.0                

CosmosQuery

CI Nuget (with prereleases)

CosmosQuery generates an Expression tree from the supplied ODataQueryOptions. This library uses AutoMapper's Queryable Extentions in conjunction with custom Expression builders to generate an Expression tree which can be parsed by the Cosmos DB LINQ provider. Furthermore, because AutoMapper is used for query projection you do not have to expose your entity types and can instead use DTO’s (Data Transfer Object) in your public facing API.

<br>

Where this library excels is how it deals with complex types. Currently OData does not provide a means of $expanding complex types. The consequence of this when using something like EFCore is that your complex data members will be null after performing a query unless the consumer of your API explicitly $select’s said data members. This can quickly become cumbersome when dealing with complex documents.

<br>

What CosmosQuery does instead is treat complex types as just another property of your entity type. In other words, all complex types are automatically expanded and pulled from the database. The data being pulled from the DB can still be controlled using the $select operator.

Supported Operations

Currently CosmosQuery supports the following OData operations in both a query and subquery:

  1. $select
  2. $filter
  3. $orderby
  4. $top
  5. $skip
  6. $count

Although this library currently supports the use of $orderby, $top, and $skip within a subquery Cosmos DB does not.

Usage

<b>Step1</b>

<hr>

Set up your DTO to Entity mappings for AutoMapper so that it can correctly project the incoming OData query from your DTO type(s) to your Entity type(s).

<br>

If you only want to include properties explicitly (E.g., the consumer of the API has to explicitly $select which properties they want included in the results) then make sure to enable Explicit expansion on your properties.

    public class Mappings : AutoMapper.Profile
    {
        public Mappings()
        {
            CreateMap<Entity, DTO>()
                .ForMember(d => d.Name, o => o.MapFrom(s => s.FullName))                
                .ForAllMembers(o => o.ExplicitExpansion());
        }
    }

<b>Step2</b>

<hr>

Set up the actions on your controller(s) to accept a ODataQueryOptions. <br> Do not decorate your actions with the [EnableQuery] attribute as this will result in some operations being applied more than once.

public class MyController : ODataController
{
    private readonly CosmosClient _client;
    private readonly IMapper _mapper;

    public MyController(CosmosClient client, IMapper mapper)
    {
        _client = client;
        _mapper = mapper;
    }

    [HttpGet]
    public async Task<IActionResult> Get(ODataQueryOptions<DTO> options)
    {
        var container = _client.GetContainer("DatabaseID", "ContainerID");
        var query = container.GetItemLinqQueryable<Entity>();
        return Ok(await query.GetQueryAsync(_mapper, options));
    }
}

And thats it, you're done! <br> The query and results are correctly mapped to and from your DTO and Entity type(s). This keeps your entities from being publically exposed via the API.

Functions

There are four main functions you can use depending on your usecase.

  • Get - Executes the query aginst the database synchronously
  • GetAsync - Executes the query against the database asynchronously
  • GetQuery - Synchronously builds the IQueryable but does not execute it against the database
  • GetQueryAsync - Asynchronously builds the IQueryable but does not execute it against the database

<b>If you plan on using the synchronous versions of the functions above make sure you've enabled synchronous execution:</b>

var container = _client.GetContainer("DatabaseID", "ContainerID");
var query = container.GetItemLinqQueryable<Entity>(allowSynchronousQueryExecution: true);

Function Signatures

public static ICollection<TModel> Get<TModel, TData>(
    this IQueryable<TData> query, 
    IMapper mapper, 
    ODataQueryOptions<TModel> options, 
    QuerySettings? querySettings = null);

public static IQueryable<TModel> GetQuery<TModel, TData>(
    this IQueryable<TData> query,
    IMapper mapper,
    ODataQueryOptions<TModel> options,
    QuerySettings? querySettings = null);

public static async Task<ICollection<TModel>> GetAsync<TModel, TData>(
    this IQueryable<TData> query, 
    IMapper mapper, 
    ODataQueryOptions<TModel> options, 
    QuerySettings? querySettings = null,
    CancellationToken cancellationToken = default);

public static async Task<IQueryable<TModel>> GetQueryAsync<TModel, TData>(
    this IQueryable<TData> query, 
    IMapper mapper, 
    ODataQueryOptions<TModel> options, 
    QuerySettings? querySettings = null,
    CancellationToken cancellationToken = default);
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.2.0 1,599 2/15/2023
0.1.1 234 2/13/2023
0.1.0 240 2/10/2023