@antelopejs/interface-database-decorators 0.1.11 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +17 -13
  2. package/dist/antelope.test.js +1 -1
  3. package/dist/common.d.ts +48 -2
  4. package/dist/common.js +51 -5
  5. package/dist/common.js.map +1 -1
  6. package/dist/database.js +18 -3
  7. package/dist/database.js.map +1 -1
  8. package/dist/internal/bound-schema.d.ts +8 -0
  9. package/dist/internal/bound-schema.js +14 -0
  10. package/dist/internal/bound-schema.js.map +1 -0
  11. package/dist/model.d.ts +21 -8
  12. package/dist/model.js +34 -15
  13. package/dist/model.js.map +1 -1
  14. package/dist/modifiers/autodate.d.ts +2 -2
  15. package/dist/modifiers/autodate.js.map +1 -1
  16. package/dist/modifiers/common.d.ts +37 -20
  17. package/dist/modifiers/common.js +81 -68
  18. package/dist/modifiers/common.js.map +1 -1
  19. package/dist/modifiers/encryption.js +26 -14
  20. package/dist/modifiers/encryption.js.map +1 -1
  21. package/dist/modifiers/hash.d.ts +46 -4
  22. package/dist/modifiers/hash.js +175 -14
  23. package/dist/modifiers/hash.js.map +1 -1
  24. package/dist/modifiers/internal/kinds.d.ts +15 -1
  25. package/dist/modifiers/internal/kinds.js +35 -0
  26. package/dist/modifiers/internal/kinds.js.map +1 -1
  27. package/dist/modifiers/internal/records.d.ts +40 -5
  28. package/dist/modifiers/internal/records.js +70 -1
  29. package/dist/modifiers/internal/records.js.map +1 -1
  30. package/dist/modifiers/localization.js +12 -7
  31. package/dist/modifiers/localization.js.map +1 -1
  32. package/dist/relation.d.ts +5 -0
  33. package/dist/relation.js +11 -0
  34. package/dist/relation.js.map +1 -1
  35. package/dist/schema.js +5 -6
  36. package/dist/schema.js.map +1 -1
  37. package/dist/table.d.ts +3 -2
  38. package/dist/table.js +29 -13
  39. package/dist/table.js.map +1 -1
  40. package/dist/tests/cross_instance.test.js +5 -2
  41. package/dist/tests/cross_instance.test.js.map +1 -1
  42. package/dist/tests/database.test.js +42 -2
  43. package/dist/tests/database.test.js.map +1 -1
  44. package/dist/tests/hash_upgrade.test.d.ts +1 -0
  45. package/dist/tests/hash_upgrade.test.js +132 -0
  46. package/dist/tests/hash_upgrade.test.js.map +1 -0
  47. package/dist/tests/helpers/hash-rows.d.ts +40 -0
  48. package/dist/tests/helpers/hash-rows.js +41 -0
  49. package/dist/tests/helpers/hash-rows.js.map +1 -0
  50. package/dist/tests/helpers/other-instance.js.map +1 -1
  51. package/dist/tests/integration.test.js +15 -4
  52. package/dist/tests/integration.test.js.map +1 -1
  53. package/dist/tests/metadata_inheritance.test.d.ts +1 -0
  54. package/dist/tests/metadata_inheritance.test.js +212 -0
  55. package/dist/tests/metadata_inheritance.test.js.map +1 -0
  56. package/dist/tests/modifiers/encryption_date_marker.test.d.ts +1 -0
  57. package/dist/tests/modifiers/encryption_date_marker.test.js +78 -0
  58. package/dist/tests/modifiers/encryption_date_marker.test.js.map +1 -0
  59. package/dist/tests/modifiers/hash.test.js +295 -0
  60. package/dist/tests/modifiers/hash.test.js.map +1 -1
  61. package/dist/tests/modifiers/inherited_names.test.d.ts +1 -0
  62. package/dist/tests/modifiers/inherited_names.test.js +96 -0
  63. package/dist/tests/modifiers/inherited_names.test.js.map +1 -0
  64. package/dist/tests/own_key_lookups.test.d.ts +1 -0
  65. package/dist/tests/own_key_lookups.test.js +49 -0
  66. package/dist/tests/own_key_lookups.test.js.map +1 -0
  67. package/dist/tests/partial_update.test.d.ts +1 -0
  68. package/dist/tests/partial_update.test.js +55 -0
  69. package/dist/tests/partial_update.test.js.map +1 -0
  70. package/dist/tests/row_forms.test.d.ts +1 -0
  71. package/dist/tests/row_forms.test.js +59 -0
  72. package/dist/tests/row_forms.test.js.map +1 -0
  73. package/dist/tests/stored_metadata.test.d.ts +1 -0
  74. package/dist/tests/stored_metadata.test.js +91 -0
  75. package/dist/tests/stored_metadata.test.js.map +1 -0
  76. package/dist/tests/subclass_schema_binding.test.d.ts +1 -0
  77. package/dist/tests/subclass_schema_binding.test.js +115 -0
  78. package/dist/tests/subclass_schema_binding.test.js.map +1 -0
  79. package/dist/tests/table.test.js +16 -0
  80. package/dist/tests/table.test.js.map +1 -1
  81. package/docs/1.introduction.md +24 -20
  82. package/docs/2.table-definitions.md +63 -41
  83. package/docs/3.table-modifiers.md +128 -98
  84. package/docs/4.data-models.md +63 -52
  85. package/docs/5.parameter-decoration.md +28 -24
  86. package/docs/tsconfig.json +3 -0
  87. package/package.json +10 -9
  88. package/skills/database-decorators-interface/SKILL.md +6 -3
