Cohesive.Adapters.Postgres 0.1.0-alpha.146

This is a prerelease version of Cohesive.Adapters.Postgres.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Cohesive.Adapters.Postgres --version 0.1.0-alpha.146
                    
NuGet\Install-Package Cohesive.Adapters.Postgres -Version 0.1.0-alpha.146
                    
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="Cohesive.Adapters.Postgres" Version="0.1.0-alpha.146" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cohesive.Adapters.Postgres" Version="0.1.0-alpha.146" />
                    
Directory.Packages.props
<PackageReference Include="Cohesive.Adapters.Postgres" />
                    
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 Cohesive.Adapters.Postgres --version 0.1.0-alpha.146
                    
#r "nuget: Cohesive.Adapters.Postgres, 0.1.0-alpha.146"
                    
#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 Cohesive.Adapters.Postgres@0.1.0-alpha.146
                    
#: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=Cohesive.Adapters.Postgres&version=0.1.0-alpha.146&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Cohesive.Adapters.Postgres&version=0.1.0-alpha.146&prerelease
                    
Install as a Cake Tool

Cohesive.Adapters.Postgres

Instance composition

PostgresPersistenceBindings.Define(databaseId, configure) accepts inline or extracted configuration through the existing native builder and freezes the result. bindings.Entity(entity, mapping => mapping.Table(...).Identity(...).Partition(...)) removes the need for a parallel mapping-property catalog. Mapping(entity) exposes a declared immutable mapping and rejects a foreign entity authority. Runtime Bind still attaches a caller-owned Npgsql data source and shares the frozen mappings.

Cohesive.Adapters.Postgres realizes Cohesive Relations, Storage, materialization, Process durability, and logical replication semantics on PostgreSQL through explicit bindings and Npgsql-backed runtime ports.

Install

dotnet add package Cohesive.Adapters.Postgres

Start with safe SQL construction

The standalone builder quotes identifiers and parameterizes values. It is useful on its own and is also shared by the canonical compiler:

var template = new SqlSelectBuilder(
        new SqlQualifiedTable("transport", "loads"),
        "l")
    .Select(SqlExpression.Column("l", "id"), "id")
    .Where(SqlExpression.Binary(
        SqlBinaryOperator.Equal,
        SqlExpression.Column("l", "status"),
        SqlExpression.RuntimeParameter("status")))
    .OrderBy(SqlExpression.Column("l", "id"))
    .Limit(100)
    .BuildTemplate(PostgresSqlDialect.Instance);

var statement = template.Bind(PostgresSqlDialect.Instance, new Dictionary<string, object?>
{
    ["status"] = "Open"
});

For canonical Relations, author the relation first, compile its exact demand, place acquired inputs in a PostgreSQL execution domain, then bind semantic fields to tables and columns. Semantic-path conventions handle ordinary names; explicit mappings and evidence are required where the physical model differs.

Implemented interpretations

  • Parameterized native SQL compilation for the declared PostgreSQL target profile.
  • Npgsql source acquisition for bounded enumeration, identity batches, and predicate batches.
  • Exact Relation storage-binding authoring and capability evidence.
  • Entity repositories and aggregate storage realization.
  • Durable Process aggregate persistence and distribution ledgers.
  • Materialization state, generation routing, rebuild, and reconciliation sources.
  • Logical replication with exact slot, baseline, checkpoint, and settlement evidence.

Current boundary

The adapter preserves only semantics proven by its target profiles and binding evidence. Text equality and ordering, temporal intervals, isolation, pagination, and change-feed assumptions are distinct claims. Missing evidence produces structured diagnostics before native compilation or execution.

The standalone SQL builder expresses PostgreSQL behavior; using it does not manufacture a canonical Relation plan or prove equivalence with one.

Continue

POCO-first entity mappings

Use the canonical entity definition as the field authority and attach physical names with selectors:

var mapping = PostgresEntityRepositoryMapping.For<Order>(entity)
    .Table("public", "cohesive_orders")
    .Identity(order => order.Id, "order_id")
    .Partition(order => order.Partition, "partition_key")
    .Build();

Column maps additional fields. Selectors follow the shared FieldPath conventions, including JsonPropertyName; nested paths and computed expressions are rejected. Scalar encodings come from the supplied canonical definition, not a second CLR type catalog. Identity and partition must be required non-null text. Build reuses repository validation for complete coverage, required fields, scalar compatibility and key semantics; the mapping constructor rejects duplicate fields/columns. An immutable mapping snapshot is independent of subsequent builder edits. The builder is invocation-local and not thread-safe. Custom version columns and batch bounds are optional Build arguments. The existing constructor remains available; neither API owns schema creation or migration.

Reuse repository mappings for native queries

