PrimebrickPrimebrick
  • Primebrick.dev
  • GitHub
  • Documentation
  • Services
  • Libraries
  • API Catalog
Resources
  • Landing Page
  • API Catalog
  • GitHub
PrimebrickPrimebrick

© 2026 Primebrick. MIT License.

github
DAL Library
    AI Agent Rules and SkillsAudit and Soft-Delete SubsystemsAudit Port and Delta TrackingAuditable Joins and Display NamesBulk OperationsCI/CD and Release ProcessConnection Pool and Session ConfigurationCore ArchitectureDal GatewayEntity Metadata SystemError HandlingGetting StartedGitFlow and Branching RulesGlossaryKey Design DecisionsOverviewQuery DSL and SQL BuilderRead OperationsRepository: CRUD and FindersStreaming Large Result SetsTest Infrastructure and EntitiesTest Suite CoverageTestingTimeout Management and withClientType Coercion: JS ↔ PostgreSQLWrite OperationsREADME
SDK Library
powered by Zudoku
DAL Library

Write Operations

Write Operations

Relevant source files

The following files were used as context for generating this wiki page:

  • docs/ai/dal-usage-guide.md
  • src/repository/repository.ts
  • test/repository-crud.test.ts

The Repository class provides a set of methods for single-row modifications. These operations are designed with a "safety-first" philosophy, featuring automatic audit stamping, version incrementing, and mandatory RETURNING * hydration to ensure the JavaScript entity remains synchronized with the database state.

Overview of Write Lifecycle

Every write operation in the DAL follows a structured lifecycle to maintain data integrity and auditability:

  1. Metadata Resolution: The system inspects the @Entity for primary keys and auditable fields src/repository/repository.ts:159-161.
  2. Actor Stamping: If the entity is auditable, the actor provided in AuditableWriteOptions is applied to created_by or updated_by src/repository/repository.ts:316-324.
  3. SQL Generation: Parameterized SQL is built, targeting either the primary key or a specific column defined by matchBy src/repository/repository.ts:100-116.
  4. Execution & Hydration: The query is executed with RETURNING *, and the resulting row is hydrated back into the JS entity type src/repository/repository.ts:281-285.
  5. Audit Dispatch: If an AuditPort is configured, a delta is calculated and the audit event is fired src/repository/repository.ts:335-343.

Data Flow: Single-Row Write

The following diagram illustrates how a write request flows from the Repository through metadata resolution to SQL execution.

Write Operation Flow

Code
graph TD subgraph "Repository API" A["repo.add() / repo.update()"] end subgraph "Metadata Engine" B["getEntityPersistenceMeta()"] C["resolveMatchColumn()"] end subgraph "Audit Subsystem" D["AuditableWriteOptions (actor)"] E["calculateDelta()"] F["AuditPort.fire()"] end subgraph "Database" G["SQL Execution (RETURNING *)"] end A --> B B --> C A --> D D --> G G --> E E --> F

Sources: src/repository/repository.ts:148-150, src/repository/repository.ts:95-116, src/repository/repository.ts:335-343, src/meta/entity-meta.ts:60-65

Core Write Methods

add (Insert)

Inserts a new record. It automatically handles uuid generation (if defined), version initialization to 1, and audit stamping for created_by and updated_by.

  • Logic: Validates that at least one column is being inserted src/repository/repository.ts:273-275.
  • Audit: Stamps created_at, updated_at, created_by, and updated_by if the entity supports them src/repository/repository.ts:316-324.

update (Update by Key)

Updates a record by matching a specific column (defaulting to the @Key).

  • Match Logic: Uses matchBy from MatchByOptions to determine the WHERE clause. The match value is extracted from the update object and removed from the SET clause src/repository/repository.ts:122-135.
  • Concurrency: Automatically increments the version column if present src/repository/repository.ts:468-470.
  • Audit: Calculates a delta between the old and new record and dispatches it to the AuditPort src/repository/repository.ts:494-502.

