Cirreum.Persistence.NoSql 1.0.11

dotnet add package Cirreum.Persistence.NoSql --version 1.0.11
                    
NuGet\Install-Package Cirreum.Persistence.NoSql -Version 1.0.11
                    
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="Cirreum.Persistence.NoSql" Version="1.0.11" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cirreum.Persistence.NoSql" Version="1.0.11" />
                    
Directory.Packages.props
<PackageReference Include="Cirreum.Persistence.NoSql" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cirreum.Persistence.NoSql --version 1.0.11
                    
#r "nuget: Cirreum.Persistence.NoSql, 1.0.11"
                    
#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.
#:package Cirreum.Persistence.NoSql@1.0.11
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cirreum.Persistence.NoSql&version=1.0.11
                    
Install as a Cake Addin
#tool nuget:?package=Cirreum.Persistence.NoSql&version=1.0.11
                    
Install as a Cake Tool

Cirreum Persistence NoSql Library

NuGet Version NuGet Downloads GitHub Release

A comprehensive .NET persistence NoSql based abstraction library that provides type-safe, feature-rich repository patterns for data access operations without external dependencies. This library offers a clean separation between your domain logic and persistence concerns through well-defined interfaces and base implementations

Overview

The Cirreum Persistence Library contains abstractions and contracts for implementing persistence repositories with support for:

  • Entity Management: Base entity types with built-in auditing, soft deletes, ETags, and TTL
  • Repository Patterns: Read-only, write-only, batch, and full repository interfaces
  • Advanced Querying: Expression-based queries, pagination, and async enumeration
  • Partial Updates: Patch operations with expression and path-based targeting
  • Soft Deletes: Built-in soft delete and restore capabilities
  • Auditing: Automatic tracking of creation, modification, and deletion metadata
  • Time Zones: IANA timezone support for audit fields
  • Concurrency Control: ETag-based optimistic concurrency
  • Time-to-Live: Automatic entity expiration support

Core Interfaces

Entity Interfaces

  • IEntity: Base entity contract with Id, EntityType, and PartitionKey
  • IAuditableEntity: Adds creation and modification tracking with timezone support
  • IDeletableEntity: Enables soft delete capabilities
  • IRestorableEntity: Extends soft delete with restoration tracking
  • IEtagEntity: Provides optimistic concurrency control
  • ITimeToLiveEntity: Automatic entity expiration

Repository Interfaces

  • IReadOnlyRepository<TEntity>: Query, retrieval, counting, and pagination operations
  • IWriteOnlyRepository<TEntity>: Create, update, delete, and restore operations
  • IBatchRepository<TEntity>: Batch operations for multiple entities
  • IRepository<TEntity>: Combined interface extending all repository types

Entity Base Classes

BaseEntity

public abstract record BaseEntity : IEntity
{
	public string Id { get; set; } = Guid.NewGuid().ToString();
	public string EntityType { get; init; }
	string IEntity.PartitionKey => GetPartitionKeyValue();
}
public abstract record Entity : BaseEntity, IEtagEntity, ITimeToLiveEntity, IAuditableEntity
{
	public string Etag { get; init; }
	public TimeSpan? TimeToLive { get; set; }
	public DateTimeOffset? CreatedOn { get; set; }
	public string? CreatedBy { get; set; }
	public string? CreatedInTimeZone { get; set; }
	public DateTimeOffset ModifiedOn { get; }
	public string ModifiedBy { get; set; }
	public string? ModifiedInTimeZone { get; set; }
}

SoftDeleteEntity

public abstract record SoftDeleteEntity : Entity, IRestorableEntity
{
	public string DeletedBy { get; set; }
	public DateTimeOffset? DeletedOn { get; set; }
	public string? DeletedInTimeZone { get; set; }
	public bool IsDeleted { get; set; }
	public int RestoreCount { get; set; }
}

Key Features

1. Comprehensive Querying

