letopis 0.20.3 → 1.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.en.md +368 -0
- package/AGENT-CHEATSHEET.md +354 -0
- package/CHANGELOG.md +348 -0
- package/MIGRATION.md +190 -0
- package/README.en.md +1937 -0
- package/README.md +1493 -3466
- package/dist/acl.d.ts +26 -50
- package/dist/acl.js +22 -267
- package/dist/admin.d.ts +138 -0
- package/dist/admin.js +170 -0
- package/dist/auth.d.ts +120 -73
- package/dist/auth.js +121 -306
- package/dist/cache.d.ts +73 -0
- package/dist/cache.js +148 -0
- package/dist/chain.d.ts +124 -191
- package/dist/chain.js +369 -551
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +164 -0
- package/dist/demo/booking.d.ts +289 -0
- package/dist/demo/booking.js +159 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.js +70 -0
- package/dist/import.d.ts +179 -0
- package/dist/import.js +792 -0
- package/dist/index.d.ts +172 -26
- package/dist/index.js +304 -178
- package/dist/jsonschema.d.ts +22 -0
- package/dist/jsonschema.js +167 -0
- package/dist/load.d.ts +76 -0
- package/dist/load.js +884 -0
- package/dist/model.d.ts +166 -0
- package/dist/model.js +224 -0
- package/dist/ops.d.ts +7 -6
- package/dist/ops.js +7 -51
- package/dist/pglite.d.ts +22 -0
- package/dist/pglite.js +45 -0
- package/dist/registry.d.ts +57 -0
- package/dist/registry.js +82 -0
- package/dist/sql.d.ts +59 -142
- package/dist/sql.js +568 -654
- package/dist/sync.d.ts +31 -0
- package/dist/sync.js +108 -0
- package/dist/tx.d.ts +129 -8
- package/dist/tx.js +300 -73
- package/dist/typed.d.ts +97 -0
- package/dist/typed.js +1 -0
- package/dist/types.d.ts +71 -250
- package/dist/types.js +27 -108
- package/dist/up.d.ts +140 -47
- package/dist/up.js +339 -267
- package/dist/uuid.d.ts +21 -6
- package/dist/uuid.js +48 -64
- package/dist/validate.d.ts +24 -0
- package/dist/validate.js +251 -0
- package/dist/watch.d.ts +62 -0
- package/dist/watch.js +168 -0
- package/dist/write.d.ts +117 -74
- package/dist/write.js +658 -720
- package/llms.txt +26 -0
- package/package.json +49 -19
- package/sql/10-core.sql +136 -0
- package/sql/15-errors.sql +60 -0
- package/sql/20-context.sql +153 -0
- package/sql/30-validate.sql +423 -0
- package/sql/40-class.sql +259 -0
- package/sql/50-acl.sql +539 -0
- package/sql/60-write.sql +1369 -0
- package/sql/70-read.sql +245 -0
- package/sql/80-auth.sql +827 -0
- package/sql/90-time.sql +957 -0
- package/sql/95-seed.system.sql +178 -0
- package/sql/99-revision.sql +3 -0
- package/sql/README.md +56 -0
- package/sql/seed.booking.sql +39 -112
- package/dist/schema.d.ts +0 -15
- package/dist/schema.js +0 -351
- package/dist/sessions.d.ts +0 -32
- package/dist/sessions.js +0 -114
- package/dist/tables.d.ts +0 -105
- package/dist/tables.js +0 -248
- package/docker/Dockerfile +0 -40
- package/docker/start.sh +0 -18
- package/scripts/check-docs.mjs +0 -375
- package/scripts/gen-api-contract.mjs +0 -226
- package/scripts/gen-types.mjs +0 -350
- package/scripts/release-notes.mjs +0 -76
- package/scripts/schema-sync.mjs +0 -185
- package/sql/ddl.sql +0 -600
- package/sql/seed.auth.sql +0 -73
package/dist/registry.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Реестр классов (план, этап 2, п. 3 и 6): описания из строк `Class` с развёрнутым `resolved`
|
|
3
|
+
* (собственные классы арендатора и системные), поиск по имени и алиасу, предки и потомки,
|
|
4
|
+
* типы листьев для фильтров и валидатор на TypeScript, скомпилированный из того же описания.
|
|
5
|
+
*/
|
|
6
|
+
import { LetopisError } from './errors.js';
|
|
7
|
+
import { compileValidator } from './validate.js';
|
|
8
|
+
export class Registry {
|
|
9
|
+
byName = new Map();
|
|
10
|
+
byAlias = new Map();
|
|
11
|
+
/** Заменить содержимое строками Class (собственные классы арендатора и системные). */
|
|
12
|
+
load(rows) {
|
|
13
|
+
this.byName.clear();
|
|
14
|
+
this.byAlias.clear();
|
|
15
|
+
for (const r of rows) {
|
|
16
|
+
const res = r.data.resolved;
|
|
17
|
+
let compiled = null;
|
|
18
|
+
const info = {
|
|
19
|
+
name: res.name,
|
|
20
|
+
tenant: r.tenant,
|
|
21
|
+
rev: r.rev,
|
|
22
|
+
kind: res.kind,
|
|
23
|
+
alias: r.data.alias,
|
|
24
|
+
abstract: Boolean(res.abstract),
|
|
25
|
+
ancestors: res.ancestors,
|
|
26
|
+
schema: res.schema,
|
|
27
|
+
ends: (res.ends ?? {}),
|
|
28
|
+
key: (res.key ?? []),
|
|
29
|
+
history: res.history,
|
|
30
|
+
ownerDefault: (res.ownerDefault ?? 'tenant'),
|
|
31
|
+
cache: (res.cache ?? undefined),
|
|
32
|
+
meta: (res.meta ?? {}),
|
|
33
|
+
validator: () => (compiled ??= compileValidator(res.schema)),
|
|
34
|
+
};
|
|
35
|
+
this.byName.set(info.name, info);
|
|
36
|
+
if (info.alias)
|
|
37
|
+
this.byAlias.set(info.alias, info.name);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
has(name) {
|
|
41
|
+
return this.byName.has(name) || this.byAlias.has(name);
|
|
42
|
+
}
|
|
43
|
+
find(name) {
|
|
44
|
+
return this.byName.get(name) ?? this.byName.get(this.byAlias.get(name) ?? '');
|
|
45
|
+
}
|
|
46
|
+
resolve(name) {
|
|
47
|
+
const c = this.find(name);
|
|
48
|
+
if (!c)
|
|
49
|
+
throw new LetopisError('invalid_class', `класс ${name} не найден`);
|
|
50
|
+
return c;
|
|
51
|
+
}
|
|
52
|
+
all() {
|
|
53
|
+
return [...this.byName.values()];
|
|
54
|
+
}
|
|
55
|
+
/** Класс и все его потомки (семейство). */
|
|
56
|
+
family(name) {
|
|
57
|
+
const root = this.resolve(name).name;
|
|
58
|
+
return this.all().filter((c) => c.ancestors.includes(root));
|
|
59
|
+
}
|
|
60
|
+
/** Тип листа по пути полей класса: по JSON Schema (type и format). */
|
|
61
|
+
leafType(cls, path) {
|
|
62
|
+
let node = this.resolve(cls).schema;
|
|
63
|
+
for (const p of path) {
|
|
64
|
+
const props = node?.properties;
|
|
65
|
+
const next = props?.[p] ?? (typeof node?.additionalProperties === 'object' ? node.additionalProperties : undefined);
|
|
66
|
+
if (!next)
|
|
67
|
+
return 'jsonb';
|
|
68
|
+
node = next;
|
|
69
|
+
}
|
|
70
|
+
const types = Array.isArray(node?.type) ? node.type.filter((t) => t !== 'null') : [node?.type];
|
|
71
|
+
if (types.length !== 1)
|
|
72
|
+
return 'jsonb';
|
|
73
|
+
switch (types[0]) {
|
|
74
|
+
case 'integer':
|
|
75
|
+
case 'number': return 'numeric';
|
|
76
|
+
case 'boolean': return 'boolean';
|
|
77
|
+
case 'string':
|
|
78
|
+
return node?.format === 'date-time' ? 'timestamptz' : node?.format === 'date' ? 'date' : node?.format === 'uuid' ? 'uuid' : 'text';
|
|
79
|
+
default: return 'jsonb';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
package/dist/sql.d.ts
CHANGED
|
@@ -1,159 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* «последняя версия» считается ПОСЛЕ сужения по class + GIN-кандидатам, а не по всей таблице.
|
|
4
|
-
*
|
|
5
|
-
* Шаблон шага:
|
|
6
|
-
* SELECT * FROM (
|
|
7
|
-
* SELECT DISTINCT ON (e.id) e.* FROM Entity e
|
|
8
|
-
* WHERE e.partition=$ AND e.class=$
|
|
9
|
-
* [AND e.id = $ | e.id IN (…)] -- id-фильтр
|
|
10
|
-
* [AND e.id = hPrev.links->>$cls] -- forward-джойн (id неизменен)
|
|
11
|
-
* [AND e.id IN (SELECT c.id FROM Entity c -- GIN-кандидаты: containment-фильтры
|
|
12
|
-
* WHERE c.partition=$ AND c.class=$ AND c.data @> $ [AND c.links @> …])]
|
|
13
|
-
* ORDER BY e.id, e.updated DESC -- latest-версия кандидатов
|
|
14
|
-
* ) t
|
|
15
|
-
* WHERE t.deleted IS NULL [AND все фильтры на t] -- перепроверка на АКТУАЛЬНОЙ версии
|
|
16
|
-
*
|
|
17
|
-
* Кандидатное сужение — оптимизация (GIN); истина — перепроверка условий на latest.
|
|
18
|
-
* Цепочка шагов соединяется JOIN LATERAL — комбинации путей сохраняются.
|
|
19
|
-
*/
|
|
20
|
-
import type { Sql } from 'postgres';
|
|
21
|
-
import type { AclOp, AclDecision, ClassDef, ChainMods, FieldType, Filter, QueryEvent } from './types.js';
|
|
22
|
-
import type { Registry } from './schema.js';
|
|
23
|
-
export interface Ctx {
|
|
24
|
-
sql: Sql;
|
|
25
|
-
registry: Registry;
|
|
26
|
-
pgSchema: string;
|
|
27
|
-
partition: string;
|
|
28
|
-
/** Арендатор ВЫЗОВА: заполнен у scoped-хендла db.as(account), пуст у корневого. */
|
|
29
|
-
account?: string;
|
|
30
|
-
/** Дефолтный owner записей этого scope (db.as(account, { owner })). Default = account. */
|
|
31
|
-
owner?: string;
|
|
32
|
-
/** System-аккаунт — fallback для NOT NULL Entity.account (загружается при connect). */
|
|
33
|
-
systemAccount?: string;
|
|
34
|
-
/** Жёсткая изоляция арендатора: все чтения фильтруются, записи пришпилены к account. */
|
|
35
|
-
enforceAccount?: boolean;
|
|
36
|
-
/** enforceAcl: скомпилированный резолвер Rule/Resource (READ/WRITE/DELETE) для account ЭТОГО ctx. */
|
|
37
|
-
aclDecide?: (cls: ClassDef, op: AclOp) => AclDecision;
|
|
38
|
-
/**
|
|
39
|
-
* enforceAcl: скомпилировать энфорсер под субъекта переданного ctx (пишет в c.aclDecide).
|
|
40
|
-
* Ставит connect(); зовут db.as() и reload. Один энфорсер = один субъект: memo в acl.ts
|
|
41
|
-
* ключуется классом+операцией БЕЗ аккаунта, переиспользование между scope — утечка решения.
|
|
42
|
-
*/
|
|
43
|
-
compileAcl?: (c: Ctx) => Promise<void>;
|
|
44
|
-
/** true внутри db.begin()-транзакции (write не оборачивает в begin повторно). */
|
|
45
|
-
inTx?: boolean;
|
|
46
|
-
/** true только у db.begin()-транзакций (не у внутренних): управляет подсказкой при 40P01/40001. */
|
|
47
|
-
userTx?: boolean;
|
|
48
|
-
/** Наблюдаемость: хук на каждый запрос цепочки. */
|
|
49
|
-
onQuery?: (e: QueryEvent) => void;
|
|
50
|
-
/** Порог «медленного» запроса, мс (без onQuery — console.warn). */
|
|
51
|
-
slowMs?: number;
|
|
52
|
-
/** Перечитать определения классов из таблицы Schema: пересобрать registry (+ enforcer при enforceAcl). Ставит connect(). */
|
|
53
|
-
reload?: () => Promise<void>;
|
|
54
|
-
}
|
|
55
|
-
/** Транзиентные ошибки PG — гонка, снимаемая повтором: deadlock / serialization failure. */
|
|
56
|
-
export declare function isTransient(e: unknown): boolean;
|
|
57
|
-
/** Внутри db.begin() повтор невозможен (вся транзакция aborted) — дописываем подсказку. */
|
|
58
|
-
export declare function hintTxRetry(e: unknown): void;
|
|
59
|
-
export declare const RETRIES = 3;
|
|
60
|
-
export declare const retryDelay: (attempt: number) => Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Единая точка исполнения запросов цепочек: sql.unsafe + событие onQuery/slowMs.
|
|
63
|
-
* Чтения в автокоммите ретраят transient-ошибки (40P01/40001); внутри db.begin()
|
|
64
|
-
* повтор запрещён семантикой PG — ошибка уходит наружу с подсказкой.
|
|
65
|
-
* Служебные запросы (loadRegistry, tables, listen) через неё не идут.
|
|
66
|
-
*/
|
|
67
|
-
export declare function runQuery<T>(ctx: Ctx, text: string, params: unknown[], mode: QueryEvent['mode'], classes: string[]): Promise<T[]>;
|
|
68
|
-
/** Значение слота связи: id | вложенный план | null (снять конец). */
|
|
69
|
-
export type SlotValue = string | {
|
|
70
|
-
plan: Step[];
|
|
71
|
-
mods?: ChainMods;
|
|
72
|
-
} | null;
|
|
73
|
-
/** Уникальная метка узла пути (для pivot-возвратов; переживает нарезку плана). */
|
|
74
|
-
export declare const nextNodeKey: () => number;
|
|
1
|
+
import type { ClassInfo, LeafType, Registry } from './registry.js';
|
|
2
|
+
import { type ChainMods, type Cursor, type Filter, type Row } from './types.js';
|
|
75
3
|
export interface Step {
|
|
76
|
-
/** Имя, как вызвано в цепочке (алиас или
|
|
4
|
+
/** Имя, как вызвано в цепочке (класс, алиас или роль). */
|
|
77
5
|
name: string;
|
|
78
|
-
|
|
6
|
+
/** Класс узла (для роли — первый класс её целей): типы листьев, вид hub/link. */
|
|
7
|
+
cls: ClassInfo;
|
|
8
|
+
/** Шаг вызван именем роли (конца): переход идёт именно этим концом. */
|
|
9
|
+
role?: string;
|
|
79
10
|
filter?: Filter;
|
|
80
|
-
/** Метка узла
|
|
11
|
+
/** Метка узла — у каждого реального шага. */
|
|
81
12
|
nodeKey?: number;
|
|
82
|
-
/**
|
|
83
|
-
* Pivot: шаг-ВОЗВРАТ к уже введённому узлу (повтор LINK-класса / entity(та же переменная)).
|
|
84
|
-
* Не создаёт узел; его фильтры дофильтровывают узел (AND); следующий шаг ветвится от узла.
|
|
85
|
-
*/
|
|
13
|
+
/** Возврат к уже введённому узлу (повтор связи, entity() той же переменной). */
|
|
86
14
|
pivotKey?: number;
|
|
87
|
-
/** .alias(name) — ключ шага в путях. */
|
|
88
15
|
aliasKey?: string;
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
* (родитель отдаёт объединение с потомками); нужно, когда наследование в домене
|
|
92
|
-
* использовано для переиспользования attributes, а не как «is-a» для выборки
|
|
93
|
-
* (демо: `запись` наследует `окно`, но смена ≠ бронь).
|
|
94
|
-
*/
|
|
95
|
-
exactClass?: boolean;
|
|
96
|
-
/** .tags(…) — фильтр по колонке tags: строка | string[] (все) | has/hasAny/hasAll. */
|
|
16
|
+
/** Только сам класс, без потомков. */
|
|
17
|
+
exact?: boolean;
|
|
97
18
|
tagsFilter?: unknown;
|
|
98
|
-
/** .account(uuid|Row) — фильтр по колонке account. */
|
|
99
|
-
accountFilter?: string;
|
|
100
|
-
/** .owner(uuid|Row) — фильтр по колонке owner. */
|
|
101
19
|
ownerFilter?: string;
|
|
102
|
-
/** Внутреннее (write-цепочки): containment по links — контекст-связи. */
|
|
103
|
-
linksFilter?: Record<string, string>;
|
|
104
|
-
/**
|
|
105
|
-
* Слоты связей (`.Класс.set(target)` / `.Класс.unset()`): значения концов записываемой
|
|
106
|
-
* версии БЕЗ участия в фильтре целей. string — id; {plan} — вложенная цепочка (та же
|
|
107
|
-
* транзакция, ровно одна сущность класса конца); null — снять optional-конец.
|
|
108
|
-
*/
|
|
109
|
-
extraLinks?: Record<string, SlotValue>;
|
|
110
|
-
/** Внутреннее (enforceAcl): предикат WRITE/DELETE-правила — цели ищутся только среди своих. */
|
|
111
|
-
aclFilter?: Record<string, unknown>;
|
|
112
|
-
/** .deep(max): рекурсивный self-обход (дети любой глубины), только reverse того же класса. */
|
|
113
20
|
deepMax?: number;
|
|
114
|
-
/**
|
|
115
|
-
op?: import('./
|
|
116
|
-
/**
|
|
117
|
-
|
|
21
|
+
/** Звено плана записи (этап 4): глагол на этом шаге; построитель чтения его не видит. */
|
|
22
|
+
op?: import('./write.js').PlanOp;
|
|
23
|
+
/** Модификаторы цепочки на момент глагола: limit и sort сужают цели записи. */
|
|
24
|
+
opMods?: ChainMods;
|
|
25
|
+
/** Слоты концов записываемой версии: .Роль.set/unset/add/remove. */
|
|
26
|
+
slots?: import('./write.js').Slot[];
|
|
27
|
+
/** Глагол сразу после глагола — пишет в те же сущности. */
|
|
28
|
+
self?: true;
|
|
29
|
+
}
|
|
30
|
+
/** Уникальная метка узла пути. */
|
|
31
|
+
export declare const nextNodeKey: () => number;
|
|
32
|
+
export type ReadMode = 'paths' | 'rows' | 'ids' | 'count' | 'countPaths' | 'versions' | 'agg';
|
|
33
|
+
export interface AggSpec {
|
|
34
|
+
fn: 'sum' | 'avg' | 'min' | 'max' | 'countBy';
|
|
35
|
+
field: string;
|
|
118
36
|
}
|
|
119
|
-
export declare const entityTable: (pgSchema: string) => string;
|
|
120
|
-
/** Тип листа data-пути по Schema: спуск через record (значение) и object (props). */
|
|
121
|
-
export declare function leafType(cls: ClassDef, path: string[]): FieldType | undefined;
|
|
122
|
-
type HopMode = 'forward' | 'reverse';
|
|
123
|
-
/** Класс target входит в какой-нибудь конец def (союзы учитываются). */
|
|
124
|
-
export declare function linksTo(def: ClassDef, target: string): boolean;
|
|
125
|
-
/** Правило обхода между шагами (по реестру Schema). */
|
|
126
|
-
export declare function resolveHop(prev: ClassDef, next: ClassDef): HopMode;
|
|
127
|
-
export type ReadMode = 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg';
|
|
128
37
|
export interface BuiltQuery {
|
|
129
38
|
text: string;
|
|
130
39
|
params: unknown[];
|
|
131
|
-
/** Ключи шагов в путях (
|
|
40
|
+
/** Ключи шагов в путях (алиасы, повторы — _2, _3). */
|
|
132
41
|
keys: string[];
|
|
42
|
+
/** Тип листа агрегата (min/max числового поля приводятся к числу). */
|
|
43
|
+
aggLeaf?: LeafType;
|
|
44
|
+
}
|
|
45
|
+
/** Классы, которые объявляют роль. */
|
|
46
|
+
export declare function roleOwners(reg: Registry, role: string): ClassInfo[];
|
|
47
|
+
/** Классы целей роли (имя конца однозначно во всей схеме — проверяет база). */
|
|
48
|
+
export declare function roleTargets(reg: Registry, role: string): string[];
|
|
49
|
+
/** Конкретные классы, которые матчит шаг: класс (роль — её цели) и потомки, если не exact(). */
|
|
50
|
+
export declare function stepClasses(reg: Registry, step: Step): string[];
|
|
51
|
+
/** Принимает ли список классов конца класс cls (с учётом его предков). */
|
|
52
|
+
export declare const accepts: (reg: Registry, targets: string[], cls: string) => boolean;
|
|
53
|
+
export interface Hop {
|
|
54
|
+
dir: 'forward' | 'reverse';
|
|
55
|
+
/** Только эти роли; null — любой конец (целостность ссылок гарантирует, что подходят только допустимые). */
|
|
56
|
+
roles: string[] | null;
|
|
133
57
|
}
|
|
134
|
-
/** Корневой хендл при enforceAccount читать/писать не может: арендатора называет db.as(). */
|
|
135
|
-
export declare function guardScoped(ctx: Ctx): void;
|
|
136
|
-
/** Построить читающий запрос по цепочке. */
|
|
137
|
-
export declare function buildRead(ctx: Ctx, steps: Step[], mods: ChainMods, mode: ReadMode): BuiltQuery;
|
|
138
|
-
/** INSERT новой версии/tombstone. $9 = updated прошлой версии (или null), $10 = deleted. */
|
|
139
|
-
export declare function insertSql(pgSchema: string): string;
|
|
140
|
-
/** Мульти-INSERT новых строк (батч): n строк × 8 параметров, updated/deleted по умолчанию. */
|
|
141
|
-
export declare function multiInsertSql(pgSchema: string, n: number): string;
|
|
142
|
-
/**
|
|
143
|
-
* Серверное удаление: DELETE перехватывает триггер entity_delete —
|
|
144
|
-
* tombstone актуальной живой версии + рекурсивный каскад по links, всё в БД.
|
|
145
|
-
* $1 partition, $2 class, дальше — id-шники.
|
|
146
|
-
*/
|
|
147
|
-
export declare function deleteSql(pgSchema: string, n: number): string;
|
|
148
|
-
/**
|
|
149
|
-
* Замыкание удаления: цели + все живые зависимые рекурсивно (то, что каскад затомбстоунит).
|
|
150
|
-
* Рекурсивный CTE; каждый узел — актуальная живая версия. $1 partition, $2 class, $3+ — ids.
|
|
151
|
-
*/
|
|
152
|
-
export declare function closureSql(pgSchema: string, n: number): string;
|
|
153
58
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
59
|
+
* Направление перехода между узлами (расширение resolveHop 0.21):
|
|
60
|
+
* - шаг-роль после владельца роли — вперёд этим концом; шаг после роли — назад этим концом;
|
|
61
|
+
* - иначе по концам всех классов обоих семейств: в своём семействе (папка → папки) — назад, к детям;
|
|
62
|
+
* хаб → связь — назад; связь → хаб и хаб → хаб — вперёд; нет нужного — другое направление.
|
|
157
63
|
*/
|
|
158
|
-
export declare function
|
|
159
|
-
|
|
64
|
+
export declare function resolveHop(reg: Registry, prev: Step, next: Step): Hop;
|
|
65
|
+
/** Курсор keyset-пагинации из последней строки страницы. */
|
|
66
|
+
export declare function cursorOf(row: Row, field: string): Cursor;
|
|
67
|
+
export interface BuildOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Режим сверки (тест find-ids-parity): вместо функций владельца find_* — те же запросы прямо
|
|
70
|
+
* под RLS. Индексы GIN тогда не работают, зато видимость решают политики, а не row_visible().
|
|
71
|
+
*/
|
|
72
|
+
direct?: boolean;
|
|
73
|
+
}
|
|
74
|
+
export declare function buildRead(reg: Registry, schema: string, steps: Step[], mods: ChainMods, mode: ReadMode, agg?: AggSpec, opts?: BuildOptions): BuiltQuery;
|
|
75
|
+
/** Строка из to_jsonb(узла): служебные поля в $deleted / $depth, пустые необязательные — без ключа. */
|
|
76
|
+
export declare function toRow(raw: Record<string, unknown>): Row;
|