Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9fd2034
refactor: clear the avoidable ratchet findings of pack 0.2.17 (#50)
Upd4ting Oct 30, 2026
161c3e2
fix(metadata): upgrade the table metadata stored by an older copy of …
Upd4ting Oct 31, 2026
5508daf
fix(modifiers): look up a container entry by own key (#56)
Upd4ting Oct 31, 2026
352bb34
fix(encryption): revive only the date marker the encoder writes (#57)
Upd4ting Oct 31, 2026
b439da5
fix(metadata): copy the metadata a subclass inherits instead of shari…
Upd4ting Oct 31, 2026
9f1e2d3
fix(modifiers): look up modified fields and event names by own key (#53)
Upd4ting Oct 31, 2026
734fb59
docs: typecheck every example and drop hand-written version prose (#58)
Upd4ting Oct 31, 2026
0cf86ee
feat(database-decorators)!: type the fixture, model and modifier even…
Upd4ting Oct 31, 2026
a9d2f49
chore(ratchet): lower ceilings to the measured counts (#64)
Upd4ting Oct 31, 2026
0bbffc8
refactor(encryption): read the value date_encoder encodes through one…
Upd4ting Oct 31, 2026
fcb0a29
feat(database-decorators)!: name the row forms the conversions read a…
Upd4ting Oct 31, 2026
aabd36b
chore(ratchet): lower ceilings to measured counts (#69)
Upd4ting Nov 1, 2026
e79a62b
refactor(database-decorators): read the unlockrequest key as text for…
Upd4ting Nov 1, 2026
0fb36e4
feat(database-decorators): let attachModifier and unlockrequest take …
Upd4ting Nov 2, 2026
9a1d103
chore(ratchet): delete the guardrail ratchet (#72)
Upd4ting Nov 2, 2026
7a0cbf5
build(deps): pin core 1.20.0 and interface-core 0.4.0 to the W7 tarba…
Upd4ting Nov 2, 2026
4a959c7
chore: merge main into campaign/integration (#77)
Upd4ting Nov 3, 2026
eaf455d
docs: pass the database-decorators docs to the docs standard (#78)
Upd4ting Nov 3, 2026
e31f7e9
build(deps): take the released interface-database (#82)
Upd4ting Nov 4, 2026
a17cb12
ci(release): pass the release version to the shared release workflow …
Upd4ting Nov 4, 2026
78a7b50
build(deps): take the released interface-core 0.4.0 (#85)
Upd4ting Nov 4, 2026
fa91e2d
docs(readme): link the package to AntelopeJS and AntelopeJS DMS (#86)
Upd4ting Nov 4, 2026
2b40c4f
test: load the api release that keeps interface-api 0.1 (#88)
Upd4ting Nov 4, 2026
a269171
build(deps): take the released core (#89)
Upd4ting Nov 4, 2026
69ef969
chore: merge main into the landing branch
Upd4ting Nov 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ permissions:

jobs:
ci:
uses: AntelopeJS/.github/.github/workflows/ci-node.yml@v1
uses: AntelopeJS/.github/.github/workflows/ci-node.yml@v1-campaign
with:
docs-files: |
README.md
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ on:
options:
- latest
- next
release-version:
description: Exact stable version; empty uses the automatic increment
required: false
type: string

permissions:
contents: write
Expand All @@ -21,5 +25,6 @@ jobs:
uses: AntelopeJS/.github/.github/workflows/release-npm-public.yml@v1
with:
channel: ${{ inputs.channel }}
release-version: ${{ inputs.release-version }}
secrets:
RELEASE_GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }}
7 changes: 1 addition & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The release commit writes `CHANGELOG.md`. Upgrade notes for that version follow

## Guardrails

Finish every change with `pnpm run checks`. It runs typecheck, lint, format, knip, tests, size, ratchet, suppressions, and sync, and prints only what failed. The change is done when it prints no failure.
Finish every change with `pnpm run checks`. It runs typecheck, lint, format, knip, tests, size, suppressions, and sync, and prints only what failed. The change is done when it prints no failure.

The tools enforce most rules, listed in the table at the end. The sections below hold the rules no tool checks.

Expand Down Expand Up @@ -69,10 +69,6 @@ Verify a boundary against the imports a developer or agent would plausibly write

`guardrails.suppressions.json` caps the suppressions in authored code: lint directives per rule they name (`*` for none), `@ts-expect-error`, `@ts-ignore` and `SAFETY:` comments, and under `config` each rule a lint config (`oxlint.config.*`, `.oxlintrc.json`, `eslint.config.*`) switches off or to a warning, keyed by rule and `files` glob anchored at the config's directory, so widening or moving a scope is a new ceiling of 0, while narrowing one takes over the room it gives up. Switching a rule off in a config is a suppression too: fix the code its rule reports instead. A suppression over its ceiling fails: fix the code, or remove another suppression of the same kind. A rule that keeps needing suppressions should be changed in the preset. Never raise or remove a number in that file: the check fails a ceiling higher than on the pull request base, and only the operator approves a raise. A directive disabling `anti-slop/require-safety-comment-for-type-assertion` is burn-down debt: remove the assertion, or, where it holds, replace the directive with `SAFETY: <why it holds>`, which takes over its room without a raise. After you remove suppressions, run `pnpm run suppressions:update` and commit the lowered file.

### Debt

`guardrails.ratchet.json` records the lint findings and oversize files this repository already had. Its numbers only go down. After you remove debt, or after a pack upgrade, run `pnpm run ratchet:update` and commit the file: it lowers the numbers and adds only the rules the new pack release enabled, at today's count. Never edit the numbers by hand; CI fails one added or raised against the base. A rule listed there is off for `oxlint`. The ratchet counts it instead, and the pre-commit hook rejects it on every line you add.

### What enforces what

| Rule | Enforced by |
Expand Down Expand Up @@ -114,6 +110,5 @@ Verify a boundary against the imports a developer or agent would plausibly write
| Entry-only rules exempt no tracked outsider | `antelopejs-sync --check` |
| A DMS layer's `build/backend-boundary.ts` is the pack's plugin | `antelopejs-sync --check` |
| A test names the wrong implementation it catches | review; no tool |
| Existing debt only shrinks | `antelopejs-ratchet` |

<!-- antelopejs-guardrails:end -->
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# @antelopejs/interface-database-decorators
# `@antelopejs/interface-database-decorators`

<div align="center">
<a href="https://www.npmjs.com/package/@antelopejs/interface-database-decorators"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-database-decorators?style=for-the-badge&labelColor=000000&color=000000"></a>
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-database-decorators?style=for-the-badge&labelColor=000000&color=000000"></a>
<a href="https://discord.gg/g4pFt6eXqu"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
<a href="https://interfaces.antelopejs.com/docs/database-decorators"><img alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
<a href="https://www.npmjs.com/package/@antelopejs/interface-database-decorators"><img data-illustration alt="npm" src="https://img.shields.io/npm/v/@antelopejs/interface-database-decorators?style=for-the-badge&labelColor=000000&color=000000"></a>
<a href="./LICENSE"><img data-illustration alt="License" src="https://img.shields.io/npm/l/@antelopejs/interface-database-decorators?style=for-the-badge&labelColor=000000&color=000000"></a>
<a href="https://discord.gg/g4pFt6eXqu"><img data-illustration alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
<a href="https://interfaces.antelopejs.com/docs/database-decorators"><img data-illustration alt="Docs" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
</div>

Database tables and data models as TypeScript classes, on top of [`@antelopejs/interface-database`](https://github.com/AntelopeJS/interface-database): declare fields and indexes with decorators, then read and write rows through a typed model.
Database tables and data models as TypeScript classes, on top of [`@antelopejs/interface-database`](https://github.com/AntelopeJS/interface-database). Declare fields and indexes with decorators, then read and write rows through a typed model.

Part of [AntelopeJS](https://github.com/AntelopeJS/antelopejs). Used by [AntelopeJS DMS](https://github.com/AntelopeJS/dms), the open-source back office for your PostgreSQL, MongoDB or RethinkDB database.

Expand Down Expand Up @@ -90,15 +90,15 @@ export async function start() {

## Compatibility

Requires AntelopeJS core `1.x` and the following peer dependencies:
The package declares these `@antelopejs/*` peer dependencies:

<!-- antelopejs-docs-compat:start -->

| Package | Supported | Tested with |
| -------------------------------- | ----------------- | ----------- |
| `@antelopejs/interface-api` | `>=0.0.15 <1.0.0` | `0.0.15` |
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` | `0.2.4` |
| `@antelopejs/interface-database` | `>=0.1.11 <1.0.0` | `0.1.11` |
| `@antelopejs/interface-core` | `>=0.2.4 <1.0.0` | `0.4.0` |
| `@antelopejs/interface-database` | `>=0.1.11 <1.0.0` | `0.3.0` |

<!-- antelopejs-docs-compat:end -->

Expand Down
44 changes: 24 additions & 20 deletions docs/1.introduction.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
# Define tables and work with models
---
title: Define tables and work with models
description: Describe a table as a TypeScript class, register its schema, and save and read a first row through a typed model.
mode: how-to
---

## Overview

Use `@antelopejs/interface-database-decorators` to describe tables with TypeScript classes and work with converted records through models. It builds on AQL (`@antelopejs/interface-database`) and adds field modifiers and API model injection.
`@antelopejs/interface-database-decorators` describes tables as TypeScript classes and reads and writes converted rows through models. It builds on AQL (`@antelopejs/interface-database`) and adds field modifiers and model injection into API controllers.

## From a table class to a stored record

1. **Describe the table.** Extend `Table`, declare fields and indexes, and register the class with `@RegisterTable("users", "myapp")`. See [table definitions](./2.table-definitions.md).
2. **Bind the schema.** Import the table declarations, then call `await RegisterSchema("myapp")` from their declaring module. This requires a configured database provider and can provision tables and insert fixtures; it is not a read-only metadata operation.
3. **Create the model.** Use `BasicDataModel(User)` and a `SchemaInstance`, or `GetModel` after the table has been bound. See [data models](./4.data-models.md).
4. **Write and read through the model.** Model operations apply conversion and modifier events. Use `model.table` when you need to compose an AQL query yourself.
2. **Bind the schema.** Import the table declarations, then call `await RegisterSchema("myapp")` from their declaring module. The call needs a configured database module. It provisions the tables and inserts fixtures, so it writes to the database.
3. **Create the model.** Use `BasicDataModel(User)` with a `SchemaInstance`, or call `GetModel` once the table is bound. See [data models](./4.data-models.md).
4. **Write and read through the model.** Model operations apply the conversions and the modifier events. To compose an AQL query yourself, use `model.table`.

Keep schema IDs and instance IDs distinct: `myapp` identifies the table definitions; an instance ID selects the database instance used by a model. A table class without a schema binding cannot be resolved by `GetModel`.
Keep schema IDs and instance IDs apart. `myapp` names the table definitions, and an instance ID selects the database instance a model uses. `GetModel` throws for a table class that `RegisterSchema` has not bound, unless a schema of the class's schema name already exists.

### Save and retrieve a note

In a module with a configured database provider, import this declaration before calling `tryNote()` during initialization. Use a disposable development database: `RegisterSchema` provisions the schema, and `insert` writes data.
In a module with a configured database module, import this declaration, then call `tryNote()` during initialization. Use a disposable development database, because `RegisterSchema` provisions the schema and `insert` writes a row.

```ts docs-check
import {
Expand Down Expand Up @@ -45,7 +49,7 @@ export async function tryNote() {
}
```

The model uses the default instance of the schema bound to `Note`. Keep the inserted ID when extending this exercise with `update` or `delete`; each successful run inserts a new note. In an application, register the schema once during initialization rather than on each request.
The model uses the default instance of the schema bound to `Note`. Each run inserts a new note, so keep the inserted ID if you extend this exercise with `update` or `delete`. In an application, register the schema once during initialization, not on each request.

## Choose the layer for your task

Expand All @@ -54,23 +58,23 @@ The model uses the default instance of the schema bound to `Note`. Keep the inse
| Describe storage fields and indexes | [Table definitions](./2.table-definitions.md) | Declaring a class is separate from registering its schema. |
| Encrypt, hash, or localize fields | [Table modifiers](./3.table-modifiers.md) | Conversion events determine when transformations run. |
| Read or write converted records | [Data models](./4.data-models.md) | Reads return converted records, not chainable queries. |
| Select a model in an HTTP request | [Parameter decoration](./5.parameter-decoration.md) | The instance ID selects a binding; it does not authorize access. |
| Select a model in an HTTP request | [Parameter decoration](./5.parameter-decoration.md) | The instance ID selects a binding. It does not authorize access. |

Start without modifiers until the schema and model work together. Add validation explicitly: string-token `@Field` declarations describe storage, while codec validation requires codecs and the model's validation options.
Start without modifiers until the schema and the model work together. Validation is opt-in. A string-token `@Field` describes storage only, and codec validation needs io-ts codecs and the model's `validate` option.

## Dependencies

This package depends on the following:
The package depends on these packages:

- [**@antelopejs/interface-database**](https://github.com/AntelopeJS/interface-database) - The underlying database query interface (AQL)
- [**@antelopejs/interface-api**](https://github.com/AntelopeJS/interface-api) - API controller integration for parameter decoration
- [**@antelopejs/interface-core**](https://github.com/AntelopeJS/interface-core) - Core decorator utilities
- [**reflect-metadata**](https://www.npmjs.com/package/reflect-metadata) - Metadata reflection for TypeScript decorators
- [**randomstring**](https://www.npmjs.com/package/randomstring) - Random string generation for hash salts
- [`@antelopejs/interface-database`](https://github.com/AntelopeJS/interface-database) is the database query interface (AQL).
- [`@antelopejs/interface-api`](https://github.com/AntelopeJS/interface-api) provides the API controllers that `@Model` injects into.
- [`@antelopejs/interface-core`](https://github.com/AntelopeJS/interface-core) provides the decorator factories.
- [`reflect-metadata`](https://www.npmjs.com/package/reflect-metadata) stores the decorator metadata.
- [`randomstring`](https://www.npmjs.com/package/randomstring) generates the salt of a `@Hashed` field that sets an `algorithm`.

## Documentation

- [Table Definitions](./2.table-definitions.md) - Define database tables with the `Table` class, `Index` decorator, and `Fixture` decorator
- [Table Modifiers](./3.table-modifiers.md) - Apply encryption, hashing, and localization modifiers to table fields, or create custom modifiers
- [Data Models](./4.data-models.md) - Create data models with `BasicDataModel` for CRUD operations and data conversion
- [Parameter Decoration](./5.parameter-decoration.md) - Inject model instances into API controller methods with the `Model` decorator
- [Table definitions](./2.table-definitions.md) covers the `Table` class and the `Field`, `Index`, `Relation`, `RegisterTable`, and `Fixture` decorators.
- [Table modifiers](./3.table-modifiers.md) covers encryption, hashing, and localization of fields, and custom modifiers.
- [Data models](./4.data-models.md) covers `BasicDataModel`, its CRUD methods, and the data conversions.
- [Parameter decoration](./5.parameter-decoration.md) covers the `Model` decorator, which injects a model into API controller methods.
Loading
Loading