// Expression-based queries
var results = await repository.QueryAsync(x => x.Name.Contains("test"));

// Cursor-based pagination (recommended for large datasets)
CursorResult<MyEntity> cursorPage = await repository.PageCursorAsync(
	predicate: x => x.IsActive,
	pageSize: 20,
	cursor: null);

// Offset-based pagination (for traditional paged UIs)
PagedResult<MyEntity> pagedResult = await repository.PageAsync(
	predicate: null,
	pageNumber: 1,
	pageSize: 10);

// Slice for simple "load more" scenarios
SliceResult<MyEntity> slice = await repository.SliceAsync(
	predicate: x => x.IsActive,
	count: 10);

// Async enumeration for large datasets
await foreach (var entity in repository.SequenceQueryAsync(x => x.Category == "Important"))
{
	// Process entity
}

2. Partial Updates with Patch Operations

// Expression-based patch operations
await repository.UpdatePartialAsync(entityId, builder => builder
	.Set(x => x.Name, "New Name")
	.Increment(x => x.ViewCount, 1)
	.Add(x => x.Tags, "new-tag")
	.Remove(x => x.ObsoleteField));

// Path-based operations for interface properties
await repository.UpdatePartialAsync(entityId, builder => builder
	.SetByPath("status", "Active")
	.IncrementByPath("score", 10));

3. Soft Delete and Restore

// Soft delete
await repository.DeleteAsync(entityId, softDelete: true);

// Restore with tracking
var (wasRestored, entity) = await repository.RestoreAsync(entityId);

// Batch restore
var results = await repository.RestoreAsBatchAsync(entities);

4. Batch Operations

// All entities must share the same partition
await repository.CreateAsBatchAsync(entities);
await repository.UpdateAsBatchAsync(entities);
await repository.DeleteAsBatchAsync(entities, softDelete: true);

5. Advanced Query Options

// Include soft-deleted entities
var allEntities = await repository.GetAllAsync(includeDeleted: true);

// Check existence
var exists = await repository.ExistsAsync(x => x.Email == "user@example.com");

// Count with filters
var count = await repository.CountAsync(x => x.IsActive && !x.IsDeleted);

Attributes for Persistence Configuration

Container Specification

[Container("my-container")]
public record MyEntity : Entity;

Partition Key Configuration

[PartitionKeyPath("/tenantId")]
public record TenantEntity : Entity {

	public string TenantId { get; set; }

	protected override string GetPartitionKeyValue() => this.TenantId;

}

Unique Key Constraints

public record UserEntity : Entity {

	[UniqueKey("email-key", "/email")]
	public string Email { get; set; }

	[UniqueKey("username-key", "/username")]
	public string Username { get; set; }

}

Indexing Policy Configuration

Declaratively define indexing policies directly on entity classes. When the persistence provider supports auto-creation, these attributes drive the container's indexing policy.

Indexing Mode and Behavior
[IndexingPolicy(IndexingMode.Consistent, Automatic = true)]
public record MyEntity : Entity;
Included and Excluded Paths
[IndexingPolicy(IndexingMode.Consistent)]
[ExcludedPath("/content/*")]
[ExcludedPath("/*")]
public record MyEntity : Entity {

	[IncludedPath]
	public string Status { get; set; }

	[IncludedPath("/customPath/?")]
	public string CustomField { get; set; }

}

When no explicit path is provided, [IncludedPath] auto-derives the path from the [JsonPropertyName] attribute or camelCase property name as /{name}/?.

Composite Indexes
[IndexingPolicy(IndexingMode.Consistent)]
[ExcludedPath("/*")]
public record TaskItem : Entity {

	[IncludedPath]
	[CompositeIndex("type-client-date", CompositePathSortOrder.Ascending, position: 0)]
	public string Type { get; set; }

	[IncludedPath]
	[CompositeIndex("type-client-date", CompositePathSortOrder.Ascending, position: 1)]
	public string ClientId { get; set; }