PostgresEntityRepositoryMapping.For(domainEntity) accepts a typed domain handle. Once a canonical query is compiled and its inputs placed, .Table(placedInput, repositoryMapping) projects the existing physical table and demanded columns into its native binding. No second column catalog is required. Text columns use explicit C-collation equality; this projection does not assert ordinal ordering, global identity uniqueness, foreign keys or partition isolation. Those remain explicit query/schema obligations. The fulfillment example demonstrates the full pipeline.

PostgresQueryRowsReader implements the shared IRelationQueryRowsReader complete-result contract and executes one compiled, unpaged native QueryRows branch against an explicitly attested PostgresNpgsqlRuntimeBinding. Prepare it once; concurrent calls own separate commands, parameter values and result budgets. The caller retains ownership of the data source. Presence markers reconstruct outer-join absence independently of SQL null. Positive row and decoded-scalar-byte bounds are mandatory; one overflow row detects truncation and fails the call rather than returning partial data. Cancellation/provider failures propagate, no retries occur, and ambient transactions are rejected. Native command timeout still bounds command duration; the result budget is not a database-work budget.

This reader deliberately does not expose a complete canonical evaluation outcome, supplied-root execution, relation invariants, paging or temporal semantics. Such artifacts/values are rejected; use the existing source-acquisition path with explicit policies where those contracts are required.

Register a typed query at host composition

PostgresPersistenceBindings(databaseId).Entity(domainEntity, mapping).Bind(runtime).Query(query, maximumRows, maximumBytes) places all demanded entity sources/traversals in the explicitly selected database, projects the registered repository mappings and invokes the existing static/placement/feasibility/native compilers. It opens no connection. Missing mappings and invalid plans fail at registration; static/native compilation failures retain their result objects in PostgresQueryPreparationException, while placement/binding failures retain the existing artifact-authoring diagnostics. This convenience covers entity-backed inputs on one database; use the lower-level APIs for custom placement, acquisition or physical bindings.

Keep the returned PostgresQueryReader<TInput,TResult> for the host lifetime. HTTP code consumes its IRelationQueryReader<TInput,TResult> contract and exact Definition, while native composition can inspect its PostgreSQL artifact. ReadAsync performs no compilation; it binds the input, reads bounded native rows and invokes the query's local typed result projection. Its Artifact remains inspectable. The builder is registration-local and mutable, while readers retain immutable prepared artifacts and require concurrency-safe projection callbacks. Native data-source ownership remains with the caller. PostgreSQL configuration stays outside the semantic query declaration.

The persistence registration is shared: .Repository(entity) uses the same attached entity definition, mapping and runtime as .Query(...). Query dependencies are resolved from the compiled input contract; unconsumed attachments do not create SQL sources. Missing/duplicate attachments fail before IO. Configure the mutable registration on one thread during host setup, then retain its prepared readers/repositories; there is no global result cache or inferred tenant scope. The earlier PostgresQueryRegistration.Register name is replaced by PostgresPersistenceRegistration.Query in this unreleased surface.

Prepared native and composed queries

PostgresPersistenceRegistration attaches canonical entities to native repository mappings once. Query prepares a native typed reader. QueryComposed(query, projection, remote, policy) prepares a closed native prefix and the remaining query over one remote PostgreSQL registration, reusing those same attachments. The policy declares acquisition bounds and a partition scope once. Remaining source and traversal mappings are selected from the remote registration; missing mappings or mismatched partition selectors fail during preparation. The native prefix must explicitly enforce the same authorized scope. This initial recipe uses sequential bounded acquisition, fails on overflow, and makes no distributed-snapshot claim. It opens no connection during preparation; caller-owned data sources must outlive the readers.

Storage-binding schema v4 includes SourceScope in its fingerprint and convention-derived identity. Null means the full placement, while ForSource means exactly the declared source. Reader and compiler admission check that declared scope; table coverage cannot silently narrow it. Persisted v3 bindings are rejected and must be regenerated from their declarations. Semantic/native preparation errors retain their compiler results; cut/physical errors retain RelationQueryPreparationException evidence.

Repository(entity) preserves the DomainEntity<T> type as IEntityRepository<T>, using the existing TypedEntityRepository<T> over the native repository. Canonical writes, batching and concurrency fences continue to delegate unchanged. At registration, the default typed-write identity selector is compiled from mapping.IdentityField using the same FieldPath.Capture member naming rules as mapping authoring (including JsonPropertyName). An absent or ambiguous readable property fails before request execution; there is no Id/Key fallback for a declared field, and warm identity extraction performs no reflection (see the scoped allocation test in the Storage README). Explicit selectEntityId remains an escape for custom CLR mappings. Semantic versions retain existing Version/zero conventions, or an explicit selectVersion. The registration remains PostgreSQL-specific; application consumers depend on typed repository/read interfaces.

This shared CLR identity conversion does not broaden native key encodings: the PostgreSQL repository still requires required, non-null TEXT identity and partition mappings. Inferred UUID/native non-text keys remain rejected by mapping validation, as before this change.

