Commit Database

The Commit Database provides transactional persistence with history tracking. CommitDatabase is the persistence layer; two stateless namespaces operate over it, each taking a CommitDatabase as its first argument:

  • CommitStateBuilder — reconstruct a CommitState from a chosen commit: state(db, id), initial_state(db).

  • CommitDatabaseHelper — reduce heads and navigate: reduce_heads(db, anchor), forward / fast_forward.

(CommitDatabase itself answers topology queries — head_commit_ids, last_commit_id, is_ancestor — and holds no “current” state.) A CommitStore wraps the persistence layer and both namespaces behind a stateful facade (undo/redo, the dispatch surface) for interactive apps. For why a reconstructed state is a blind replay of the linearized trace, see Commit Database.

When to use: Use these classes to persist DSM documents with history — every write is a commit, and earlier states stay reconstructible. For flat CRUD without versioning, use Database instead. Within this page, reach for CommitStore when an interactive application needs undo/redo and a dispatch surface, and for the two stateless namespaces when a script or service drives the database directly.

Quick Start

>>> from dsviper import *
>>> MODEL = """
... namespace MyApp {8f14e45f-ceea-467a-9575-1c14b48f0b7e} {
...     concept User;
...     struct Profile { string city; uint16 age; };
...     attachment<User, Profile> profile;
... };
... """
>>> builder = DSMBuilder()
>>> builder.append("model.dsm", MODEL)
>>> report, dsm_defs, defs = builder.parse()
>>> report.has_error()
False
>>> defs.inject(globals())             # MY_APP_T_USER, MY_APP_A_USER_PROFILE, …
>>> key = ValueKey.create(MY_APP_T_USER, "0d2f0e1a-1111-4222-8333-444455556666")
>>> document = Value.create(MY_APP_S_PROFILE, {"city": "Paris", "age": 30})

A CommitDatabase keeps every commit. Mutations are applied to a CommitMutableState built over the state you start from — a fresh database has no commit yet, so start from the initial state:

>>> db = CommitDatabase.create_in_memory()
>>> db.extend_definitions(defs).count()
3
>>> last = db.last_commit_id()
>>> state = CommitStateBuilder.state(db, last) if last else CommitStateBuilder.initial_state(db)
>>> mutable = CommitMutableState(state)
>>> mutable.attachment_mutating().set(MY_APP_A_USER_PROFILE, key, document)
>>> commit_id = db.commit_mutations("Add user", mutable)

Reading goes through the state at a commit:

>>> state = CommitStateBuilder.state(db, commit_id)
>>> Value.dumps(state.attachment_getting().get(MY_APP_A_USER_PROFILE, key).unwrap())
{'city': 'Paris', 'age': 30}

A second commit records only what changed:

>>> mutable = CommitMutableState(CommitStateBuilder.state(db, commit_id))
>>> mutable.attachment_mutating().set(
...     MY_APP_A_USER_PROFILE, key, Value.create(MY_APP_S_PROFILE, {"city": "Lyon", "age": 31}))
>>> second = db.commit_mutations("Move to Lyon", mutable)
>>> Value.dumps(CommitStateBuilder.state(db, second)
...             .attachment_getting().get(MY_APP_A_USER_PROFILE, key).unwrap())
{'city': 'Lyon', 'age': 31}

See also

For detailed examples and the Dual-Layer Contract, see Commit Database and The Dual-Layer Contract.

Path-Based Mutations

Use Path with update() to modify specific fields without replacing the entire document. This enables disjoint concurrent writes — changes to different fields converge automatically.

from dsviper import CommitDatabase, CommitStateBuilder, CommitMutableState, Path

db = CommitDatabase.open("model.cdb")
db.definitions().inject()

# Build a path to a nested field: document.address.city
path_city = Path.from_field("address").field("city").const()

# Create mutable state
last = db.last_commit_id()
state = CommitStateBuilder.state(db, last) if last else CommitStateBuilder.initial_state(db)
mutable = CommitMutableState(state)
mutating = mutable.attachment_mutating()

# Update only the city field (not the whole document)
mutating.update(MY_APP_A_USER_PROFILE, user_key, path_city, "Paris")

# Commit
db.commit_mutations("Update city", mutable)

With set(), concurrent edits to the same document silently lose one (last-writer-wins). With update(), edits to different fields converge without loss.

Supervised Reconciliation

Reconciling a merge — CommitMergeAnalyzer and friends — is an additive supervisor over this API, documented on its own page: Merge Reconciliation.

Database ↔ CommitDatabase Transfer

Moving content between the flat Database and the versioned CommitDatabase — convert, materialize, faithful copy, and flatten — is a set of converters documented on its own page: Database Transfer.

Choosing the Right Class

Use Case

Class

Example

Open commit database

CommitDatabase

db = CommitDatabase.open(path)

Read state at specific commit

CommitStateBuilder

state = CommitStateBuilder.state(db, commit_id)

Reduce divergent heads

CommitDatabaseHelper

CommitDatabaseHelper.reduce_heads(db)

Prepare mutations

CommitMutableState

mutable = CommitMutableState(state)

Read documents (get, keys, has)

AttachmentGetting

getting = state.attachment_getting()

Write documents (set, update)

AttachmentMutating

mutating = mutable.attachment_mutating()

Inspect commit metadata

CommitHeader

header = db.commit_header(id)

Core Classes

dsviper.Commit

One commit as it is stored.

dsviper.CommitDatabase

A Commit database keeps the history of mutations in a DAG of commits.

dsviper.CommitDatabaseSQLite

A low-level class used to represent the database based on SQLite3 through the CommitDatabasing interface.

dsviper.CommitDatabaseRemote

A low-level class used to represent a remote Commit database through the CommitDatabasing interface.

dsviper.CommitDatabaseServer

A CommitDatabaseServer provides network access to a CommitDatabase.

dsviper.CommitDatabasing

Abstracts the persistence layer behind a Commit database.

State Access

dsviper.CommitState

The data reconstructed at one commit, by replaying the mutations down to it.

dsviper.CommitMutableState

Registers the mutations of a value executed through the AttachmentMutating interface.

dsviper.CommitStateBuilder

Reconstructs a CommitState from a chosen commit.

History & DAG

dsviper.CommitNode

One commit in the DAG, linked to the commits that follow it.

dsviper.CommitNodeGrid

One commit's place in the DAG once it is laid out on a grid.

dsviper.CommitNodeGridBuilder

Builds the grid layout of the commit DAG.

dsviper.CommitHeader

What identifies a commit, without its content.

dsviper.CommitData

One commit's encoded opcodes, with the header that places it.

dsviper.CommitEvalAction

A class used by the evaluator to reconstruct a value by executing mutation opcodes.

dsviper.CommitDatabaseHelper

Navigates the commit DAG.

Synchronization

dsviper.CommitStore

A high-level application class used to implement the store, dispatch, undo/redo and notification concepts inspired by the redux approach.

dsviper.CommitStoreNotifying

An interface used to represent the notification emitted by a store.

dsviper.CommitSynchronizer

Synchronizes two concrete databases through the CommitDatabasing interface (low-level driver interface).

dsviper.CommitSynchronizerInfo

What a synchronization found.

dsviper.CommitSynchronizerInfoTransmit

What one synchronization actually transferred.

dsviper.CommitSyncData

The commits one database hands another when they synchronize.

Tracing

dsviper.CommitStateTracing

Asks a state for the trace of one document.

dsviper.CommitStateTrace

The replay of one document.

dsviper.CommitStateTraceProgram

One commit's contribution to a document.