	[IncludedPath]
	[CompositeIndex("type-client-date", CompositePathSortOrder.Descending, position: 2)]
	public DateTimeOffset CreatedAt { get; set; }

}

Properties are grouped into composite indexes by GroupName and ordered by Position. A property can participate in multiple composite index groups by applying the attribute multiple times.

Spatial Indexes
[IndexingPolicy(IndexingMode.Consistent)]
public record LocationEntity : Entity {

	[SpatialIndex(SpatialType.Point)]
	public Location Coordinates { get; set; }

}
Available Enums
  • IndexingMode: Consistent, Lazy, None
  • CompositePathSortOrder: Ascending, Descending
  • SpatialType: Point, LineString, Polygon, MultiPolygon

Pagination Support

The library provides three pagination approaches via types from Cirreum.Result:

  • Stable results when data is being inserted or deleted
  • Consistent performance regardless of how deep into the result set
  • Ideal for large datasets, real-time data, and infinite scroll interfaces
  • Returns CursorResult<T> with NextCursor, HasNextPage, and optional TotalCount

Offset-Based Paging

  • Traditional page number-based paging with arbitrary page jumps
  • Includes total counts for displaying "Page X of Y"
  • Performance degrades on deep pages; results can shift between requests
  • Returns PagedResult<T> with PageNumber, PageSize, TotalCount, and TotalPages

Slice

  • Simple "load more" pattern without full pagination metadata
  • Fetches N+1 items to check if more exist
  • Ideal for "Show More" buttons or batch processing
  • Returns SliceResult<T> with Items and HasMore

Timezone Support

All audit fields support IANA timezone identifiers:

entity.CreatedInTimeZone = "America/Phoenix";
entity.ModifiedInTimeZone = "Europe/London";
entity.DeletedInTimeZone = "Asia/Tokyo";

Thread Safety and Concurrency

  • ETag-based optimistic concurrency control
  • Concurrency tokens for partial updates
  • Thread-safe read operations
  • Batch operations require entities in same partition

Best Practices

  1. Inherit from appropriate base classes: Use Entity for full features, BaseEntity for minimal requirements
  2. Implement partition strategy: Override GetPartitionKeyValue() for custom partitioning
  3. Use cursor paging: Prefer PageCursorAsync over PageAsync for large datasets and infinite scroll
  4. Use slice for simple scenarios: Use SliceAsync when you just need "load more" without page numbers
  5. Batch same-partition entities: Ensure batch operations only include entities from the same partition
  6. Handle soft deletes: Use includeDeleted parameter appropriately in queries
  7. Leverage partial updates: Use patch operations for efficient field-level updates

Dependencies

This library has minimal dependencies:

  • Cirreum.Result for pagination result types (CursorResult<T>, PagedResult<T>, SliceResult<T>)
  • System.Text.Json for serialization attributes
  • System.Linq.Expressions for query building

Integration

This abstraction layer is designed to be implemented by concrete persistence providers such as:

  • Azure Cosmos DB
  • MongoDB
  • Entity Framework Core
  • Any document or relational database

The clean separation ensures your domain logic remains persistence-agnostic while providing rich functionality through the unified interface.

Contributing

This package is part of the Cirreum ecosystem. Follow the established patterns when contributing new features or provider implementations.

Cirreum Foundation Framework
Layered simplicity for modern .NET

Product 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 is compatible.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Cirreum.Persistence.NoSql:

Package Downloads
Cirreum.Persistence.Azure

Persistence Library using Azure Cosmos DB for NoSQL.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.11 46 6/5/2026
1.0.10 206 5/1/2026
1.0.9 392 3/25/2026
1.0.8 145 3/21/2026
1.0.7 129 3/21/2026
1.0.6 273 3/13/2026
1.0.5 143 3/9/2026
1.0.4 277 1/21/2026
1.0.3 218 1/5/2026
1.0.2 155 1/4/2026