For composed execution, construct PostgresRelationQueryComposedPolicy(physicalPlanningPolicy, ...). It retains that required planning policy and derives SourcePolicy.MaximumBatchKeys from MaximumBatchSize; there is no second batch-size input. QueryComposed accepts only this composed policy type. Standalone readers retain PostgresRelationQuerySourcePolicy and its integer batch bound. The composed policy rejects a null partition scope at construction. Missing remote mappings or mismatched partition scopes raise RelationQueryPreparationException with a postgres.composed.* code and semantic compilation evidence. Identity caching and allocation boundaries are documented once in the Storage README.

Atomic entity process receipts

Opt in with PostgresTransitionReceiptOptions(schema, table, partitionKey) on the repository or persistence.Repository(entity, transitionReceipts: storage). Execute options.SchemaSql explicitly in your schema lifecycle, then obtain storage = await options.BindAsync(dataSource). The repository requires this validated handle and rejects a handle from another data-source instance; unchecked options cannot be passed. The check rejects incompatible columns or missing immediate primary/creation uniqueness fences without migrating the table. PostgreSQL 14 and 17 are exercised, including invalid-schema rejection; the optional PostgreSQL 15+ null-equality metadata is read through a version-tolerant catalog projection. Rebind after external schema changes: startup validation does not lock out later DDL. Column order is immaterial: the shared SQL builder emits an explicit insert column list. Without options the repository advertises no atomic transition-receipt support.

State and canonical receipt commit in one native transaction. Advisory transaction locks serialize the same occurrence/subject; the conditional SQL write still fences external writers. Exact replay returns original evidence even after later entity updates. Receipt size, format, hash, canonical encoding and identity are checked on read. Oversized receipt writes roll back entity state. No retry is hidden; an ambiguous COMMIT requires exact receipt resolution. Options choose a trusted physical partition, not an authorization grant. Application schema, retention and recovery remain explicit. Receipts do not imply an outbox or event-authoritative state.

Create(..., EntityCreationPolicy.IfAbsent) uses INSERT ... ON CONFLICT DO NOTHING on the configured identity/partition key, independently of receipt configuration. Upsert retains its existing replacement behavior. Typed wrappers forward both the capability and the operation.

The shared Storage receipt protocol resolves replay only after a conditional native conflict; PostgreSQL supplies the locked native transaction and conditional SQL writes. Fixed receipt partition evidence is inherited by process bindings. Receipt validation intentionally retains canonical reserialization and hashing: the warm cost is measured in src/Cohesive.Relations.Benchmarks/RESULTS.md, separately from SQL and network latency.

PostgresQueryRowsReader executes a prepared unpaged row artifact through the shared Npgsql executor. Parameters and the overflow limit have explicit provider types; results use sequential decoding and one-pass immutable row assembly. Its byte budget counts all retrieved scalar values, including presence columns and suppressed fields. Raw rows are bounded and invocation-owned. See qualification.

Offline infrastructure preparation

PostgresPersistenceBindings(databaseId).Entity(entity, mapping) owns offline validated mappings. Prepare(query.CompilationRequest) runs the existing semantic/placement/native compilers without a connection; Bind(runtime) shares the frozen mappings with a PostgresPersistenceRegistration. Offline bindings are created only through Define; the mutable public constructor has been removed. Mapping builders are host-composition objects and must not be mutated concurrently. Runtime parameters, connections and results remain invocation-scoped; no query-result cache or global registry is added.

Optional Cohesive.Adapters.Postgres.Infra projects prepared artifacts into exact infrastructure evidence without adding an Infra dependency to the base adapter.

Product Compatible and additional computed target framework versions.
.NET 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 (2)

Showing the top 2 NuGet packages that depend on Cohesive.Adapters.Postgres:

Package Downloads
Cohesive.Adapters.Postgres.Infra

Infrastructure evidence derived from prepared PostgreSQL query bindings.

Cohesive.Adapters.Marten

Cohesive semantic system definition and orchestration building blocks.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-alpha.156 40 10/22/2026
0.1.0-alpha.155 51 10/20/2026
0.1.0-alpha.154 47 10/20/2026
0.1.0-alpha.153 47 10/20/2026
0.1.0-alpha.152 58 10/19/2026
0.1.0-alpha.151 59 10/19/2026
0.1.0-alpha.150 55 10/19/2026
0.1.0-alpha.149 59 10/18/2026
0.1.0-alpha.148 59 10/18/2026
0.1.0-alpha.147 64 10/18/2026
0.1.0-alpha.146 64 10/18/2026
0.1.0-alpha.145 67 10/17/2026
0.1.0-alpha.144 61 10/17/2026
0.1.0-alpha.143 64 10/16/2026
0.1.0-alpha.142 62 10/16/2026
0.1.0-alpha.141 63 10/16/2026
0.1.0-alpha.140 55 10/15/2026
0.1.0-alpha.139 53 10/13/2026
0.1.0-alpha.138 45 10/13/2026
0.1.0-alpha.137 49 10/12/2026
Loading failed