letopis 1.4.1 → 2.0.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.
- package/AGENT-CHEATSHEET.md +329 -278
- package/CHANGELOG.md +558 -1
- package/README.md +606 -1037
- package/dist/acl.d.ts +78 -1
- package/dist/acl.js +264 -13
- package/dist/admin.d.ts +10 -141
- package/dist/admin.js +24 -175
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +5 -15
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +33 -10
- package/dist/chain.d.ts +19 -41
- package/dist/chain.js +169 -201
- package/dist/cli.js +51 -88
- package/dist/demo/booking.d.ts +352 -36
- package/dist/describe.d.ts +47 -0
- package/dist/describe.js +195 -0
- package/dist/errors.d.ts +59 -13
- package/dist/errors.js +190 -29
- package/dist/index.d.ts +52 -71
- package/dist/index.js +245 -130
- package/dist/internal.d.ts +12 -0
- package/dist/internal.js +5 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +20 -12
- package/dist/load.js +225 -186
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +171 -215
- package/dist/messages/access.d.ts +90 -0
- package/dist/messages/access.js +113 -0
- package/dist/messages/api.d.ts +171 -0
- package/dist/messages/api.js +215 -0
- package/dist/messages/boot.d.ts +201 -0
- package/dist/messages/boot.js +256 -0
- package/dist/messages/codes.d.ts +172 -0
- package/dist/messages/codes.js +173 -0
- package/dist/messages/index.d.ts +95 -0
- package/dist/messages/index.js +118 -0
- package/dist/messages/mcp.d.ts +306 -0
- package/dist/messages/mcp.js +387 -0
- package/dist/messages/model.d.ts +233 -0
- package/dist/messages/model.js +283 -0
- package/dist/messages/query.d.ts +131 -0
- package/dist/messages/query.js +158 -0
- package/dist/messages/sql-access.d.ts +70 -0
- package/dist/messages/sql-access.js +87 -0
- package/dist/messages/sql-core.d.ts +150 -0
- package/dist/messages/sql-core.js +181 -0
- package/dist/messages/sql-time.d.ts +71 -0
- package/dist/messages/sql-time.js +88 -0
- package/dist/messages/sql-write.d.ts +246 -0
- package/dist/messages/sql-write.js +270 -0
- package/dist/messages/time.d.ts +23 -0
- package/dist/messages/time.js +29 -0
- package/dist/messages/types.d.ts +27 -0
- package/dist/messages/types.js +5 -0
- package/dist/messages/write.d.ts +405 -0
- package/dist/messages/write.js +509 -0
- package/dist/model.d.ts +73 -60
- package/dist/model.js +26 -29
- package/dist/ops.d.ts +35 -0
- package/dist/ops.js +101 -0
- package/dist/pglite.d.ts +0 -9
- package/dist/pglite.js +3 -1
- package/dist/registry.d.ts +3 -19
- package/dist/registry.js +3 -16
- package/dist/signals.d.ts +5 -9
- package/dist/signals.js +5 -9
- package/dist/sql.d.ts +13 -6
- package/dist/sql.js +176 -83
- package/dist/sync.d.ts +9 -3
- package/dist/sync.js +51 -21
- package/dist/tx.d.ts +26 -1
- package/dist/tx.js +44 -14
- package/dist/typed.d.ts +240 -45
- package/dist/types.d.ts +23 -91
- package/dist/types.js +12 -14
- package/dist/up.d.ts +53 -32
- package/dist/up.js +184 -73
- package/dist/uuid.js +5 -5
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +61 -29
- package/dist/watch.d.ts +11 -10
- package/dist/watch.js +33 -70
- package/dist/write.d.ts +9 -16
- package/dist/write.js +118 -187
- package/llms.txt +22 -25
- package/package.json +8 -11
- package/sql/10-core.sql +7 -50
- package/sql/15-errors.sql +64 -10
- package/sql/20-context.sql +7 -6
- package/sql/30-validate.sql +35 -27
- package/sql/40-class.sql +20 -114
- package/sql/50-acl.sql +8 -13
- package/sql/60-write.sql +220 -667
- package/sql/70-read.sql +20 -16
- package/sql/80-auth.sql +24 -27
- package/sql/90-time.sql +70 -859
- package/sql/95-seed.system.sql +7 -14
- package/sql/99-revision.sql +2 -1
- package/sql/README.md +32 -24
- package/sql/migrate/README.md +14 -0
- package/AGENT-CHEATSHEET.en.md +0 -485
- package/MIGRATION.md +0 -190
- package/README.en.md +0 -2859
- package/dist/import.d.ts +0 -185
- package/dist/import.js +0 -820
- package/dist/project.d.ts +0 -350
- package/dist/project.js +0 -1224
- package/sql/75-history.sql +0 -358
- package/sql/88-derived.sql +0 -1235
- package/sql/migrate/0006-changed-paths.sql +0 -3
- package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/dist/typed.d.ts
CHANGED
|
@@ -1,35 +1,171 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Строгие типы цепочек по моделям (план 2.0, этап 4, п. 1; типы шагов, строк и фильтров — план 1.0, этап 3, п. 9).
|
|
3
|
+
* `connect({ models })` — модели letopis/model — или `connect<Models>()` — объявления `letopis types` (generateTypes,
|
|
4
|
+
* sync.ts) — дают TypedDb без индексных сигнатур:
|
|
5
|
+
* - шаг от корня — только известный класс или алиас: моделей подключения и системных (встроенный набор SystemModels);
|
|
6
|
+
* - переходы цепочки выводятся из концов, как в resolveHop (lib/src/sql.ts): от класса C — роли его семейства (C и
|
|
7
|
+
* потомков) и классы, связанные с семейством C концом в любую сторону (роль, имя которой совпало с именем класса,
|
|
8
|
+
* во время выполнения — шаг класса, так же и здесь);
|
|
9
|
+
* - слоты — только роли класса C: `set(id | строка | цепочка)`, `add` и `remove` — у множественного конца, `unset` —
|
|
10
|
+
* у необязательного;
|
|
11
|
+
* - поля фильтров, `or()` и агрегатов `sum`, `avg`, `min`, `max`, `countBy` — поля класса.
|
|
12
|
+
* Чего типы не знают: возврат к узлу связи из пути (pivot) от класса, с которым связь не связана концом, и роль чужого
|
|
13
|
+
* класса шагом. Это и имена, известные только во время выполнения, — через loose(db) (index.ts): проверки во время
|
|
14
|
+
* выполнения те же. db.as(), db.begin(), db.batch() и entity() отдают цепочки без строгих типов (Db, Batch, Chain).
|
|
15
|
+
* Модель описана структурно (ModelLike), поэтому основная точка входа не зависит от Zod.
|
|
6
16
|
*/
|
|
7
|
-
import type { ChainCore,
|
|
8
|
-
import type { Cursor, Op, Path, Row, Scalar } from './types.js';
|
|
17
|
+
import type { ChainCore, ChainRef } from './chain.js';
|
|
18
|
+
import type { Cursor, Op, OP, Path, Row, Scalar } from './types.js';
|
|
9
19
|
import type { IncMarker } from './write.js';
|
|
10
|
-
/**
|
|
11
|
-
|
|
20
|
+
/**
|
|
21
|
+
* То, что цепочкам нужно от модели: имя, алиас и типы для вывода — данные строки, концы строки, концы класса (роль →
|
|
22
|
+
* `{ targets: имена классов целей; many; required }`) и имена класса и его предков. Модели letopis/model и объявления
|
|
23
|
+
* `letopis types` ему соответствуют.
|
|
24
|
+
*/
|
|
25
|
+
export interface ModelLike<N extends string = string, D = unknown, L = unknown, A extends string = string, E = unknown, P extends string = never> {
|
|
12
26
|
readonly name: N;
|
|
13
27
|
readonly alias?: A;
|
|
14
28
|
readonly __types?: {
|
|
15
29
|
data: D;
|
|
16
30
|
links: L;
|
|
31
|
+
ends?: E;
|
|
32
|
+
ancestors?: P;
|
|
17
33
|
};
|
|
18
34
|
}
|
|
19
|
-
export type AnyModelLike = ModelLike<string, any, any, any>;
|
|
20
|
-
|
|
21
|
-
type
|
|
35
|
+
export type AnyModelLike = ModelLike<string, any, any, any, any, any>;
|
|
36
|
+
/** Обязательный одиночный конец на класс T (системные классы). */
|
|
37
|
+
type One<T extends string> = {
|
|
38
|
+
targets: T;
|
|
39
|
+
many: false;
|
|
40
|
+
required: true;
|
|
41
|
+
};
|
|
42
|
+
type NoKeys = Record<never, never>;
|
|
43
|
+
/**
|
|
44
|
+
* Встроенный набор моделей системных классов (lib/sql/95-seed.system.sql): шаги Class, Account, member, Resource, rule
|
|
45
|
+
* есть у любого TypedDb. Модель с тем же именем в `models` (например, из `letopis types --system`) — вместо встроенной.
|
|
46
|
+
*/
|
|
47
|
+
export type SystemModels = readonly [
|
|
48
|
+
ModelLike<'Class', {
|
|
49
|
+
name: string;
|
|
50
|
+
}, NoKeys, never, NoKeys>,
|
|
51
|
+
ModelLike<'Account', {
|
|
52
|
+
name: string;
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
categories?: string[];
|
|
55
|
+
}, NoKeys, never, NoKeys>,
|
|
56
|
+
ModelLike<'member', {
|
|
57
|
+
roles?: string[];
|
|
58
|
+
}, {
|
|
59
|
+
User: string;
|
|
60
|
+
Tenant: string;
|
|
61
|
+
}, never, {
|
|
62
|
+
User: One<'Account'>;
|
|
63
|
+
Tenant: One<'Account'>;
|
|
64
|
+
}>,
|
|
65
|
+
ModelLike<'Resource', {
|
|
66
|
+
alias: string;
|
|
67
|
+
category: 'ACCOUNT' | 'API' | 'READ' | 'WRITE' | 'DELETE';
|
|
68
|
+
pattern?: {
|
|
69
|
+
categories?: string;
|
|
70
|
+
roles?: string;
|
|
71
|
+
endpoint?: string;
|
|
72
|
+
class?: string;
|
|
73
|
+
};
|
|
74
|
+
description?: string;
|
|
75
|
+
}, NoKeys, never, NoKeys>,
|
|
76
|
+
ModelLike<'rule', {
|
|
77
|
+
permission: 'allow' | 'deny';
|
|
78
|
+
weight?: number;
|
|
79
|
+
enabled?: boolean;
|
|
80
|
+
code?: number;
|
|
81
|
+
message?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
}, {
|
|
84
|
+
Group: string;
|
|
85
|
+
Object: string;
|
|
86
|
+
}, never, {
|
|
87
|
+
Group: One<'Resource'>;
|
|
88
|
+
Object: One<'Resource'>;
|
|
89
|
+
}>
|
|
90
|
+
];
|
|
91
|
+
type NameOf<K> = K extends {
|
|
92
|
+
readonly name: infer N extends string;
|
|
93
|
+
} ? N : never;
|
|
94
|
+
/** Алиас модели; нет алиаса (или он не литерал) — never. */
|
|
95
|
+
type AliasOf<K> = K extends {
|
|
96
|
+
readonly alias?: infer A;
|
|
97
|
+
} ? (A extends string ? (string extends A ? never : A) : never) : never;
|
|
98
|
+
/** Имена, которыми модель вызывается шагом: имя и алиас. */
|
|
99
|
+
type StepNames<K> = NameOf<K> | AliasOf<K>;
|
|
100
|
+
type TypesOf<K> = K extends {
|
|
101
|
+
readonly __types?: infer T;
|
|
102
|
+
} ? NonNullable<T> : NoKeys;
|
|
103
|
+
/** Данные строки класса C (интерфейсы `letopis types` — тоже: индексная сигнатура не требуется). */
|
|
104
|
+
type DataOf<C> = C extends unknown ? (TypesOf<C> extends {
|
|
105
|
+
data: infer D;
|
|
106
|
+
} ? (D extends object ? D : Record<string, unknown>) : Record<string, unknown>) : never;
|
|
107
|
+
type LinksOf<C> = C extends unknown ? (TypesOf<C> extends {
|
|
108
|
+
links: infer L;
|
|
109
|
+
} ? (L extends object ? L : Record<string, string>) : Record<string, string>) : never;
|
|
110
|
+
/** Концы класса C: роль → { targets, many, required }; модель без них — без концов. */
|
|
111
|
+
type EndsOf<C> = C extends unknown ? (TypesOf<C> extends {
|
|
112
|
+
ends?: infer E;
|
|
113
|
+
} ? EndsOrNone<NonNullable<E>> : NoKeys) : never;
|
|
114
|
+
type EndsOrNone<E> = [E] extends [object] ? E : NoKeys;
|
|
115
|
+
/** Имя класса и его предков (ancestors реестра). */
|
|
116
|
+
type AncestorsOf<K> = K extends unknown ? NameOf<K> | (TypesOf<K> extends {
|
|
117
|
+
ancestors?: infer P;
|
|
118
|
+
} ? Extract<P, string> : never) : never;
|
|
119
|
+
type EndTargets<S> = S extends {
|
|
120
|
+
targets: infer T;
|
|
121
|
+
} ? Extract<T, string> : never;
|
|
122
|
+
/** Классы целей всех концов модели. */
|
|
123
|
+
type TargetsOf<K> = K extends unknown ? {
|
|
124
|
+
[R in keyof EndsOf<K>]: EndTargets<EndsOf<K>[R]>;
|
|
125
|
+
}[keyof EndsOf<K>] : never;
|
|
126
|
+
/** Роли модели. */
|
|
127
|
+
type RolesOf<K> = K extends unknown ? Extract<keyof EndsOf<K>, string> : never;
|
|
128
|
+
/** Модели подключения и встроенные системные (своя модель системного класса — вместо встроенной). */
|
|
129
|
+
type AllOf<M extends readonly AnyModelLike[]> = M[number] | Exclude<SystemModels[number], {
|
|
130
|
+
readonly name: NameOf<M[number]>;
|
|
131
|
+
}>;
|
|
132
|
+
/** Семейство класса C: сам класс и потомки (reg.family). */
|
|
133
|
+
type FamilyOf<C, All> = C extends unknown ? C | DescendantsOf<NameOf<C>, All> : never;
|
|
134
|
+
type DescendantsOf<N, All> = All extends unknown ? (N extends AncestorsOf<All> ? All : never) : never;
|
|
135
|
+
type FamTargets<C, All> = TargetsOf<FamilyOf<C, All>>;
|
|
136
|
+
type FamAncestors<C, All> = AncestorsOf<FamilyOf<C, All>>;
|
|
137
|
+
/**
|
|
138
|
+
* Связаны ли классы C и X концом: роль семейства C принимает класс семейства X (вперёд) или роль семейства X — класс
|
|
139
|
+
* семейства C (назад); конец принимает класс и его потомков (accepts).
|
|
140
|
+
*/
|
|
141
|
+
type Linked<C, X, All> = [FamTargets<C, All> & FamAncestors<X, All>] extends [never] ? ([FamTargets<X, All> & FamAncestors<C, All>] extends [never] ? false : true) : true;
|
|
142
|
+
/** Классы, в которые ведёт шаг от C. */
|
|
143
|
+
type HopClasses<C, All> = HopClassesOf<C, All, All>;
|
|
144
|
+
type HopClassesOf<C, X, All> = X extends unknown ? (Linked<C, X, All> extends true ? X : never) : never;
|
|
145
|
+
/** Модель по имени или алиасу шага. */
|
|
146
|
+
type ByStepName<P, U> = U extends unknown ? (P extends StepNames<U> ? U : never) : never;
|
|
147
|
+
/** Классы целей роли R: имя роли однозначно во всей схеме (проверяет база). */
|
|
148
|
+
type RoleTargets<R, All> = All extends unknown ? (R extends RolesOf<All> ? EndTargets<EndsOf<All>[R & keyof EndsOf<All>]> : never) : never;
|
|
149
|
+
/** Модели классов T; класса нет среди моделей — только имя (строки без типов данных). */
|
|
150
|
+
type ModelsNamed<T, All> = (All extends unknown ? (NameOf<All> extends T ? All : never) : never) | BareOf<Exclude<T, NameOf<All>>>;
|
|
151
|
+
type BareOf<T> = T extends string ? {
|
|
152
|
+
readonly name: T;
|
|
153
|
+
} : never;
|
|
154
|
+
/**
|
|
155
|
+
* Анонимный тип объекта вместо интерфейса: у интерфейса (`<Класс>Data` из `letopis types`) нет неявной индексной
|
|
156
|
+
* сигнатуры, и без этого его строка не подошла бы туда, где ждут `Row` (`entity()`, `cursorOf()`).
|
|
157
|
+
*/
|
|
158
|
+
type Plain<T> = {
|
|
159
|
+
[K in keyof T]: T[K];
|
|
160
|
+
};
|
|
22
161
|
/** Строка ответа класса C. */
|
|
23
|
-
export type RowOf<C> = Row<DataOf<C
|
|
162
|
+
export type RowOf<C> = C extends unknown ? Row<Plain<DataOf<C>>, Plain<LinksOf<C>>> : never;
|
|
24
163
|
/** Фильтр по значению поля: равенство, оператор, вложенный объект любой глубины. */
|
|
25
164
|
export type FieldFilterOf<T> = Op | (T extends readonly unknown[] ? T : T extends Record<string, unknown> ? {
|
|
26
165
|
[P in keyof T]?: FieldFilterOf<T[P]>;
|
|
27
166
|
} : T extends Scalar ? T | null : never);
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
id: string;
|
|
31
|
-
class: string;
|
|
32
|
-
} | ({
|
|
167
|
+
/** Фильтр-объект класса C: поля данных, роли концов и id. */
|
|
168
|
+
type ObjectFilterOf<C> = C extends unknown ? {
|
|
33
169
|
[P in keyof DataOf<C>]?: FieldFilterOf<DataOf<C>[P]>;
|
|
34
170
|
} & {
|
|
35
171
|
[R in keyof LinksOf<C>]?: string | {
|
|
@@ -37,26 +173,98 @@ export type FilterOf<C> = string | string[] | Op | {
|
|
|
37
173
|
} | null;
|
|
38
174
|
} & {
|
|
39
175
|
id?: string | string[];
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
176
|
+
} : never;
|
|
177
|
+
/**
|
|
178
|
+
* Результат `or(…)` (index.ts): оператор `or` и фильтры, которыми он типизирован; `F` — только для типов. В шаге класса C
|
|
179
|
+
* фильтры внутри `or()` — фильтры-объекты класса C.
|
|
180
|
+
*/
|
|
181
|
+
export type OrOp<F = Record<string, unknown>> = Op & {
|
|
182
|
+
readonly [K in typeof OP]: 'or';
|
|
44
183
|
} & {
|
|
45
|
-
|
|
184
|
+
readonly __filters?: F;
|
|
46
185
|
};
|
|
186
|
+
/** Фильтр шага класса C: id, список id, строка ответа, or(…) из фильтров класса или объект полей и ролей. */
|
|
187
|
+
export type FilterOf<C> = string | string[] | {
|
|
188
|
+
id: string;
|
|
189
|
+
class: string;
|
|
190
|
+
} | OrOp<ObjectFilterOf<C>> | ObjectFilterOf<C>;
|
|
47
191
|
/** Патч update: поля любой глубины необязательны; inc() — только у числовых полей (§2.5). */
|
|
48
192
|
export type PatchOf<T> = {
|
|
49
193
|
[P in keyof T]?: T[P] extends number | undefined ? T[P] | IncMarker : T[P] extends readonly unknown[] | undefined ? T[P] : T[P] extends Record<string, unknown> | undefined ? PatchOf<NonNullable<T[P]>> : T[P];
|
|
50
194
|
};
|
|
51
|
-
|
|
52
|
-
|
|
195
|
+
/** Счётчик глубины путей полей. */
|
|
196
|
+
type Depth = [never, 0, 1, 2, 3, 4, 5];
|
|
197
|
+
/** Пути полей данных через точку — без элементов массивов. */
|
|
198
|
+
type FieldPaths<T, D extends number = 6> = [D] extends [never] ? never : T extends readonly unknown[] ? never : T extends object ? {
|
|
199
|
+
[K in keyof T & string]-?: K | `${K}.${FieldPaths<NonNullable<T[K]>, Depth[D]>}`;
|
|
200
|
+
}[keyof T & string] : never;
|
|
201
|
+
/** Пути числовых полей (и полей без типа). */
|
|
202
|
+
type NumberPaths<T, D extends number = 6> = [D] extends [never] ? never : T extends readonly unknown[] ? never : T extends object ? {
|
|
203
|
+
[K in keyof T & string]-?: (unknown extends T[K] ? K : NonNullable<T[K]> extends number ? K : never) | `${K}.${NumberPaths<NonNullable<T[K]>, Depth[D]>}`;
|
|
204
|
+
}[keyof T & string] : never;
|
|
205
|
+
/** Поле агрегата класса C: `'data.<путь>'`. */
|
|
206
|
+
type DataField<C> = `data.${FieldPaths<DataOf<C>>}`;
|
|
207
|
+
/** Числовое поле агрегата класса C (sum, avg). */
|
|
208
|
+
type NumberField<C> = `data.${NumberPaths<DataOf<C>>}`;
|
|
209
|
+
/** Шаг класса C: фильтр класса и цепочка с ним. */
|
|
210
|
+
type StepFnOf<C, M extends readonly AnyModelLike[]> = (filter?: FilterOf<C>) => TypedChain<C, M>;
|
|
211
|
+
/** Шаги корня: имена и алиасы моделей подключения и системных классов. */
|
|
212
|
+
export type StepsOf<M extends readonly AnyModelLike[]> = {
|
|
213
|
+
[K in AllOf<M> as NameOf<K>]: StepFnOf<K, M>;
|
|
214
|
+
} & {
|
|
215
|
+
[K in AllOf<M> as AliasOf<K>]: StepFnOf<K, M>;
|
|
216
|
+
};
|
|
217
|
+
/** Значение слота одиночного конца: id, строка ответа или цепочка. */
|
|
218
|
+
type SlotOne = string | {
|
|
219
|
+
readonly id: string;
|
|
220
|
+
} | ChainRef;
|
|
221
|
+
/** Значение слота множественного конца: ещё и список id или строк. */
|
|
222
|
+
type SlotMany = SlotOne | readonly (string | {
|
|
223
|
+
readonly id: string;
|
|
224
|
+
})[];
|
|
225
|
+
/** Слоты роли с концом S записываемой строки класса C. */
|
|
226
|
+
type SlotFns<S, C, M extends readonly AnyModelLike[]> = {
|
|
227
|
+
set(value: S extends {
|
|
228
|
+
many: true;
|
|
229
|
+
} ? SlotMany : SlotOne): TypedChain<C, M>;
|
|
230
|
+
} & (S extends {
|
|
231
|
+
many: false;
|
|
232
|
+
} ? unknown : {
|
|
233
|
+
add(value: SlotMany): TypedChain<C, M>;
|
|
234
|
+
remove(value: SlotMany): TypedChain<C, M>;
|
|
235
|
+
}) & (S extends {
|
|
236
|
+
required: true;
|
|
237
|
+
} ? unknown : {
|
|
238
|
+
unset(): TypedChain<C, M>;
|
|
239
|
+
});
|
|
240
|
+
/** Шаг от C по имени P: класс или алиас, связанный с C, или роль семейства C (имя роли, совпавшее с классом, — шаг класса). */
|
|
241
|
+
type HopStep<C, P, M extends readonly AnyModelLike[], All> = P extends StepNames<All> ? ([ByStepName<P, HopClasses<C, All>>] extends [never] ? unknown : StepFnOf<ByStepName<P, HopClasses<C, All>>, M>) : P extends RolesOf<FamilyOf<C, All>> ? StepFnOf<ModelsNamed<RoleTargets<P, All>, All>, M> : unknown;
|
|
242
|
+
/** Слоты имени P: только роль самого класса C. */
|
|
243
|
+
type HopSlots<C, P, M extends readonly AnyModelLike[]> = P extends keyof EndsOf<C> ? SlotFns<EndsOf<C>[P], C, M> : unknown;
|
|
244
|
+
/** Свойства-шаги цепочки класса C. */
|
|
245
|
+
type HopsOf<C, M extends readonly AnyModelLike[], All = AllOf<M>> = {
|
|
246
|
+
[P in StepNames<HopClasses<C, All>> | Exclude<RolesOf<FamilyOf<C, All>>, StepNames<All>> | Extract<keyof EndsOf<C>, string>]: HopStep<C, P, M, All> & HopSlots<C, P, M>;
|
|
247
|
+
};
|
|
248
|
+
type Retyped = 'paths' | 'rows' | 'first' | 'versions' | 'limit' | 'offset' | 'sort' | 'asOf' | 'after' | 'withDeleted' | 'deep' | 'exact' | 'alias' | 'tags' | 'owner' | 'create' | 'update' | 'upsert' | 'delete' | 'forUpdate' | 'restore' | 'cache' | 'sum' | 'avg' | 'min' | 'max' | 'countBy';
|
|
249
|
+
/**
|
|
250
|
+
* Цепочка с текущим классом C (у шага-роли с несколькими целями — их союз): терминалы отдают RowOf<C>, шаги — переходы
|
|
251
|
+
* из концов, слоты — роли C, агрегаты — поля C.
|
|
252
|
+
*/
|
|
53
253
|
export type TypedChain<C, M extends readonly AnyModelLike[]> = Omit<ChainCore, Retyped> & {
|
|
54
254
|
paths(): Promise<Path[]>;
|
|
55
255
|
rows(): Promise<RowOf<C>[]>;
|
|
56
256
|
first(): Promise<RowOf<C> | null>;
|
|
57
|
-
versions(
|
|
58
|
-
|
|
59
|
-
|
|
257
|
+
versions(): Promise<RowOf<C>[]>;
|
|
258
|
+
/** Сумма числового поля `'data.<путь>'` класса; нет ни одного значения — `null`. */
|
|
259
|
+
sum(field: NumberField<C>): Promise<number | null>;
|
|
260
|
+
/** Среднее числового поля `'data.<путь>'` класса; нет ни одного значения — `null`. */
|
|
261
|
+
avg(field: NumberField<C>): Promise<number | null>;
|
|
262
|
+
/** Наименьшее значение поля `'data.<путь>'` класса. */
|
|
263
|
+
min(field: DataField<C>): Promise<unknown>;
|
|
264
|
+
/** Наибольшее значение поля `'data.<путь>'` класса. */
|
|
265
|
+
max(field: DataField<C>): Promise<unknown>;
|
|
266
|
+
/** Сколько объектов с каждым значением поля `'data.<путь>'` класса. */
|
|
267
|
+
countBy(field: DataField<C>): Promise<Record<string, number>>;
|
|
60
268
|
limit(n: number): TypedChain<C, M>;
|
|
61
269
|
offset(n: number): TypedChain<C, M>;
|
|
62
270
|
sort(field: 'at' | 'rev' | 'id' | `data.${string}`, dir?: 'asc' | 'desc' | boolean): TypedChain<C, M>;
|
|
@@ -73,40 +281,27 @@ export type TypedChain<C, M extends readonly AnyModelLike[]> = Omit<ChainCore, R
|
|
|
73
281
|
create(data: Partial<DataOf<C>>, opts?: {
|
|
74
282
|
reason?: string;
|
|
75
283
|
}): TypedChain<C, M>;
|
|
284
|
+
/** Без фильтра, id, `tags()`, `owner()` и `limit()` у шагов — `invalid_query`; правка всех строк — `{ all: true }`. */
|
|
76
285
|
update(patch?: PatchOf<DataOf<C>>, opts?: {
|
|
77
286
|
rev?: number;
|
|
287
|
+
all?: boolean;
|
|
78
288
|
reason?: string;
|
|
79
289
|
}): TypedChain<C, M>;
|
|
80
290
|
upsert(data: Partial<DataOf<C>>, opts?: {
|
|
81
291
|
reason?: string;
|
|
82
292
|
}): TypedChain<C, M>;
|
|
293
|
+
/** С `{ confirm: true }` без фильтра, id, `tags()`, `owner()` и `limit()` у шагов — `invalid_query`; всех — `{ all: true }`. */
|
|
83
294
|
delete(opts?: {
|
|
84
295
|
confirm?: boolean;
|
|
296
|
+
all?: boolean;
|
|
85
297
|
reason?: string;
|
|
86
298
|
}): TypedChain<C, M>;
|
|
87
|
-
anonymize(fields: (keyof DataOf<C> & string)[], opts?: {
|
|
88
|
-
reason?: string;
|
|
89
|
-
}): TypedChain<C, M>;
|
|
90
|
-
reclass(cls: string, data?: Record<string, unknown>, opts?: {
|
|
91
|
-
reason?: string;
|
|
92
|
-
}): TypedChain<unknown, M>;
|
|
93
299
|
forUpdate(): TypedChain<C, M>;
|
|
94
300
|
restore(opts?: {
|
|
95
301
|
reason?: string;
|
|
96
302
|
}): TypedChain<C, M>;
|
|
97
|
-
purge(opts?: {
|
|
98
|
-
confirm?: boolean;
|
|
99
|
-
reason?: string;
|
|
100
|
-
}): TypedChain<C, M>;
|
|
101
|
-
rekey(patch: Partial<DataOf<C>> & Partial<Record<keyof LinksOf<C>, string | {
|
|
102
|
-
id: string;
|
|
103
|
-
}>>, opts?: {
|
|
104
|
-
reason?: string;
|
|
105
|
-
}): TypedChain<C, M>;
|
|
106
303
|
cache(opts?: {
|
|
107
304
|
ttl?: number;
|
|
108
305
|
}): TypedChain<C, M>;
|
|
109
|
-
} &
|
|
110
|
-
[step: string]: StepFn;
|
|
111
|
-
};
|
|
306
|
+
} & HopsOf<C, M>;
|
|
112
307
|
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -3,35 +3,36 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Ревизия схемы, которую знает эта версия пакета, — номер версии SQL-части letopis (таблиц и функций в схеме установки).
|
|
6
|
-
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии `up()` обновляет только с
|
|
7
|
-
* а `connect()` о ней предупреждает.
|
|
6
|
+
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии 2.x `up()` обновляет только с
|
|
7
|
+
* `upgrade: true`, а `connect()` о ней предупреждает.
|
|
8
8
|
*/
|
|
9
|
-
export declare const DDL_REVISION =
|
|
9
|
+
export declare const DDL_REVISION = 8;
|
|
10
10
|
/**
|
|
11
11
|
* Классы, строки которых меняют права и схему: их запись повышает счётчик прав (загрузчик), а сигнал
|
|
12
12
|
* сбрасывает весь кэш результатов и пропуска прав. Тот же список — в триггерах базы (60-write.sql).
|
|
13
13
|
*/
|
|
14
14
|
export declare const ACL_CLASS_NAMES: readonly string[];
|
|
15
15
|
/**
|
|
16
|
-
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then
|
|
17
|
-
*
|
|
16
|
+
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then`. После шага цепочки эти
|
|
17
|
+
* имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
|
|
18
18
|
*/
|
|
19
|
-
export declare const CHAIN_METHODS: readonly ["then", "entity", "paths", "rows", "first", "ids", "count", "limit", "offset", "sort", "asOf", "withDeleted", "deep", "exact", "sum", "avg", "min", "max", "countBy", "after", "versions", "create", "update", "upsert", "set", "unset", "add", "remove", "delete", "
|
|
19
|
+
export declare const CHAIN_METHODS: readonly ["then", "entity", "paths", "rows", "first", "ids", "count", "limit", "offset", "sort", "asOf", "withDeleted", "deep", "exact", "sum", "avg", "min", "max", "countBy", "after", "versions", "create", "update", "upsert", "set", "unset", "add", "remove", "delete", "restore", "alias", "tags", "owner", "forUpdate", "cache"];
|
|
20
20
|
/** Свойства корня db (и транзакции db.begin()). */
|
|
21
|
-
export declare const DB_METHODS: readonly ["as", "begin", "commit", "rollback", "lock", "batch", "watch", "close", "registry", "sql", "load", "
|
|
21
|
+
export declare const DB_METHODS: readonly ["as", "begin", "commit", "rollback", "lock", "batch", "watch", "close", "registry", "sql", "load", "maintain", "auth", "acl", "idOf", "refresh", "transaction", "flushSignals", "schema", "token", "tenant", "cache"];
|
|
22
22
|
/** Свойства батча db.batch(name). */
|
|
23
|
-
export declare const BATCH_METHODS: readonly ["discard", "size"];
|
|
23
|
+
export declare const BATCH_METHODS: readonly ["run", "discard", "size"];
|
|
24
24
|
/**
|
|
25
25
|
* Имена методов цепочки, корня `db` и батча. Там, где имя занято методом, библиотека не ищет его среди классов, и шаг с
|
|
26
|
-
* таким именем до класса не
|
|
27
|
-
*
|
|
26
|
+
* таким именем до класса не дойдёт. Хаб с таким именем отклоняют `hub()`, `syncModels` и база, связь (`link`) — база
|
|
27
|
+
* (`invalid_class`; план 2.0, этап 4, п. 2); хаб, заведённый мимо проверки базы, `up()` оставляет и называет в
|
|
28
|
+
* предупреждении.
|
|
28
29
|
*/
|
|
29
30
|
export declare const RESERVED_CLASS_NAMES: readonly string[];
|
|
30
31
|
/** Строка ответа: текущая версия (или версия журнала для asOf, versions, withDeleted). */
|
|
31
32
|
export interface Row<D = Record<string, unknown>, L = Record<string, string | string[]>> {
|
|
32
33
|
id: string;
|
|
33
34
|
class: string;
|
|
34
|
-
/** Номер версии — для update(patch, { rev })
|
|
35
|
+
/** Номер версии — для update(patch, { rev }). */
|
|
35
36
|
rev: number;
|
|
36
37
|
tenant: string;
|
|
37
38
|
owner: string;
|
|
@@ -42,23 +43,17 @@ export interface Row<D = Record<string, unknown>, L = Record<string, string | st
|
|
|
42
43
|
at: string;
|
|
43
44
|
author: string;
|
|
44
45
|
agent?: string;
|
|
45
|
-
/** Вид операции версии: create, update, delete,
|
|
46
|
+
/** Вид операции версии: create, update, delete, restore, … */
|
|
46
47
|
op: string;
|
|
47
48
|
reason?: string;
|
|
48
|
-
/** Связь со старым или новым id при reclass и rekey. */
|
|
49
|
-
moved?: string;
|
|
50
49
|
/** Надгробие: удалённая сущность (withDeleted) или версия удаления (versions). */
|
|
51
50
|
$deleted?: true;
|
|
52
51
|
/** Глубина узла при deep() (1 — прямой потомок); в превью удаления — уровень каскада (0 — цель). */
|
|
53
52
|
$depth?: number;
|
|
54
|
-
/** Что сделал upsert
|
|
53
|
+
/** Что сделал upsert. */
|
|
55
54
|
$upsert?: 'created' | 'updated' | 'unchanged';
|
|
56
55
|
/** Превью удаления (delete() без confirm): удалится, снимется конец или помешает (restrict). */
|
|
57
56
|
$action?: 'delete' | 'unset' | 'restrict';
|
|
58
|
-
/** purge(): число версий в журнале (превью) или стёртых. */
|
|
59
|
-
$versions?: number;
|
|
60
|
-
/** purge({ confirm: true }): история стёрта. */
|
|
61
|
-
$purged?: true;
|
|
62
57
|
}
|
|
63
58
|
/** Путь paths(): узел на каждый шаг цепочки. */
|
|
64
59
|
export type Path = Record<string, Row>;
|
|
@@ -85,10 +80,17 @@ export type Filter = string | string[] | Op | {
|
|
|
85
80
|
} | {
|
|
86
81
|
[field: string]: FieldFilter | undefined;
|
|
87
82
|
};
|
|
88
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Курсор постраничного вывода для `after()`: значение поля сортировки и id последней строки страницы. Равные по полю
|
|
85
|
+
* строки разводят `rev` (версии в `versions()`) и `path` (id всех узлов пути в `paths()`); `cursorOf` заполняет их сам.
|
|
86
|
+
*/
|
|
89
87
|
export interface Cursor {
|
|
90
88
|
v: string | number | boolean | null;
|
|
91
89
|
id: string;
|
|
90
|
+
/** Номер версии строки: в `versions()` отделяет версии одного объекта с равным полем сортировки. */
|
|
91
|
+
rev?: number;
|
|
92
|
+
/** Узлы пути из `paths()`: ключ узла → id; отделяет пути с общим последним узлом. */
|
|
93
|
+
path?: Record<string, string>;
|
|
92
94
|
}
|
|
93
95
|
/** Модификаторы выборки цепочки. */
|
|
94
96
|
export interface ChainMods {
|
|
@@ -104,24 +106,14 @@ export interface ChainMods {
|
|
|
104
106
|
withDeleted?: boolean;
|
|
105
107
|
/** Чтение с блокировкой строк последнего шага (только в db.begin()). */
|
|
106
108
|
forUpdate?: boolean;
|
|
107
|
-
/** versions({ follow: true }): история и через смену id (reclass, rekey) по колонке moved. */
|
|
108
|
-
follow?: boolean;
|
|
109
109
|
/** Кэш результатов (§2.12): .cache() — срок по умолчанию, .cache({ ttl }) — свой, секунды. */
|
|
110
110
|
cache?: {
|
|
111
111
|
ttl?: number;
|
|
112
112
|
};
|
|
113
|
-
/** Параметры терминалов diff() и blame() (план 1.1, §2.1): номера версий или моменты (ISO). */
|
|
114
|
-
hist?: {
|
|
115
|
-
from?: number | string;
|
|
116
|
-
to?: number | string;
|
|
117
|
-
at?: string;
|
|
118
|
-
follow?: boolean;
|
|
119
|
-
limit?: number;
|
|
120
|
-
};
|
|
121
113
|
}
|
|
122
114
|
/** Событие хука onQuery: один запрос цепочки. */
|
|
123
115
|
export interface QueryEvent {
|
|
124
|
-
mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg'
|
|
116
|
+
mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg';
|
|
125
117
|
/** Классы шагов цепочки. */
|
|
126
118
|
classes: string[];
|
|
127
119
|
ms: number;
|
|
@@ -129,63 +121,3 @@ export interface QueryEvent {
|
|
|
129
121
|
/** ms > slowMs. */
|
|
130
122
|
slow: boolean;
|
|
131
123
|
}
|
|
132
|
-
/** Изменение пути: added — не было, removed — не стало, changed — другое значение. */
|
|
133
|
-
export interface DiffChange {
|
|
134
|
-
/** Путь: первый сегмент — раздел строки (data, links, tags, owner, class). */
|
|
135
|
-
path: string[];
|
|
136
|
-
kind: 'added' | 'removed' | 'changed';
|
|
137
|
-
before?: unknown;
|
|
138
|
-
after?: unknown;
|
|
139
|
-
}
|
|
140
|
-
/** Различия объекта между двумя версиями (diff()). */
|
|
141
|
-
export interface DiffResult {
|
|
142
|
-
id: string;
|
|
143
|
-
class: string | null;
|
|
144
|
-
from: {
|
|
145
|
-
rev: number;
|
|
146
|
-
at: string;
|
|
147
|
-
id?: string;
|
|
148
|
-
} | null;
|
|
149
|
-
to: {
|
|
150
|
-
rev: number;
|
|
151
|
-
at: string;
|
|
152
|
-
id?: string;
|
|
153
|
-
deleted?: true;
|
|
154
|
-
} | null;
|
|
155
|
-
changes: DiffChange[];
|
|
156
|
-
}
|
|
157
|
-
/** Кто и почему последним изменил лист версии (blame()). */
|
|
158
|
-
export interface BlameField {
|
|
159
|
-
path: string[];
|
|
160
|
-
rev: number;
|
|
161
|
-
at: string;
|
|
162
|
-
author: string;
|
|
163
|
-
agent?: string;
|
|
164
|
-
op: string;
|
|
165
|
-
reason?: string;
|
|
166
|
-
/** Другой id (история прошла через смену id при reclass или rekey). */
|
|
167
|
-
id?: string;
|
|
168
|
-
/** false — до найденной версии история неполная: изменение могло быть раньше. */
|
|
169
|
-
exact: boolean;
|
|
170
|
-
}
|
|
171
|
-
/** Поля версии объекта с версиями, которые их изменили (blame()). */
|
|
172
|
-
export interface BlameResult {
|
|
173
|
-
id: string;
|
|
174
|
-
class: string;
|
|
175
|
-
rev: number;
|
|
176
|
-
deleted?: true;
|
|
177
|
-
/** История просмотрена целиком и без пропусков. */
|
|
178
|
-
complete: boolean;
|
|
179
|
-
fields: BlameField[];
|
|
180
|
-
}
|
|
181
|
-
/** diff(): «до» и «после» — номер версии или момент (ISO-строка, Date); follow — через смену id. */
|
|
182
|
-
export interface DiffOptions {
|
|
183
|
-
from?: number | string | Date;
|
|
184
|
-
to?: number | string | Date;
|
|
185
|
-
follow?: boolean;
|
|
186
|
-
}
|
|
187
|
-
/** blame(): версия на момент at (по умолчанию текущая); limit — сколько версий просматривать (1000). */
|
|
188
|
-
export interface BlameOptions {
|
|
189
|
-
at?: string | Date;
|
|
190
|
-
limit?: number;
|
|
191
|
-
}
|
package/dist/types.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Ревизия схемы, которую знает эта версия пакета, — номер версии SQL-части letopis (таблиц и функций в схеме установки).
|
|
6
|
-
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии `up()` обновляет только с
|
|
7
|
-
* а `connect()` о ней предупреждает.
|
|
6
|
+
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии 2.x `up()` обновляет только с
|
|
7
|
+
* `upgrade: true`, а `connect()` о ней предупреждает.
|
|
8
8
|
*/
|
|
9
|
-
export const DDL_REVISION =
|
|
9
|
+
export const DDL_REVISION = 8;
|
|
10
10
|
/**
|
|
11
11
|
* Классы, строки которых меняют права и схему: их запись повышает счётчик прав (загрузчик), а сигнал
|
|
12
12
|
* сбрасывает весь кэш результатов и пропуска прав. Тот же список — в триггерах базы (60-write.sql).
|
|
@@ -16,28 +16,26 @@ export const ACL_CLASS_NAMES = ['rule', 'Resource', 'member', 'Account', 'Class'
|
|
|
16
16
|
// Методы цепочки — единственный источник зарезервированных имён (план, §2.14, этап 3, п. 10)
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
/**
|
|
19
|
-
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then
|
|
20
|
-
*
|
|
19
|
+
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then`. После шага цепочки эти
|
|
20
|
+
* имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
|
|
21
21
|
*/
|
|
22
22
|
export const CHAIN_METHODS = [
|
|
23
23
|
'then', 'entity', 'paths', 'rows', 'first', 'ids', 'count', 'limit', 'offset', 'sort', 'asOf', 'withDeleted',
|
|
24
24
|
'deep', 'exact', 'sum', 'avg', 'min', 'max', 'countBy', 'after', 'versions', 'create', 'update', 'upsert', 'set',
|
|
25
|
-
'unset', 'add', 'remove', 'delete', '
|
|
26
|
-
'forUpdate', 'cache', 'rekey', 'run', 'execute', 'account', 'diff', 'blame',
|
|
25
|
+
'unset', 'add', 'remove', 'delete', 'restore', 'alias', 'tags', 'owner', 'forUpdate', 'cache',
|
|
27
26
|
];
|
|
28
27
|
/** Свойства корня db (и транзакции db.begin()). */
|
|
29
28
|
export const DB_METHODS = [
|
|
30
|
-
'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'registry', 'sql', 'load',
|
|
31
|
-
'maintain', '
|
|
32
|
-
'token', 'tenant', 'reloadSchema', 'accounts', 'credentials', 'resources', 'rules', 'compact',
|
|
33
|
-
'trimHistory', 'rekeyClass', 'cache', 'projector', 'rebuildAggregates',
|
|
29
|
+
'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'registry', 'sql', 'load',
|
|
30
|
+
'maintain', 'auth', 'acl', 'idOf', 'refresh', 'transaction', 'flushSignals', 'schema', 'token', 'tenant', 'cache',
|
|
34
31
|
];
|
|
35
32
|
/** Свойства батча db.batch(name). */
|
|
36
|
-
export const BATCH_METHODS = ['discard', 'size'];
|
|
33
|
+
export const BATCH_METHODS = ['run', 'discard', 'size'];
|
|
37
34
|
/**
|
|
38
35
|
* Имена методов цепочки, корня `db` и батча. Там, где имя занято методом, библиотека не ищет его среди классов, и шаг с
|
|
39
|
-
* таким именем до класса не
|
|
40
|
-
*
|
|
36
|
+
* таким именем до класса не дойдёт. Хаб с таким именем отклоняют `hub()`, `syncModels` и база, связь (`link`) — база
|
|
37
|
+
* (`invalid_class`; план 2.0, этап 4, п. 2); хаб, заведённый мимо проверки базы, `up()` оставляет и называет в
|
|
38
|
+
* предупреждении.
|
|
41
39
|
*/
|
|
42
40
|
export const RESERVED_CLASS_NAMES = [...new Set([...CHAIN_METHODS, ...DB_METHODS, ...BATCH_METHODS])];
|
|
43
41
|
/** Метка операторов фильтра (символ не пересекается с данными). */
|