@antelopejs/interface-database-decorators 0.3.1 → 0.3.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/modifiers/localization.d.ts +11 -1
- package/dist/modifiers/localization.js +23 -0
- package/dist/modifiers/localization.js.map +1 -1
- package/dist/tests/localized_plain_data.test.d.ts +1 -0
- package/dist/tests/localized_plain_data.test.js +87 -0
- package/dist/tests/localized_plain_data.test.js.map +1 -0
- package/docs/4.data-models.md +1 -1
- package/package.json +1 -1
- package/skills/database-decorators-interface/SKILL.md +1 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as DatabaseDev from "@antelopejs/interface-database";
|
|
2
|
-
import { type Constructible } from "../common";
|
|
2
|
+
import { type Constructible, type PlainData } from "../common";
|
|
3
3
|
import { ContainerModifier, MixinSymbol } from "./common";
|
|
4
4
|
type Options = {
|
|
5
5
|
/**
|
|
@@ -52,6 +52,16 @@ export declare class LocalizationModifier extends ContainerModifier<Record<strin
|
|
|
52
52
|
* field without a fallback value reads `null`, as an unset field does.
|
|
53
53
|
*/
|
|
54
54
|
unlock(locked_value: Record<string, unknown>, key: string | undefined): unknown;
|
|
55
|
+
/**
|
|
56
|
+
* Reads a field that plain data gives as a plain object as its values by
|
|
57
|
+
* locale, as `PlainData` types it, whatever locale the row is read with
|
|
58
|
+
* afterwards. A field with a modifier inside its locales, such as
|
|
59
|
+
* `@Localized() @Encrypted()`, keeps the value for the next locale selected:
|
|
60
|
+
* that modifier transforms the value before the locales are set.
|
|
61
|
+
*/
|
|
62
|
+
fromPlainData<T extends {
|
|
63
|
+
constructor: any;
|
|
64
|
+
}>(object: T, field: Extract<keyof T, string>, raw: PlainData<T>): void;
|
|
55
65
|
unlockrequest(data: DatabaseDev.ValueProxy<Record<string, unknown>>, meta: DatabaseDev.ValueProxy<Record<string, never>>, key: DatabaseDev.ValueProxyOrValue<string | undefined>): DatabaseDev.ValueProxy<unknown>;
|
|
56
66
|
[MixinSymbol]: {
|
|
57
67
|
new (): {
|
|
@@ -3,12 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Localized = exports.LocalizationModifier = void 0;
|
|
4
4
|
const decorators_1 = require("@antelopejs/interface-core/decorators");
|
|
5
5
|
const common_1 = require("../common");
|
|
6
|
+
const kinds_1 = require("./internal/kinds");
|
|
6
7
|
const common_2 = require("./common");
|
|
7
8
|
/** A text left empty in one language counts as no text in that language. */
|
|
8
9
|
const EMPTY_TEXT = "";
|
|
9
10
|
function withoutEmptyTexts(values) {
|
|
10
11
|
return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== EMPTY_TEXT));
|
|
11
12
|
}
|
|
13
|
+
/** Whether `value` is an object literal, not an array, a date or a class instance. */
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
if (!(0, kinds_1.isRecord)(value))
|
|
16
|
+
return false;
|
|
17
|
+
const prototype = Object.getPrototypeOf(value);
|
|
18
|
+
return prototype === Object.prototype || prototype === null;
|
|
19
|
+
}
|
|
12
20
|
/**
|
|
13
21
|
* Localization modifier. enables the use of {@link Localized} on table fields.
|
|
14
22
|
*
|
|
@@ -60,6 +68,21 @@ class LocalizationModifier extends common_2.ContainerModifier {
|
|
|
60
68
|
: undefined;
|
|
61
69
|
return key === undefined ? (fallback ?? null) : fallback;
|
|
62
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Reads a field that plain data gives as a plain object as its values by
|
|
73
|
+
* locale, as `PlainData` types it, whatever locale the row is read with
|
|
74
|
+
* afterwards. A field with a modifier inside its locales, such as
|
|
75
|
+
* `@Localized() @Encrypted()`, keeps the value for the next locale selected:
|
|
76
|
+
* that modifier transforms the value before the locales are set.
|
|
77
|
+
*/
|
|
78
|
+
fromPlainData(object, field, raw) {
|
|
79
|
+
const modifiers = (0, common_1.getMetadata)(object.constructor, common_2.ModifiersStaticMetadata)
|
|
80
|
+
.fields[field];
|
|
81
|
+
if (modifiers?.at(-1)?.id === LocalizationModifier.name &&
|
|
82
|
+
isPlainObject(raw[field])) {
|
|
83
|
+
(0, common_2.unlock)(object, LocalizationModifier, [field], "*");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
63
86
|
unlockrequest(
|
|
64
87
|
// oxlint-disable-next-line anti-slop/no-unsafe-dictionary-type -- the container modifier leaves the values by locale untyped
|
|
65
88
|
data, meta, key) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/modifiers/localization.ts"],"names":[],"mappings":";;;AACA,sEAA8E;AAE9E,
|
|
1
|
+
{"version":3,"file":"localization.js","sourceRoot":"","sources":["../../src/modifiers/localization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const chai_1 = require("chai");
|
|
13
|
+
const interface_database_1 = require("@antelopejs/interface-database");
|
|
14
|
+
const schema_1 = require("../schema");
|
|
15
|
+
const database_1 = require("../database");
|
|
16
|
+
const model_1 = require("../model");
|
|
17
|
+
const table_1 = require("../table");
|
|
18
|
+
const encryption_1 = require("../modifiers/encryption");
|
|
19
|
+
const localization_1 = require("../modifiers/localization");
|
|
20
|
+
const records_1 = require("../modifiers/internal/records");
|
|
21
|
+
describe("Localized fields - plain data with values by locale", () => {
|
|
22
|
+
let Role = class Role extends table_1.Table.with(localization_1.LocalizationModifier, encryption_1.EncryptionModifier) {
|
|
23
|
+
};
|
|
24
|
+
__decorate([
|
|
25
|
+
(0, localization_1.Localized)(),
|
|
26
|
+
__metadata("design:type", String)
|
|
27
|
+
], Role.prototype, "displayName", void 0);
|
|
28
|
+
__decorate([
|
|
29
|
+
(0, localization_1.Localized)(),
|
|
30
|
+
__metadata("design:type", Object)
|
|
31
|
+
], Role.prototype, "tooltip", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, localization_1.Localized)(),
|
|
34
|
+
(0, encryption_1.Encrypted)({ secretKey: "12345678901234567890123456789012" }),
|
|
35
|
+
__metadata("design:type", Object)
|
|
36
|
+
], Role.prototype, "note", void 0);
|
|
37
|
+
Role = __decorate([
|
|
38
|
+
(0, schema_1.RegisterTable)("roles", "localized-plain-data-schema")
|
|
39
|
+
], Role);
|
|
40
|
+
const RoleModel = (0, model_1.BasicDataModel)(Role, "roles");
|
|
41
|
+
const wording = { en: "Members", fr: "Membres" };
|
|
42
|
+
async function model() {
|
|
43
|
+
await (0, database_1.RegisterSchema)("localized-plain-data-schema");
|
|
44
|
+
const instance = interface_database_1.Schema.get("localized-plain-data-schema")?.instance();
|
|
45
|
+
if (!instance)
|
|
46
|
+
throw new Error("Database not found");
|
|
47
|
+
return new RoleModel(instance);
|
|
48
|
+
}
|
|
49
|
+
async function stored(row) {
|
|
50
|
+
const roles = await model();
|
|
51
|
+
row._id = "role-1";
|
|
52
|
+
await roles.insert(row);
|
|
53
|
+
const read = await roles.get("role-1");
|
|
54
|
+
if (!read)
|
|
55
|
+
throw new Error("Row not stored");
|
|
56
|
+
return read;
|
|
57
|
+
}
|
|
58
|
+
afterEach(async () => {
|
|
59
|
+
await interface_database_1.Schema.get("localized-plain-data-schema")
|
|
60
|
+
?.instance()
|
|
61
|
+
.table("roles")
|
|
62
|
+
.delete()
|
|
63
|
+
.run();
|
|
64
|
+
});
|
|
65
|
+
it("stores every locale of a record read under one locale", async () => {
|
|
66
|
+
const read = await stored(RoleModel.fromPlainData({ displayName: wording }).localize("en"));
|
|
67
|
+
(0, chai_1.expect)((0, records_1.getInternal)(read).data.displayName).to.deep.equal(wording);
|
|
68
|
+
(0, chai_1.expect)(read.localize("en").displayName).to.equal("Members");
|
|
69
|
+
});
|
|
70
|
+
it("stores every locale of a record read with no locale", async () => {
|
|
71
|
+
const read = await stored(RoleModel.fromPlainData({ displayName: wording }));
|
|
72
|
+
(0, chai_1.expect)((0, records_1.getInternal)(read).data.displayName).to.deep.equal(wording);
|
|
73
|
+
});
|
|
74
|
+
it("stores a plain value under the locale it is read with", async () => {
|
|
75
|
+
const read = await stored(RoleModel.fromPlainData({ displayName: "Members" }).localize("en"));
|
|
76
|
+
(0, chai_1.expect)((0, records_1.getInternal)(read).data.displayName).to.deep.equal({ en: "Members" });
|
|
77
|
+
});
|
|
78
|
+
it("stores a null value under the locale it is read with", async () => {
|
|
79
|
+
const read = await stored(RoleModel.fromPlainData({ displayName: wording, tooltip: null }).localize("en"));
|
|
80
|
+
(0, chai_1.expect)((0, records_1.getInternal)(read).data.tooltip).to.deep.equal({ en: null });
|
|
81
|
+
});
|
|
82
|
+
it("stores no record for a field encrypted inside its locales", async () => {
|
|
83
|
+
const read = await stored(RoleModel.fromPlainData({ note: wording }));
|
|
84
|
+
(0, chai_1.expect)((0, records_1.getInternal)(read).data.note).to.equal(undefined);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=localized_plain_data.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localized_plain_data.test.js","sourceRoot":"","sources":["../../src/tests/localized_plain_data.test.ts"],"names":[],"mappings":"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"}
|
package/docs/4.data-models.md
CHANGED
|
@@ -129,7 +129,7 @@ const user = UserModel.fromPlainData({
|
|
|
129
129
|
});
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
The object is a `PlainData<T>`. Every field is optional and may be partial, and a field under a container modifier may hold its value per key, as a localized field holds one text per locale. `toPlainData` gives the reverse form, a `PlainRow<T>`.
|
|
132
|
+
The object is a `PlainData<T>`. Every field is optional and may be partial, and a field under a container modifier may hold its value per key, as a localized field holds one text per locale. A plain object given for a localized field is read as its texts by locale, so every locale is stored, whatever `localize()` call follows. A single text is stored under the locale that a later `localize()` call selects. A field with another modifier inside its locales, such as `@Localized() @Encrypted()`, does not read a plain object this way. `toPlainData` gives the reverse form, a `PlainRow<T>`.
|
|
133
133
|
|
|
134
134
|
### `fromDatabase(obj)`
|
|
135
135
|
|
package/package.json
CHANGED
|
@@ -130,6 +130,7 @@ class Chef extends Table.with(
|
|
|
130
130
|
- `@Hashed({ algorithm })` stores a fast digest instead of scrypt: use it only for non-secret fingerprints, never for credentials.
|
|
131
131
|
- Localized fields must be written through a localized instance (`instance.localize(locale).field = ...`);
|
|
132
132
|
values assigned before `localize()` are held in floating state and silently dropped on insert/update.
|
|
133
|
+
- In plain data, a plain object given for a localized field is its texts by locale: `fromPlainData` and `insert` store every locale, whatever `localize()` call follows, and `update` replaces the stored texts with that record. A single text still waits for a locale. A field with another modifier inside its locales, such as `@Localized() @Encrypted()`, does not read a record this way.
|
|
133
134
|
- `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.
|
|
134
135
|
- 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.
|
|
135
136
|
- A localized value `""` is stored as no value: reads and queries in that locale get the `fallbackLocale` value.
|