| name | changesets |
| description | Use when capturing, applying, inverting, or concatenating SQLite changesets (the SESSION extension) for audit logs, one-way replication, or undo — the liteorm.org/dialect/sqlite/changeset package. SQLite backend only. |
SQLite changesets
Import liteorm.org/dialect/sqlite/changeset. A changeset is a compact binary ([]byte) diff of the rows a set of statements touched. Capture one, invert it, concatenate it, or apply it to another database with a Go conflict handler. Classic uses: audit logs, one-way replication, undo. SQLite-only — every function takes a liteorm.Session opened by liteorm.org/dialect/sqlite.
Capturing
Capture records every mutation a function makes to the listed tables and returns the serialized changeset. The mutations MUST run against the session Capture hands back (s), not the outer handle — it pins a dedicated connection so the recording and the writes share one physical connection. This is the #1 mistake.
import "liteorm.org/dialect/sqlite/changeset"
cs, err := changeset.Capture(ctx, db, []string{"users", "orders"},
func(ctx context.Context, s liteorm.Session) error {
_, err := s.ExecContext(ctx, `UPDATE users SET name = ? WHERE id = ?`, "Ada", 1)
return err
},
)
Pass a nil/empty table slice to record every table that has a primary key. cs is a []byte — store it, ship it, or apply it elsewhere.
Applying
err := changeset.Apply(ctx, replica, cs)
Resolve conflicts row by row with WithConflictHandler(func(ConflictType) ConflictAction):
err := changeset.Apply(ctx, replica, cs,
changeset.WithConflictHandler(func(t changeset.ConflictType) changeset.ConflictAction {
switch t {
case changeset.ConflictNotFound:
return changeset.Omit
case changeset.ConflictData:
return changeset.Replace
default:
return changeset.Abort
}
}),
)
- Conflict types:
ConflictData, ConflictNotFound, ConflictConflict, ConflictConstraint, ConflictForeignKey.
- Actions:
Omit, Replace, Abort.
WithTableFilter(func(table string) bool) restricts which tables the changeset applies to.
Inverting & concatenating
undo, err := changeset.Invert(ctx, db, cs)
combined, err := changeset.Concat(ctx, db, csA, csB)
Pitfalls
- Writes inside
Capture that don't use the handed-back session are silently not recorded.
- A table must have a PRIMARY KEY to be captured.
- SQLite-only; on other backends the import isn't available. For change tracking across backends, use an observer (the observability skill) or hooks.
Deeper