upsert (Insert on Conflict)

Performs an INSERT ... ON CONFLICT operation.

  • Conflict Target: Uses the primary key as the conflict target src/repository/repository.ts:384-386.
  • Behavior: If a conflict occurs, it updates the existing record, increments the version, and updates the updated_by/updated_at fields src/repository/repository.ts:405-410.

delete and restore (Soft-Delete)

The DAL favors soft-deletion over physical deletion for auditable entities.

  • delete: Sets deleted_at to the current timestamp and deleted_by to the provided actor src/repository/repository.ts:553-561.
  • restore: Reverses a soft-delete by setting deleted_at and deleted_by back to null src/repository/repository.ts:603-608.

hardDelete (Physical Delete)

Performs a physical DELETE FROM query. This is irreversible and should be used with caution src/repository/repository.ts:646-654.

Sources: src/repository/repository.ts:264-353, src/repository/repository.ts:370-435, src/repository/repository.ts:446-519, src/repository/repository.ts:532-583, src/repository/repository.ts:594-633, src/repository/repository.ts:646-668

Code Entity Mapping

This diagram maps natural language operations to the specific internal functions and classes responsible for executing them.

Entity Mapping: Natural Language to Code

Code
classDiagram class Repository { +add(entity, data, options) +update(entity, updates, options) +upsert(entity, data, options) +delete(entity, match, options) } class InternalHelpers { +resolveMatchColumn() +extractMatchValue() +calculateDelta() } class MetadataDecorators { +@Key() +@AuditableField() +@DeletableField() } Repository ..> InternalHelpers : uses Repository ..> MetadataDecorators : inspects

Sources: src/repository/repository.ts:148-150, src/repository/repository.ts:95-116, src/repository/repository.ts:53-64, src/meta/entity-decorators.ts:74-84

Write Options and Auditing

AuditableWriteOptions

All write methods accept an options object extending AuditableWriteOptions.

OptionTypeDescription
actorstringRequired. The identity of the user/system performing the write.
auditPortAuditPortOptional override for the global audit port.
matchBystringFor updates/deletes: specify which property to use in the WHERE clause.

Delta Calculation

When an update occurs, the Repository uses calculateDelta to compare the oldEntity (fetched via the RETURNING clause or prior state) with the newEntity src/repository/repository.ts:53-64.

Code
function calculateDelta( oldEntity: Record<string, unknown>, newEntity: Record<string, unknown> ): Record<string, { old: unknown; new: unknown }> { const delta: Record<string, { old: unknown; new: unknown }> = {}; for (const key in newEntity) { if (JSON.stringify(oldEntity[key]) !== JSON.stringify(newEntity[key])) { delta[key] = { old: oldEntity[key], new: newEntity[key] }; } } return delta; }

Sources: src/repository/repository.ts:53-64, src/types/types.ts:106-115

Error Handling in Writes

Write operations may throw the following DAL-specific errors:

  • NotFoundError: Thrown during update or delete if the matchBy criteria finds no rows src/repository/repository.ts:485-487.
  • ValidationError: Thrown if an add operation contains no columns or if a matchBy value is missing src/repository/repository.ts:274-276, src/repository/repository.ts:128-131.
  • UnknownColumnError: Thrown if the matchBy property does not exist on the entity src/repository/repository.ts:103-105.

Sources: src/errors/errors.ts:1-25, src/repository/repository.ts:100-116


Last modified on July 13, 2026
Type Coercion: JS ↔ PostgreSQLREADME
On this page
  • Overview of Write Lifecycle
    • Data Flow: Single-Row Write
  • Core Write Methods
    • add (Insert)
    • update (Update by Key)
    • upsert (Insert on Conflict)
    • delete and restore (Soft-Delete)
    • hardDelete (Physical Delete)
  • Code Entity Mapping
  • Write Options and Auditing
    • AuditableWriteOptions
    • Delta Calculation
  • Error Handling in Writes
TypeScript