@@ -1,10 +1,14 @@
1
- # Table Definitions
1
+ ---
2
+ title: Table definitions
3
+ description: Reference for the Table class and the Field, Index, Relation, RegisterTable, and Fixture decorators, RegisterSchema, and Table.table.
4
+ mode: reference
5
+ ---
2
6
 
3
- The Database Decorators package provides a class-based approach to defining database tables. You extend the `Table` base class, declare each field with TypeScript's `declare` keyword and the `@Field` decorator, and use further decorators to configure indexes, relations, and initial data.
7
+ A table is a class that extends `Table`. Each field is a property declared with TypeScript's `declare` keyword and the `@Field` decorator. Further decorators add indexes, relations, and initial data.
4
8
 
5
- ## The Table Class
9
+ ## The `Table` class
6
10
 
7
- The `Table` class serves as the base class for all table definitions. Every table automatically includes an `_id` field as the primary key.
11
+ `Table` is the base class of every table definition. It declares `_id: string`, the primary key of every table.
8
12
 
9
13
  ```typescript
10
14
  import { Table, Field } from "@antelopejs/interface-database-decorators";
@@ -18,9 +22,9 @@ class User extends Table {
18
22
  }
19
23
  ```
20
24
 
21
- ### Extend with Modifiers
25
+ ### Extend with modifiers
22
26
 
23
- The `Table.with()` static method incorporates modifier mixins into the table class, adding capabilities like encryption, hashing, or localization:
27
+ The static `Table.with()` method returns a subclass of the table class that holds the mixin methods of the modifiers it receives, such as encryption, hashing, or localization:
24
28
 
25
29
  ```typescript
26
30
  import {
@@ -45,11 +49,11 @@ class SensitiveData extends Table.with(EncryptionModifier) {
45
49
  }
46
50
  ```
47
51
 
