Skip to content

Bitemporal Persistence in Arda Common Module

Overview

Bitemporal persistence is a data management approach that tracks both the valid time (when a fact is true in the real world) and the transaction time (when a fact is stored in the database). This allows for powerful historical queries, auditing, and correction of past data without losing information about previous states.

The Arda common module implements bitemporal persistence using Kotlin, Exposed ORM, and a set of extensible abstractions. This document describes the core concepts, schema, and API for bitemporal persistence in this module.

Core Concepts

Time Coordinates

  • TimeCoordinates: Represents a pair of timestamps: effective (valid time) and recorded (transaction time).
  • All bitemporal records are associated with a TimeCoordinates instance, enabling queries as of any point in both timelines.

Bitemporal Table Schema

  • BitemporalTable: Abstracts a table with columns for effective and recorded times, author, entity ID (eId), previous record reference, and a retired flag.
  • TimeCoordinatesColumn: Composite column for storing and retrieving TimeCoordinates.

Bitemporal Entity and Record

  • BitemporalEntity: Serializable data class representing a versioned entity, including payload, metadata, time coordinates, author, and links to previous versions.
  • BitemporalRecord: Abstracts a row in a bitemporal table, mapping to a BitemporalEntity and providing methods to fill payload and metadata.

Guards and Idempotency

  • CreateGuard, UpdateGuard, DeleteGuard: Type aliases for suspend functions that enforce business rules before creating, updating, or deleting records.
  • Idempotency: Enum controlling how updates handle duplicate or conflicting changes (REJECT, CONFIRM, SKIP).

Persistence API

Persistence Interface

Defines the contract for bitemporal persistence, including:

  • Creating, updating, and deleting entities with guard support.
  • Querying as of any time coordinates.
  • Pagination and filtering.

BitemporalEntityClass

Provides Exposed-based implementations for:

  • Reading the latest entity as of a given time.
  • Listing all latest entities for each unique ID (using subquery or window function strategies).
  • Counting entities as of a given time.
  • Ensuring uniqueness and enforcing idempotency/versioning rules.

Example Usage

  1. Define a Table and Payload:
    • Implement BitemporalTable and BitemporalPayload for your domain.
  2. Implement a Record:
    • Extend BitemporalRecord and provide logic to fill payload/metadata.
  3. Use the Persistence API:
    • Use BitemporalEntityClass methods to create, update, delete, and query entities as of any time.

Benefits

  • Full auditability and historical reconstruction.
  • Correction of past data without data loss.
  • Support for complex business rules and versioning strategies.

References


For more details, see the source code in lib/src/main/kotlin/cards/arda/common/lib/persistence/bitemporal/.

Comments