@antelopejs/interface-database-decorators 0.2.1 → 0.2.2
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.
- package/dist/common.js +7 -5
- package/dist/common.js.map +1 -1
- package/dist/model.js +21 -11
- package/dist/model.js.map +1 -1
- package/dist/modifiers/common.d.ts +4 -29
- package/dist/modifiers/common.js +12 -66
- package/dist/modifiers/common.js.map +1 -1
- package/dist/modifiers/encryption.js +32 -1
- package/dist/modifiers/encryption.js.map +1 -1
- package/dist/modifiers/hash.d.ts +3 -1
- package/dist/modifiers/hash.js +3 -1
- package/dist/modifiers/hash.js.map +1 -1
- package/dist/modifiers/internal/classes.d.ts +45 -0
- package/dist/modifiers/internal/classes.js +131 -0
- package/dist/modifiers/internal/classes.js.map +1 -0
- package/dist/modifiers/internal/records.d.ts +6 -0
- package/dist/modifiers/internal/records.js +12 -1
- package/dist/modifiers/internal/records.js.map +1 -1
- package/dist/modifiers/localization.d.ts +30 -4
- package/dist/modifiers/localization.js +8 -20
- package/dist/modifiers/localization.js.map +1 -1
- package/dist/tests/hash_upgrade.test.js +6 -2
- package/dist/tests/hash_upgrade.test.js.map +1 -1
- package/dist/tests/localized_query_keys.test.d.ts +1 -0
- package/dist/tests/localized_query_keys.test.js +63 -0
- package/dist/tests/localized_query_keys.test.js.map +1 -0
- package/dist/tests/metadata_inheritance.test.js +63 -0
- package/dist/tests/metadata_inheritance.test.js.map +1 -1
- package/dist/tests/modifiers/common.test.js +6 -0
- package/dist/tests/modifiers/common.test.js.map +1 -1
- package/dist/tests/modifiers/encryption_date_marker.test.js +22 -0
- package/dist/tests/modifiers/encryption_date_marker.test.js.map +1 -1
- package/dist/tests/modifiers/hash.test.js +10 -4
- package/dist/tests/modifiers/hash.test.js.map +1 -1
- package/dist/tests/modifiers/localization.test.js +134 -0
- package/dist/tests/modifiers/localization.test.js.map +1 -1
- package/dist/tests/modifiers/symbol_fields.test.d.ts +1 -0
- package/dist/tests/modifiers/symbol_fields.test.js +62 -0
- package/dist/tests/modifiers/symbol_fields.test.js.map +1 -0
- package/dist/tests/partial_update.test.js +79 -6
- package/dist/tests/partial_update.test.js.map +1 -1
- package/docs/3.table-modifiers.md +9 -6
- package/docs/4.data-models.md +2 -0
- package/package.json +4 -4
- package/skills/database-decorators-interface/SKILL.md +3 -0
|
@@ -110,13 +110,13 @@ A field with an `algorithm` stores the base64 digest of the row's salt followed
|
|
|
110
110
|
The `HashModifier` mixin adds these methods to table instances:
|
|
111
111
|
|
|
112
112
|
```typescript fragment
|
|
113
|
-
testHash<This extends {}, F extends keyof This>(this: This, field: F, value: This[F]):
|
|
113
|
+
testHash<This extends {}, F extends keyof This>(this: This, field: F, value: This[F]): boolean
|
|
114
114
|
testHashAsync<This extends {}, F extends keyof This>(this: This, field: F, value: This[F]): Promise<boolean>
|
|
115
115
|
isHashOutdated<This extends {}>(this: This, field: keyof This): boolean
|
|
116
116
|
```
|
|
117
117
|
|
|
118
118
|
- `testHashAsync` resolves whether `value` matches the stored hash. It runs scrypt on the thread pool, so use it on a server. It rejects with `Field <name> is not hashed` for a field without `@Hashed`.
|
|
119
|
-
- `testHash` gives the same result and blocks the event loop while scrypt runs.
|
|
119
|
+
- `testHash` gives the same result and blocks the event loop while scrypt runs. It throws `Field <name> is not hashed` for a field without `@Hashed`.
|
|
120
120
|
- `isHashOutdated` returns whether the stored hash differs from what the field writes today, which is any stored string that does not start with `$scrypt$ln=15,r=8,p=3$`. It returns `false` when nothing is stored, and always on a field with an `algorithm`. It throws `Field <name> is not hashed` for a field without `@Hashed`.
|
|
121
121
|
|
|
122
122
|
#### Upgrade stored hashes
|
|
@@ -187,11 +187,11 @@ console.log(german.name); // "Premium Headphones" (fallback)
|
|
|
187
187
|
|
|
188
188
|
#### Wildcard key
|
|
189
189
|
|
|
190
|
-
The wildcard key `"*"` reads or writes all translations at once. `localize()`
|
|
190
|
+
The wildcard key `"*"` reads or writes all translations at once. List the localized fields with it, and `localize("*", fields)` types each listed field as its values by locale, a `LocalizedRecords<T, K>`: a field declared as `string` reads as a `Record<string, string>`. Calling `localize()` on that view with one locale gives back the row type. The view is not the row type, so pass the row itself to `insert()` or `update()`. Write all translations with `Object.assign`, which calls the field's setter. `undefined` or `null` clears every translation. Any other value that is not a record, such as a single text, throws a `TypeError` and leaves the stored translations as they were:
|
|
191
191
|
|
|
192
192
|
```typescript fragment
|
|
193
193
|
// Get all translations
|
|
194
|
-
const allNames:
|
|
194
|
+
const allNames: Record<string, string> = product.localize("*", ["name"]).name;
|
|
195
195
|
// { en: "Premium Headphones", fr: "Casque Premium", es: "Auriculares Premium" }
|
|
196
196
|
|
|
197
197
|
// Set all translations
|
|
@@ -216,9 +216,12 @@ Object.assign(product.localize("*"), {
|
|
|
216
216
|
The `LocalizationModifier` mixin adds a `localize` method:
|
|
217
217
|
|
|
218
218
|
```typescript fragment
|
|
219
|
-
localize<This extends { constructor: any }>(this: This, locale:
|
|
219
|
+
localize<This extends { constructor: any }, K extends keyof This>(this: This, locale: "*", fields: readonly K[]): LocalizedRecords<This, K>
|
|
220
|
+
localize<This extends { constructor: any }>(this: This, locale: string, fields?: ReadonlyArray<keyof This>): This
|
|
220
221
|
```
|
|
221
222
|
|
|
223
|
+
Without `fields`, `localize("*")` unlocks every localized field but keeps the class's field types. A listed method stays callable.
|
|
224
|
+
|
|
222
225
|
`localize()` changes the active locale and returns the same object, not a copy for that locale.
|
|
223
226
|
|
|
224
227
|
- **References share state.** `spanish`, `german`, and `product` above refer to one object. A later `localize()` call changes what all three references read.
|
|
@@ -410,7 +413,7 @@ Base64 is an encoding, not encryption. The example declares its `LockedType` as
|
|
|
410
413
|
|
|
411
414
|
### `ContainerModifier`
|
|
412
415
|
|
|
413
|
-
A modifier that stores several values under keys, as `LocalizationModifier` does, extends `ContainerModifier`. Its `lock`, `unlock`, and `unlockrequest` take the key as their argument
|
|
416
|
+
A modifier that stores several values under keys, as `LocalizationModifier` does, extends `ContainerModifier`. Its `lock`, `unlock`, and `unlockrequest` take the key as their argument, a `string` or `undefined`. `lock` and `unlock` treat the wildcard key `"*"` as the whole record, and `lock` throws a `TypeError` for a value under `"*"` that is not a record. `undefined` is no key: `lock` stores nothing under it, and `unlock` and `unlockrequest` find no value, so a `LocalizationModifier` answers its `fallbackLocale`:
|
|
414
417
|
|
|
415
418
|
```typescript
|
|
416
419
|
import { ContainerModifier } from "@antelopejs/interface-database-decorators";
|
package/docs/4.data-models.md
CHANGED
|
@@ -95,6 +95,8 @@ await userModel.update({ _id: "user-123", name: "Updated Name" });
|
|
|
95
95
|
|
|
96
96
|
When you call `update` without a separate ID argument, the object must include the primary key. Its type requires `_id`, and a call without it throws `Missing primary key in object update.`
|
|
97
97
|
|
|
98
|
+
An update with plain data that sets a field whose modifiers lock without arguments, such as an encrypted or hashed field, first reads the row's stored modifier state, then locks the new value onto it. The row keeps its other modified fields and its hash salt. A table instance, such as one read with `get`, already holds that state and costs no extra read.
|
|
99
|
+
|
|
98
100
|
### Delete
|
|
99
101
|
|
|
100
102
|
```typescript fragment
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antelopejs/interface-database-decorators",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "AntelopeJS decorators for database tables and typed data models, with encrypted, hashed and localized fields",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antelopejs",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"test": "pnpm run build && ajs module test .",
|
|
129
129
|
"format:check": "oxfmt --check .",
|
|
130
130
|
"knip": "knip",
|
|
131
|
-
"prepare": "if
|
|
131
|
+
"prepare": "if [ -e .git ] && command -v git >/dev/null 2>&1 && command -v lefthook >/dev/null 2>&1 && GIT_DIR=.git GIT_WORK_TREE=. git rev-parse --git-dir >/dev/null 2>&1; then GIT_DIR=.git GIT_WORK_TREE=. lefthook install; fi",
|
|
132
132
|
"checks": "antelopejs-checks",
|
|
133
133
|
"size": "antelopejs-check-size",
|
|
134
134
|
"sync": "antelopejs-sync",
|
|
@@ -142,11 +142,11 @@
|
|
|
142
142
|
"reflect-metadata": "^0.2.2"
|
|
143
143
|
},
|
|
144
144
|
"devDependencies": {
|
|
145
|
-
"@antelopejs/core": "^1.
|
|
145
|
+
"@antelopejs/core": "^1.21.0",
|
|
146
146
|
"@antelopejs/interface-api": "^0.0.15",
|
|
147
147
|
"@antelopejs/interface-core": "^0.4.0",
|
|
148
148
|
"@antelopejs/interface-database": "^0.3.0",
|
|
149
|
-
"@antelopejs/tooling-configs": "^0.
|
|
149
|
+
"@antelopejs/tooling-configs": "^0.4.0",
|
|
150
150
|
"@types/chai": "^4.3.20",
|
|
151
151
|
"@types/mocha": "^10.0.10",
|
|
152
152
|
"@types/node": "^22.19.15",
|
|
@@ -129,7 +129,10 @@ class Chef extends Table.with(
|
|
|
129
129
|
- `@Hashed({ algorithm })` stores a fast digest instead of scrypt: use it only for non-secret fingerprints, never for credentials.
|
|
130
130
|
- Localized fields must be written through a localized instance (`instance.localize(locale).field = ...`);
|
|
131
131
|
values assigned before `localize()` are held in floating state and silently dropped on insert/update.
|
|
132
|
+
- `instance.localize("*", ["motto"])` reads and writes every locale at once, typed `Record<string, string>` for each listed field (`LocalizedRecords<T, K>`); without a field list the field types stay unchanged.
|
|
133
|
+
- Under `localize("*")` a localized field takes the record of texts by locale, and `undefined` or `null` clears every locale. A single text throws a `TypeError`, whether it is assigned or held from `fromPlainData` when `localize("*")` runs.
|
|
132
134
|
- A localized value `""` is stored as no value: reads and queries in that locale get the `fallbackLocale` value.
|
|
135
|
+
- A `ContainerModifier` key of `undefined` is no key: writes store nothing under it, and reads and queries get no value, or the `fallbackLocale` value for a localized field.
|
|
133
136
|
- `@Relation({ to: () => Target })` is declarative metadata only: no foreign-key enforcement, consumed by introspection tooling via `RelationStaticMetadata`.
|
|
134
137
|
- `Model.validate` (and `{ validate: true }` on insert/update) only checks fields whose `@Field` type is an
|
|
135
138
|
io-ts-style codec with `.decode`; plain string field tokens are skipped. Update validates with
|