48
- Provide a high-entropy key through your secret manager; do not use a default key. See [Table Modifiers](./3.table-modifiers.md#encryptionmodifier) for key format and date precision constraints.
52
+ Provide a high-entropy key through your secret manager, and never a default key. See [Table modifiers](./3.table-modifiers.md#encryptionmodifier) for the key format and the date precision limit.
49
53
 
50
- ## The Index Decorator
54
+ ## The `Index` decorator
51
55
 
52
- The `Index` decorator marks a field as a database index. Indexed fields enable efficient lookups through `getAll()` and `between()` on the underlying AQL table.
56
+ The `Index` decorator marks a field as a database index. An indexed field serves lookups through `getAll()` and `between()` on the AQL table, and through the model's `getBy()`. `@Index` on a symbol-keyed property throws, because a database index names a field.
53
57
 
54
58
  ```typescript
55
59
  import { Table, Field, Index } from "@antelopejs/interface-database-decorators";
@@ -72,13 +76,15 @@ class User extends Table {
72
76
  | `crossInstance` | `boolean` | Also keep the index fast for queries that run across all instances. |
73
77
  | `unique` | `boolean` | Refuse two rows of the instance with the same key. |
74
78
 
75
- ### Cross-Instance Indexes
79
+ ### Cross-instance indexes
76
80
 
77
- Every index is scoped to the schema instance, so queries on a single instance always use it. Set `crossInstance: true` when the index is also queried across all instances (queries on the `CROSS_INSTANCE` instance), so the database driver maintains an additional index for those queries.
81
+ Every index is scoped to the schema instance. Set `crossInstance: true` when queries across all instances (on the `CROSS_INSTANCE` instance) also use the index. The database driver then maintains an additional index for those queries.
78
82
 
79
- The option never changes query results. Without it, cross-instance queries that name the index still return the same rows but run slower, and the driver logs a warning once per index. Leave it unset for indexes that are only queried within one instance, since each extra index costs storage and write time.
83
+ The option never changes query results. Without it, a cross-instance query that names the index returns the same rows but runs slower, and the `@antelopejs/mongodb` and `@antelopejs/rethinkdb` drivers log a warning once per index. Leave it unset for an index that only queries within one instance use, because each extra index costs storage and write time.
80
84
 
81
85
  ```typescript
86
+ import { Field, Index, Table } from "@antelopejs/interface-database-decorators";
87
+
82
88
  class User extends Table {
83
89
  @Index({ crossInstance: true })
84
90
  @Field("string")
@@ -88,11 +94,13 @@ class User extends Table {
88
94
 
89
95
  For a compound index, setting `crossInstance: true` on any field of the group applies it to the whole group.
90
96
 
91
- ### Unique Indexes
97
+ ### Unique indexes
92
98
 
93
- Set `unique: true` to refuse a second row with the same key in one instance. The write that would store it throws `DuplicateKeyError` from `@antelopejs/interface-database`, naming the index and its fields; test it with `IsDuplicateKeyError`. Rows of different instances may share a key.
99
+ Set `unique: true` to refuse a second row with the same key in one instance. The write that would store it throws `DuplicateKeyError` from `@antelopejs/interface-database`, which names the index and its fields. Test for it with `IsDuplicateKeyError`. Rows of different instances may share a key.
94
100
 
95
101
  ```typescript
102
+ import { Field, Index, Table } from "@antelopejs/interface-database-decorators";
103
+
96
104
  class Template extends Table {
97
105
  @Index({ unique: true })
98
106
  @Field("string")
@@ -100,9 +108,9 @@ class Template extends Table {
100
108
  }
101
109
  ```
102
110
 
103
- For a compound index, setting `unique: true` on any field of the group makes the whole group's key unique. Not every database module can enforce unique secondary indexes: one that cannot refuses the schema rather than ignoring the option.
111
+ For a compound index, setting `unique: true` on any field of the group makes the whole group's key unique. Not every database module can enforce a unique secondary index. A module that cannot, such as `@antelopejs/rethinkdb`, refuses the schema instead of ignoring the option.
104
112
 
105
- ### Compound Indexes
113
+ ### Compound indexes
106
114
 
107
115
  Assign multiple fields to the same index group to create a compound index:
108
116
 
@@ -134,11 +142,11 @@ class UserActivity extends Table {
134
142
  }
135
143
  ```
136
144
 
137
- ## The Field Decorator
145
+ ## The `Field` decorator
138
146
 
139
- `@Field(type)` declares the field type for a property. The type is forwarded verbatim into the `TableDefinition.fields` map handed to the adapter. It accepts the full `FieldType` union -- primitive tokens (`"string"`, `"number"`, ...), arrays, nested records, or an io-ts codec.
147
+ `@Field(type)` declares the type of a property. The type goes unchanged into the `TableDefinition.fields` map that the database module receives. It accepts every member of the `FieldType` union, for example a string token such as `"string"` or `"number"`, an array, a nested record, or an io-ts codec.
140
148
 
141
- ```typescript
149
+ ```typescript fragment
142
150
  import * as t from "io-ts";
143
151
  import {
144
152
  Table,
@@ -161,13 +169,13 @@ class Order extends Table {
161
169
  }
162
170
  ```
163
171
 
164
- Properties without `@Field` are omitted from `fields`. `@Field` stacks freely with `@Index`.
172
+ Properties without `@Field` are left out of `fields`. `@Field` and `@Index` each write their own metadata, so they combine in either order.
165
173
 
166
- ## The Relation Decorator
174
+ ## The `Relation` decorator
167
175
 
168
- The `Relation` decorator declares a link from a field to another table. It is **declarative metadata only**: database implementations do not enforce it (no foreign key constraint, no referential validation). Introspection tooling consumes it to expose the links between tables — for example to render schema diagrams or navigate related records.
176
+ The `Relation` decorator declares a link from a field to another table. It is metadata only. Database modules do not enforce it, with no foreign key constraint and no check that the target exists. Introspection tools read it to show the links between tables, for example in a schema diagram or to navigate to related records.
169
177
 
170
- ```typescript
178
+ ```typescript fragment
171
179
  import {
172
180
  Table,
173
181
  Field,
@@ -195,11 +203,11 @@ class Comment extends Table {
195
203
  | `toField` | `string` | Target field name. Defaults to the target table's primary key. |
196
204
  | `many` | `boolean` | The decorated field holds multiple target keys (many targets per source record). |
197
205
 
198
- `@Relation` stacks freely with `@Field` and `@Index`.
206
+ `@Relation` writes its own metadata, so it combines with `@Field` and `@Index` in any order.
199
207
 
200
- ## The RegisterTable Decorator
208
+ ## The `RegisterTable` decorator
201
209
 
202
- The `RegisterTable` class decorator associates a table class with a specific table name and schema. This registration is used by `RegisterSchema` to build the schema definition automatically.
210
+ The `RegisterTable` class decorator gives a table class its table name and its schema. `RegisterSchema` builds the schema definition from these registrations.
203
211
 
204
212
  ```typescript
205
213
  import {
@@ -222,9 +230,9 @@ class User extends Table {
222
230
 
223
231
  The first argument is the table name in the database, and the second is the schema name.
224
232
 
225
- ## The Fixture Decorator
233
+ ## The `Fixture` decorator
226
234
 
227
- The `Fixture` decorator defines default data to insert when a table is first created. It receives a generator function that produces initial records.
235
+ The `Fixture` decorator defines the rows to insert into an empty table. It receives a generator function that returns them.
228
236
 
229
237
  ```typescript
230
238
  import {
@@ -246,13 +254,21 @@ class UserRole extends Table {
246
254
 
247
255
  The generator function:
248
256
 
249
- - Receives the table class as its parameter.
250
- - Can return a single object, an array of objects, or a `Promise` resolving to either.
251
- - Runs only when the table is empty, preventing duplicate inserts on subsequent starts.
257
+ - Receives the table class registered into the schema, which is the decorated class or a subclass of it.
258
+ - Can return a single object, an array of objects, or a `Promise` of either.
259
+ - Runs when `RegisterSchema` finds the table empty, so a later start inserts nothing again.
252
260
 
253
- ### Async Generators
261
+ Only a table registered with `@RegisterTable` gets its fixture, from `RegisterSchema`. Each row goes through the same conversion as a model insert, so modifiers and the `insert` event apply. A row without an `_id` gets `<table>:fixture:<position>`, so two processes that start on the same empty table write one row between them.
262
+
263
+ ### Async generators
264
+
265
+ ```typescript fragment
266
+ import {
267
+ Field,
268
+ Fixture,
269
+ Table,
270
+ } from "@antelopejs/interface-database-decorators";
254
271
 
255
- ```typescript
256
272
  @Fixture(async () => {
257
273
  const defaults = await loadDefaultConfig();
258
274
  return defaults.map((cfg) => ({
@@ -268,7 +284,7 @@ class SystemConfig extends Table {
268
284
 
269
285
  ## Inheritance
270
286
 
271
- Tables support standard class inheritance. Define a base table with common fields and extend it for specific use cases:
287
+ A table class can extend another table class. The subclass starts with a copy of its parent's table and schema names, fields, indexes, and fixture, so decorators on the subclass do not change the parent:
272
288
 
273
289
  ```typescript
274
290
  import {
@@ -312,11 +328,11 @@ class Post extends BaseEntity {
312
328
  }
313
329
  ```
314
330
 
315
- ## Register a Schema
331
+ ## Register a schema
316
332
 
317
- The `RegisterSchema` function builds a `SchemaDefinition` from all tables registered for the given schema id (via `@RegisterTable`), constructs the `Schema` (which the adapter provisions), binds each table class to that `Schema` (see [Open a Table from its Class](#open-a-table-from-its-class)), then inserts any fixture data for tables that are empty.
333
+ The `RegisterSchema` function builds a `SchemaDefinition` from every table that `@RegisterTable` registered for the schema ID. It constructs the `Schema`, which the database module provisions, and binds each table class to it (see [Open a table from its class](#open-a-table-from-its-class)). Then it inserts the fixtures of the tables that are empty.
318
334
 
319
- Call it in the module that declares the tables: the binding then follows that module's database, whichever module later uses the classes.
335
+ Call it in the module that declares the tables. The binding then follows that module's database, whichever module later uses the classes.
320
336
 
321
337
  ```typescript
322
338
  import { RegisterSchema } from "@antelopejs/interface-database-decorators";
@@ -330,13 +346,19 @@ await RegisterSchema("myapp");
330
346
  | ---------- | -------- | ------------------------------------------------------------------ |
331
347
  | `schemaId` | `string` | Schema id matching the `@RegisterTable(_, schemaId)` declarations. |
332
348
 
333
- `RegisterSchema` returns `Promise<void>`.
349
+ `RegisterSchema` returns `Promise<void>`. It throws `No tables registered for schema '<schemaId>'` when no class registers into the schema.
334
350
 
335
- ## Open a Table from its Class
351
+ ## Open a table from its class
336
352
 
337
353
  `Table.table()` returns the AQL table a class describes, in the schema `RegisterSchema` bound it to:
338
354
 
339
- ```typescript
355
+ ```typescript fragment
356
+ import {
357
+ RegisterSchema,
358
+ RegisterTable,
359
+ Table,
360
+ } from "@antelopejs/interface-database-decorators";
361
+
340
362
  @RegisterTable("users", "myapp")
341
363
  class User extends Table {
342
364
  declare name: string;
@@ -349,4 +371,4 @@ User.table("tenant-1"); // instance "tenant-1" (CROSS_INSTANCE is accepted too)
349
371
  User.table(db); // db.table("users") on a SchemaInstance you already hold
350
372
  ```
351
373
 
352
- When given a `SchemaInstance`, `table()` takes the table from it as is: pass an instance of the class's own schema. A class that no `RegisterSchema` call bound throws, naming the class.
374
+ Given a `SchemaInstance`, `table()` takes the table from it as is, so pass an instance of the class's own schema. A class without `@RegisterTable` throws `<Class> has no table name`. A class that no `RegisterSchema` call bound, and whose schema name has no schema, throws `<Class> is not bound to a schema`.