fastify-auto-sqlapi 0.0.5 → 0.1.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/AGENTS.md +15 -2
- package/AGENTS_BACKEND.md +144 -20
- package/AGENTS_FRONTEND.md +161 -67
- package/README.md +47 -26
- package/dist/bin/generate-schema.js +9 -26
- package/dist/bin/generate-tables.js +7 -30
- package/dist/bin/utils.d.ts +28 -0
- package/dist/bin/utils.d.ts.map +1 -1
- package/dist/bin/utils.js +69 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/cli/load-dependency.d.ts +8 -0
- package/dist/lib/cli/load-dependency.d.ts.map +1 -0
- package/dist/lib/cli/load-dependency.js +21 -0
- package/dist/lib/cli/mysql-introspect.d.ts.map +1 -1
- package/dist/lib/cli/mysql-introspect.js +2 -18
- package/dist/lib/cli/pg-introspect.d.ts.map +1 -1
- package/dist/lib/cli/pg-introspect.js +2 -17
- package/dist/lib/db.d.ts +1 -0
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +33 -55
- package/dist/lib/dialect.d.ts +17 -0
- package/dist/lib/dialect.d.ts.map +1 -1
- package/dist/lib/dialect.js +32 -0
- package/dist/lib/engine/bulk/bulk-delete.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-delete.js +8 -2
- package/dist/lib/engine/bulk/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-upsert.js +15 -43
- package/dist/lib/engine/rest/delete.d.ts.map +1 -1
- package/dist/lib/engine/rest/delete.js +14 -12
- package/dist/lib/engine/rest/get.d.ts.map +1 -1
- package/dist/lib/engine/rest/get.js +3 -5
- package/dist/lib/engine/rest/insert.d.ts.map +1 -1
- package/dist/lib/engine/rest/insert.js +11 -31
- package/dist/lib/engine/rest/update.d.ts.map +1 -1
- package/dist/lib/engine/rest/update.js +13 -46
- package/dist/lib/engine/search/search.d.ts.map +1 -1
- package/dist/lib/engine/search/search.js +553 -229
- package/dist/lib/engine/write-helpers.d.ts +39 -2
- package/dist/lib/engine/write-helpers.d.ts.map +1 -1
- package/dist/lib/engine/write-helpers.js +55 -12
- package/dist/lib/errors.d.ts +11 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +12 -0
- package/dist/lib/schema/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/schema/bulk-upsert.js +9 -25
- package/dist/lib/schema/helpers.d.ts +28 -1
- package/dist/lib/schema/helpers.d.ts.map +1 -1
- package/dist/lib/schema/helpers.js +38 -0
- package/dist/lib/schema/insert.d.ts.map +1 -1
- package/dist/lib/schema/insert.js +9 -19
- package/dist/lib/schema/search.d.ts.map +1 -1
- package/dist/lib/schema/search.js +138 -50
- package/dist/lib/schema/update.d.ts.map +1 -1
- package/dist/lib/schema/update.js +9 -25
- package/dist/lib/sql-api.d.ts +6 -6
- package/dist/lib/sql-api.d.ts.map +1 -1
- package/dist/lib/sql-api.js +10 -10
- package/dist/lib/table-helpers.d.ts +6 -1
- package/dist/lib/table-helpers.d.ts.map +1 -1
- package/dist/lib/table-helpers.js +42 -2
- package/dist/lib/tenant.d.ts +30 -0
- package/dist/lib/tenant.d.ts.map +1 -1
- package/dist/lib/tenant.js +78 -9
- package/dist/routes/auto/bulk-delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-delete.routes.js +17 -23
- package/dist/routes/auto/bulk-upsert.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-upsert.routes.js +16 -22
- package/dist/routes/auto/delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/delete.routes.js +18 -24
- package/dist/routes/auto/get.routes.d.ts.map +1 -1
- package/dist/routes/auto/get.routes.js +16 -23
- package/dist/routes/auto/insert.routes.d.ts.map +1 -1
- package/dist/routes/auto/insert.routes.js +19 -26
- package/dist/routes/auto/plugin.d.ts.map +1 -1
- package/dist/routes/auto/plugin.js +40 -5
- package/dist/routes/auto/route-helpers.d.ts +27 -2
- package/dist/routes/auto/route-helpers.d.ts.map +1 -1
- package/dist/routes/auto/route-helpers.js +39 -1
- package/dist/routes/auto/search.routes.d.ts.map +1 -1
- package/dist/routes/auto/search.routes.js +47 -47
- package/dist/routes/auto/update.routes.d.ts.map +1 -1
- package/dist/routes/auto/update.routes.js +20 -27
- package/dist/types/cli.d.ts +22 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +1 -0
- package/dist/types/computed.d.ts +29 -0
- package/dist/types/computed.d.ts.map +1 -0
- package/dist/types/computed.js +1 -0
- package/dist/types/conditions.d.ts +16 -0
- package/dist/types/conditions.d.ts.map +1 -0
- package/dist/types/conditions.js +1 -0
- package/dist/types/db.d.ts +22 -0
- package/dist/types/db.d.ts.map +1 -0
- package/dist/types/db.js +1 -0
- package/dist/types/dml.d.ts +66 -0
- package/dist/types/dml.d.ts.map +1 -0
- package/dist/types/dml.js +1 -0
- package/dist/types/join.d.ts +44 -0
- package/dist/types/join.d.ts.map +1 -0
- package/dist/types/join.js +1 -0
- package/dist/types/plugin.d.ts +20 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +1 -0
- package/dist/types/schema.d.ts +10 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +1 -0
- package/dist/types/search.d.ts +45 -0
- package/dist/types/search.d.ts.map +1 -0
- package/dist/types/search.js +1 -0
- package/dist/types/table.d.ts +76 -0
- package/dist/types/table.d.ts.map +1 -0
- package/dist/types/table.js +7 -0
- package/dist/types/tenant.d.ts +19 -0
- package/dist/types/tenant.d.ts.map +1 -0
- package/dist/types/tenant.js +1 -0
- package/dist/types/validation.d.ts +21 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +1 -0
- package/dist/types.d.ts +12 -277
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +12 -7
- package/package.json +3 -3
|
@@ -4,102 +4,190 @@ const JoinGroupResultItem = Type.Object({
|
|
|
4
4
|
sum: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
5
5
|
min: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
6
6
|
max: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
7
|
+
avg: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
8
|
+
count: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
7
9
|
distinctCount: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
8
10
|
rows: Type.Optional(Type.Array(Type.Any())),
|
|
9
11
|
});
|
|
10
12
|
export function SearchTableBodyPost(dbTables, tableName) {
|
|
11
13
|
const tableConf = dbTables[tableName];
|
|
12
14
|
const schema = tableConf.Schema;
|
|
13
|
-
// Condition item shape (shared across main, joinFilters, joins, joinGroups)
|
|
14
15
|
const methodEnum = Type.Union(ALLOWED_METHODS.map((m) => Type.Literal(m)));
|
|
15
16
|
const conditionItemSchema = Type.Object({
|
|
16
17
|
field: Type.String(),
|
|
17
18
|
method: methodEnum,
|
|
18
19
|
params: Type.Optional(Type.Array(Type.Any())),
|
|
19
20
|
});
|
|
20
|
-
//
|
|
21
|
+
// Build a TypeBox map of computed-field types (declared in defineTable).
|
|
22
|
+
const computedTypes = {};
|
|
23
|
+
if (tableConf.computedFields) {
|
|
24
|
+
for (const [name, fn] of Object.entries(tableConf.computedFields)) {
|
|
25
|
+
// Cheap dry-run with a stub context to extract the declared `type`.
|
|
26
|
+
// The fn is pure-functional w.r.t. ctx — only `type` is read here.
|
|
27
|
+
try {
|
|
28
|
+
const stub = fn({
|
|
29
|
+
db: { qi: (s) => s, dialectName: 'postgres' },
|
|
30
|
+
qiCol: () => '""',
|
|
31
|
+
});
|
|
32
|
+
if (stub.type)
|
|
33
|
+
computedTypes[name] = stub.type;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore — Swagger schema generation is best-effort; runtime validates.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
21
40
|
const filterFields = {
|
|
22
41
|
...schema.fields,
|
|
23
42
|
...tableConf.extraFilters,
|
|
43
|
+
...computedTypes,
|
|
24
44
|
};
|
|
25
45
|
const filtersSchema = Type.Optional(Type.Partial(Type.Object(filterFields)));
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
46
|
+
// Per-alias entries split by unique flag:
|
|
47
|
+
// - unique:false → joinMustExist / joinMultiple / joinGroup
|
|
48
|
+
// - unique:true → joinLeft
|
|
49
|
+
const joinMustExistProps = {};
|
|
50
|
+
const joinMultipleProps = {};
|
|
51
|
+
const joinGroupProps = {};
|
|
52
|
+
const joinLeftProps = {};
|
|
30
53
|
if (tableConf.allowedReadJoins) {
|
|
31
|
-
for (const
|
|
32
|
-
const
|
|
33
|
-
const joinTableConf = dbTables[
|
|
54
|
+
for (const joinDef of tableConf.allowedReadJoins) {
|
|
55
|
+
const { joinSchema, alias, unique } = joinDef;
|
|
56
|
+
const joinTableConf = dbTables[joinSchema.tableName];
|
|
57
|
+
const joinComputedTypes = {};
|
|
58
|
+
if (joinTableConf?.computedFields) {
|
|
59
|
+
for (const [name, fn] of Object.entries(joinTableConf.computedFields)) {
|
|
60
|
+
try {
|
|
61
|
+
const stub = fn({
|
|
62
|
+
db: { qi: (s) => s, dialectName: 'postgres' },
|
|
63
|
+
qiCol: () => '""',
|
|
64
|
+
});
|
|
65
|
+
if (stub.type)
|
|
66
|
+
joinComputedTypes[name] = stub.type;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// best-effort
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
34
73
|
const joinFilterFields = joinTableConf
|
|
35
|
-
? { ...joinSchema.fields, ...joinTableConf.extraFilters }
|
|
74
|
+
? { ...joinSchema.fields, ...joinTableConf.extraFilters, ...joinComputedTypes }
|
|
36
75
|
: { ...joinSchema.fields };
|
|
37
|
-
// Shared { filters?, conditions? } shape for joinFilters, joins, and joinGroups inner filters
|
|
38
76
|
const joinRefShape = {
|
|
39
77
|
filters: Type.Optional(Type.Partial(Type.Object(joinFilterFields))),
|
|
40
78
|
conditions: Type.Optional(Type.Array(conditionItemSchema)),
|
|
41
79
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
80
|
+
const joinFetchShape = {
|
|
81
|
+
...joinRefShape,
|
|
82
|
+
selection: Type.Optional(Type.String()),
|
|
83
|
+
};
|
|
84
|
+
if (unique) {
|
|
85
|
+
joinLeftProps[alias] = Type.Object(joinFetchShape);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
joinMustExistProps[alias] = Type.Object(joinRefShape);
|
|
89
|
+
joinMultipleProps[alias] = Type.Object(joinFetchShape);
|
|
90
|
+
joinGroupProps[alias] = Type.Object({
|
|
91
|
+
aggregations: Type.Object({
|
|
92
|
+
by: Type.Optional(Type.String()),
|
|
93
|
+
distinctCount: Type.Optional(Type.Array(Type.String())),
|
|
94
|
+
min: Type.Optional(Type.Array(Type.String())),
|
|
95
|
+
max: Type.Optional(Type.Array(Type.String())),
|
|
96
|
+
sum: Type.Optional(Type.Array(Type.String())),
|
|
97
|
+
avg: Type.Optional(Type.Array(Type.String())),
|
|
98
|
+
count: Type.Optional(Type.Array(Type.String())),
|
|
99
|
+
}),
|
|
100
|
+
filters: Type.Optional(Type.Partial(Type.Object(joinFilterFields))),
|
|
101
|
+
conditions: Type.Optional(Type.Array(conditionItemSchema)),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
57
104
|
}
|
|
58
105
|
}
|
|
59
106
|
const bodyProperties = {
|
|
60
107
|
filters: filtersSchema,
|
|
61
108
|
conditions: Type.Optional(Type.Array(conditionItemSchema)),
|
|
62
109
|
};
|
|
63
|
-
if (Object.keys(
|
|
64
|
-
bodyProperties.
|
|
65
|
-
|
|
66
|
-
|
|
110
|
+
if (Object.keys(computedTypes).length > 0) {
|
|
111
|
+
bodyProperties.selectComputed = Type.Optional(Type.Array(Type.String()));
|
|
112
|
+
}
|
|
113
|
+
if (Object.keys(joinMustExistProps).length > 0) {
|
|
114
|
+
bodyProperties.joinMustExist = Type.Optional(Type.Partial(Type.Object(joinMustExistProps)));
|
|
115
|
+
bodyProperties.joinMultiple = Type.Optional(Type.Partial(Type.Object(joinMultipleProps)));
|
|
116
|
+
bodyProperties.joinGroup = Type.Optional(Type.Partial(Type.Object(joinGroupProps)));
|
|
117
|
+
}
|
|
118
|
+
if (Object.keys(joinLeftProps).length > 0) {
|
|
119
|
+
bodyProperties.joinLeft = Type.Optional(Type.Partial(Type.Object(joinLeftProps)));
|
|
67
120
|
}
|
|
68
121
|
return Type.Object(bodyProperties);
|
|
69
122
|
}
|
|
70
123
|
export const SearchTableQueryString = Type.Object({
|
|
71
124
|
orderBy: Type.Optional(Type.String()),
|
|
72
125
|
page: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
73
|
-
itemsPerPage: Type.Optional(Type.Integer({ minimum: 1,
|
|
126
|
+
itemsPerPage: Type.Optional(Type.Integer({ minimum: 1, default: 500 })),
|
|
74
127
|
computeMin: Type.Optional(Type.String()),
|
|
75
128
|
computeMax: Type.Optional(Type.String()),
|
|
76
129
|
computeSum: Type.Optional(Type.String()),
|
|
77
130
|
computeAvg: Type.Optional(Type.String()),
|
|
131
|
+
// selectComputed list goes in the body (POST), not querystring — see SearchTableBodyPost.
|
|
78
132
|
});
|
|
79
133
|
export function SearchTableResponse(dbTables, tableName) {
|
|
80
134
|
const tableConf = dbTables[tableName];
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
135
|
+
// Computed fields are present in main rows only when explicitly listed in
|
|
136
|
+
// request body's selectComputed, so they're optional/Partial here.
|
|
137
|
+
const computedTypes = {};
|
|
138
|
+
if (tableConf.computedFields) {
|
|
139
|
+
for (const [name, fn] of Object.entries(tableConf.computedFields)) {
|
|
140
|
+
try {
|
|
141
|
+
const stub = fn({
|
|
142
|
+
db: { qi: (s) => s, dialectName: 'postgres' },
|
|
143
|
+
qiCol: () => '""',
|
|
144
|
+
});
|
|
145
|
+
if (stub.type)
|
|
146
|
+
computedTypes[name] = stub.type;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// best-effort
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const mainItem = Object.keys(computedTypes).length > 0
|
|
154
|
+
? Type.Partial(Type.Object({ ...tableConf.Schema.fields, ...computedTypes }))
|
|
155
|
+
: Type.Partial(Type.Object(tableConf.Schema.fields));
|
|
156
|
+
const joinMultipleProps = {};
|
|
157
|
+
const joinLeftProps = {};
|
|
158
|
+
const joinGroupProps = {};
|
|
84
159
|
if (tableConf.allowedReadJoins) {
|
|
85
|
-
for (const
|
|
86
|
-
|
|
87
|
-
|
|
160
|
+
for (const joinDef of tableConf.allowedReadJoins) {
|
|
161
|
+
const { joinSchema, alias, unique } = joinDef;
|
|
162
|
+
const itemArray = Type.Array(Type.Partial(Type.Object(joinSchema.fields)));
|
|
163
|
+
if (unique) {
|
|
164
|
+
joinLeftProps[alias] = itemArray;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
joinMultipleProps[alias] = itemArray;
|
|
168
|
+
joinGroupProps[alias] = JoinGroupResultItem;
|
|
169
|
+
}
|
|
88
170
|
}
|
|
89
171
|
}
|
|
90
|
-
|
|
172
|
+
const responseProps = {
|
|
91
173
|
table: Type.String(),
|
|
92
174
|
main: Type.Array(mainItem),
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
175
|
+
};
|
|
176
|
+
if (Object.keys(joinMultipleProps).length > 0) {
|
|
177
|
+
responseProps.joinMultiple = Type.Optional(Type.Partial(Type.Object(joinMultipleProps)));
|
|
178
|
+
responseProps.joinGroup = Type.Optional(Type.Partial(Type.Object(joinGroupProps)));
|
|
179
|
+
}
|
|
180
|
+
if (Object.keys(joinLeftProps).length > 0) {
|
|
181
|
+
responseProps.joinLeft = Type.Optional(Type.Partial(Type.Object(joinLeftProps)));
|
|
182
|
+
}
|
|
183
|
+
responseProps.pagination = Type.Optional(Type.Object({
|
|
184
|
+
total: Type.Integer(),
|
|
185
|
+
pages: Type.Integer(),
|
|
186
|
+
computed: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
187
|
+
paginator: Type.Object({
|
|
188
|
+
page: Type.Integer(),
|
|
189
|
+
itemsPerPage: Type.Integer(),
|
|
190
|
+
}),
|
|
191
|
+
}));
|
|
192
|
+
return Type.Object(responseProps);
|
|
105
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,OAAO,EAAgB,MAAM,mBAAmB,CAAC;AAErE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAS/C,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAqB9E;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAalF"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Type } from '@sinclair/typebox';
|
|
2
2
|
import { primaryAsString } from '../../types.js';
|
|
3
|
-
import {
|
|
4
|
-
import { pkSchema, buildSecondaryFields, applySchemaOverrides } from './helpers.js';
|
|
3
|
+
import { pkSchema, applySchemaOverrides, attachWriteJoinSections, writeJoinBodyFields, writeJoinResponseFields, } from './helpers.js';
|
|
5
4
|
export function UpdateTableBody(dbTables, tableName) {
|
|
6
5
|
const tableConf = dbTables[tableName];
|
|
7
6
|
const schema = tableConf.Schema;
|
|
@@ -14,18 +13,10 @@ export function UpdateTableBody(dbTables, tableName) {
|
|
|
14
13
|
const bodyProperties = {
|
|
15
14
|
main: Type.Object(mainFields),
|
|
16
15
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const secondaryTableConf = findSecondaryTableConf(dbTables, joinSchema.tableName);
|
|
22
|
-
const joinFields = buildSecondaryFields(joinSchema, joinField, secondaryTableConf);
|
|
23
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(joinFields));
|
|
24
|
-
deletionProperties[joinSchema.tableName] = Type.Array(Type.Partial(Type.Object(joinSchema.fields)));
|
|
25
|
-
}
|
|
26
|
-
bodyProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
27
|
-
bodyProperties.deletions = Type.Optional(Type.Partial(Type.Object(deletionProperties)));
|
|
28
|
-
}
|
|
16
|
+
attachWriteJoinSections(bodyProperties, tableConf, dbTables, {
|
|
17
|
+
withDeletions: true,
|
|
18
|
+
secondaryFields: writeJoinBodyFields,
|
|
19
|
+
});
|
|
29
20
|
return Type.Object(bodyProperties);
|
|
30
21
|
}
|
|
31
22
|
export function UpdateTableResponse(dbTables, tableName) {
|
|
@@ -33,16 +24,9 @@ export function UpdateTableResponse(dbTables, tableName) {
|
|
|
33
24
|
const responseProperties = {
|
|
34
25
|
main: Type.Object(pkSchema(tableConf, tableConf.Schema, primaryAsString(tableConf.primary))),
|
|
35
26
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const secondaryTableConf = findSecondaryTableConf(dbTables, joinSchema.tableName);
|
|
41
|
-
secondaryProperties[joinSchema.tableName] = Type.Array(Type.Object(pkSchema(secondaryTableConf, joinSchema, joinField)));
|
|
42
|
-
deletionProperties[joinSchema.tableName] = Type.Array(Type.Partial(Type.Object(joinSchema.fields)));
|
|
43
|
-
}
|
|
44
|
-
responseProperties.secondaries = Type.Optional(Type.Partial(Type.Object(secondaryProperties)));
|
|
45
|
-
responseProperties.deletions = Type.Optional(Type.Partial(Type.Object(deletionProperties)));
|
|
46
|
-
}
|
|
27
|
+
attachWriteJoinSections(responseProperties, tableConf, dbTables, {
|
|
28
|
+
withDeletions: true,
|
|
29
|
+
secondaryFields: writeJoinResponseFields,
|
|
30
|
+
});
|
|
47
31
|
return Type.Object(responseProperties);
|
|
48
32
|
}
|
package/dist/lib/sql-api.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import type { FastifyRequest } from 'fastify';
|
|
2
2
|
import { QueryClient } from './db.js';
|
|
3
3
|
import { type DialectName } from './dialect.js';
|
|
4
|
-
import type { DbTables, Queryable, FilterRecord, SearchCondition, Paginator, JoinGroupRequest, SearchResult, GetResult, InsertResult, UpdateResult, DeleteResult, BulkUpsertItem, BulkUpsertResult, BulkDeleteResult, TenantId } from '../types.js';
|
|
4
|
+
import type { DbTables, Queryable, FilterRecord, SearchCondition, Paginator, JoinGroupRequest, JoinRefFilter, JoinFetchRequest, SearchResult, GetResult, InsertResult, UpdateResult, DeleteResult, BulkUpsertItem, BulkUpsertResult, BulkDeleteResult, TenantId } from '../types.js';
|
|
5
5
|
export interface SqlApiSearchParams {
|
|
6
6
|
filters?: FilterRecord;
|
|
7
7
|
conditions?: SearchCondition[];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
joinGroups?: Record<string, JoinGroupRequest>;
|
|
8
|
+
joinMustExist?: Record<string, JoinRefFilter>;
|
|
9
|
+
joinMultiple?: Record<string, JoinFetchRequest>;
|
|
10
|
+
joinGroup?: Record<string, JoinGroupRequest>;
|
|
11
|
+
joinLeft?: Record<string, JoinFetchRequest>;
|
|
13
12
|
orderBy?: string;
|
|
14
13
|
paginator?: Paginator;
|
|
15
14
|
computeMin?: string;
|
|
16
15
|
computeMax?: string;
|
|
17
16
|
computeSum?: string;
|
|
18
17
|
computeAvg?: string;
|
|
18
|
+
selectComputed?: string[];
|
|
19
19
|
}
|
|
20
20
|
export interface SqlApiInsertParams {
|
|
21
21
|
record: Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-api.d.ts","sourceRoot":"","sources":["../../src/lib/sql-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,EAAqB,WAAW,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"sql-api.d.ts","sourceRoot":"","sources":["../../src/lib/sql-api.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/sql-api.js
CHANGED
|
@@ -2,6 +2,7 @@ import { ConditionBuilder } from 'node-condition-builder';
|
|
|
2
2
|
import { createQueryClient, QueryClient } from './db.js';
|
|
3
3
|
import { getDialect } from './dialect.js';
|
|
4
4
|
import { resolveTenant } from './tenant.js';
|
|
5
|
+
import { httpError } from './errors.js';
|
|
5
6
|
import { searchEngine } from './engine/search/search.js';
|
|
6
7
|
import { getEngine } from './engine/rest/get.js';
|
|
7
8
|
import { insertEngine } from './engine/rest/insert.js';
|
|
@@ -31,11 +32,8 @@ export class SqlApi {
|
|
|
31
32
|
}
|
|
32
33
|
getTableConf(tableName) {
|
|
33
34
|
const conf = this.dbTables[tableName];
|
|
34
|
-
if (!conf)
|
|
35
|
-
|
|
36
|
-
err.statusCode = 400;
|
|
37
|
-
throw err;
|
|
38
|
-
}
|
|
35
|
+
if (!conf)
|
|
36
|
+
throw httpError(400, `Table "${tableName}" not found in DbTables`);
|
|
39
37
|
return conf;
|
|
40
38
|
}
|
|
41
39
|
async getTenant(tableName, request) {
|
|
@@ -52,15 +50,17 @@ export class SqlApi {
|
|
|
52
50
|
tableConf,
|
|
53
51
|
filters: params.filters,
|
|
54
52
|
conditions: params.conditions,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
joinMustExist: params.joinMustExist,
|
|
54
|
+
joinMultiple: params.joinMultiple,
|
|
55
|
+
joinGroup: params.joinGroup,
|
|
56
|
+
joinLeft: params.joinLeft,
|
|
58
57
|
orderBy: params.orderBy,
|
|
59
58
|
paginator: params.paginator,
|
|
60
59
|
computeMin: params.computeMin,
|
|
61
60
|
computeMax: params.computeMax,
|
|
62
61
|
computeSum: params.computeSum,
|
|
63
62
|
computeAvg: params.computeAvg,
|
|
63
|
+
selectComputed: params.selectComputed,
|
|
64
64
|
tenant,
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -99,7 +99,7 @@ export class SqlApi {
|
|
|
99
99
|
async delete(tableName, id, request) {
|
|
100
100
|
const tableConf = this.getTableConf(tableName);
|
|
101
101
|
const tenant = await this.getTenant(tableName, request);
|
|
102
|
-
return deleteEngine({ db: this.db, tableConf, id, tenant });
|
|
102
|
+
return deleteEngine({ db: this.db, tableConf, id, tenant, request });
|
|
103
103
|
}
|
|
104
104
|
async bulkUpsert(tableName, items, request) {
|
|
105
105
|
const tableConf = this.getTableConf(tableName);
|
|
@@ -116,7 +116,7 @@ export class SqlApi {
|
|
|
116
116
|
async bulkDelete(tableName, ids, request) {
|
|
117
117
|
const tableConf = this.getTableConf(tableName);
|
|
118
118
|
const tenant = await this.getTenant(tableName, request);
|
|
119
|
-
return bulkDeleteEngine({ db: this.db, tableConf, ids, tenant });
|
|
119
|
+
return bulkDeleteEngine({ db: this.db, tableConf, ids, tenant, request });
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
export function createSqlApi(dbOrPool, dbTables, options) {
|
|
@@ -10,7 +10,12 @@ export declare function exportTableInfo<F extends Record<string, TSchema>, EF ex
|
|
|
10
10
|
extraFilters: Record<string, TSchema>;
|
|
11
11
|
};
|
|
12
12
|
export declare function defineTable<F extends Record<string, TSchema>>(config: ITable<F>): ITable<F>;
|
|
13
|
-
export
|
|
13
|
+
export interface BuildRelationOptions {
|
|
14
|
+
alias?: string;
|
|
15
|
+
selection?: string;
|
|
16
|
+
unique?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildRelation<M extends Record<string, TSchema>, J extends Record<string, TSchema>>(mainSchema: SchemaDefinition<M>, mainField: string & keyof M | (string & keyof M)[], joinSchema: SchemaDefinition<J>, joinField: string & keyof J, options?: BuildRelationOptions): JoinDefinition;
|
|
14
19
|
export declare function buildUpsertRule<F extends Record<string, TSchema>>(schema: SchemaDefinition<F>, columns: (string & keyof F)[]): [SchemaDefinition, string[]];
|
|
15
20
|
export declare function buildUpsertRules(...rules: [SchemaDefinition, string[]][]): Map<SchemaDefinition, string[]>;
|
|
16
21
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/table-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,MAAM,EACP,MAAM,aAAa,CAAC;AAYrB,KAAK,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAExH,wBAAgB,eAAe,CAC7B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,EAAE,SAAS,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,EAErE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,YAAY,GAAE,EAAa,EAC3B,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,yBAAyB;CAAE,KAC3E,IAAI,GACR;IAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CA0BhG;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChB,MAAM,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"table-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/table-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,MAAM,EACP,MAAM,aAAa,CAAC;AAYrB,KAAK,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAExH,wBAAgB,eAAe,CAC7B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,EAAE,SAAS,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,EAErE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,YAAY,GAAE,EAAa,EAC3B,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,yBAAyB;CAAE,KAC3E,IAAI,GACR;IAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CA0BhG;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,GAChB,MAAM,CAAC,CAAC,CAAC,CAKX;AA2CD,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,aAAa,CAC3B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAEjC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,EAClD,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,cAAc,CAShB;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,OAAO,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,GAC5B,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAE9B;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,KAAK,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC,EAAE,GACvC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAEjC"}
|
|
@@ -29,10 +29,50 @@ export function exportTableInfo(Schema, extraFilters = {}, extendedCondition) {
|
|
|
29
29
|
return { Schema, filters, extraFilters: efRecord };
|
|
30
30
|
}
|
|
31
31
|
export function defineTable(config) {
|
|
32
|
+
validateAliasUniqueness(config.allowedReadJoins, 'allowedReadJoins');
|
|
33
|
+
validateAliasUniqueness(config.allowedWriteJoins, 'allowedWriteJoins');
|
|
34
|
+
validateComputedFields(config);
|
|
32
35
|
return config;
|
|
33
36
|
}
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
function validateComputedFields(config) {
|
|
38
|
+
const computed = config.computedFields;
|
|
39
|
+
if (!computed)
|
|
40
|
+
return;
|
|
41
|
+
const schemaFields = Object.keys(config.Schema.fields);
|
|
42
|
+
const extraKeys = Object.keys(config.extraFilters || {});
|
|
43
|
+
for (const name of Object.keys(computed)) {
|
|
44
|
+
if (schemaFields.includes(name)) {
|
|
45
|
+
throw new Error(`defineTable: computedFields name '${name}' collides with a schema field on ` +
|
|
46
|
+
`table '${config.Schema.tableName}'. Choose a different name.`);
|
|
47
|
+
}
|
|
48
|
+
if (extraKeys.includes(name)) {
|
|
49
|
+
throw new Error(`defineTable: computedFields name '${name}' collides with an extraFilters key on ` +
|
|
50
|
+
`table '${config.Schema.tableName}'. Choose a different name.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function validateAliasUniqueness(joins, label) {
|
|
55
|
+
if (!joins?.length)
|
|
56
|
+
return;
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
for (const j of joins) {
|
|
59
|
+
if (seen.has(j.alias)) {
|
|
60
|
+
throw new Error(`defineTable: duplicate alias '${j.alias}' in ${label}. ` +
|
|
61
|
+
`When omitted, alias defaults to joinSchema.tableName — ` +
|
|
62
|
+
`declare an explicit alias to disambiguate.`);
|
|
63
|
+
}
|
|
64
|
+
seen.add(j.alias);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function buildRelation(mainSchema, mainField, joinSchema, joinField, options) {
|
|
68
|
+
return {
|
|
69
|
+
joinSchema,
|
|
70
|
+
joinField,
|
|
71
|
+
mainField,
|
|
72
|
+
alias: options?.alias ?? joinSchema.tableName,
|
|
73
|
+
selection: options?.selection ?? '*',
|
|
74
|
+
unique: options?.unique ?? false,
|
|
75
|
+
};
|
|
36
76
|
}
|
|
37
77
|
export function buildUpsertRule(schema, columns) {
|
|
38
78
|
return [schema, columns];
|
package/dist/lib/tenant.d.ts
CHANGED
|
@@ -15,5 +15,35 @@ export declare function buildTenantDeleteWhere(db: QueryClient, tableName: strin
|
|
|
15
15
|
where: string;
|
|
16
16
|
values: unknown[];
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Mutates `fields` in-place: removes the tenant column from a SET payload (direct scopes only).
|
|
20
|
+
* No-op for indirect or no scope.
|
|
21
|
+
*/
|
|
18
22
|
export declare function stripTenantColumn(fields: Record<string, unknown>, scope: TenantScope): void;
|
|
23
|
+
/**
|
|
24
|
+
* For insert/bulk-upsert: enforce tenant on records that are about to be written.
|
|
25
|
+
* For direct scopes, mutates each record in-place to inject/validate the tenant column.
|
|
26
|
+
* For indirect scopes, batch-validates the FK values against the tenant scope.
|
|
27
|
+
* Throws 400 (ambiguous tenant) or 403 (mismatch) on violation. No-op when `tenant` is undefined.
|
|
28
|
+
*/
|
|
29
|
+
export declare function enforceTenantOnWrites(db: QueryClient, tenant: TenantContext | undefined, records: Record<string, unknown>[]): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* For update: builds the optional `extraCondition` ConditionBuilder for direct tenants.
|
|
32
|
+
* Returns undefined for indirect or no-tenant scenarios — those are handled separately
|
|
33
|
+
* (indirect uses pre-check via `assertTenantOwnership`).
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildTenantUpdateExtra(tenant: TenantContext | undefined): ConditionBuilder | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* For update with indirect tenant: pre-check ownership via `SELECT 1 ... INNER JOIN ... LIMIT 1`.
|
|
38
|
+
* Throws 404 if the record either does not exist or does not belong to the tenant.
|
|
39
|
+
* No-op for direct or no-tenant — those are enforced via `extraCondition` in the UPDATE itself.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assertTenantOwnership(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string, pkValue: ConditionValue): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Assert that EVERY pk in `ids` exists and belongs to the tenant, for both direct and indirect
|
|
44
|
+
* scopes. Throws 404 if any id is missing or not owned. No-op when `tenant` is undefined or `ids`
|
|
45
|
+
* is empty. Used by the delete engines to enforce tenant ownership BEFORE running a `beforeDelete`/
|
|
46
|
+
* `beforeBulkDelete` hook, so user code never runs against rows the caller cannot access.
|
|
47
|
+
*/
|
|
48
|
+
export declare function assertTenantOwnsAll(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string, ids: ConditionValue[]): Promise<void>;
|
|
19
49
|
//# sourceMappingURL=tenant.d.ts.map
|
package/dist/lib/tenant.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/lib/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/lib/tenant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAE/G,OAAO,KAAK,EACV,MAAM,EACN,mBAAmB,EACnB,QAAQ,EACR,WAAW,EACX,mBAAmB,EACnB,aAAa,EACd,MAAM,aAAa,CAAC;AAMrB,wBAAsB,aAAa,CACjC,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CASpC;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,gBAAgB,CAclB;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,aAAa,EAAE,MAAM,GACpB,MAAM,CAMR;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,QAAQ,EAAE,GACpB,IAAI,CAiBN;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,QAAQ,EAAE,EACrB,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,GAAG,cAAc,EAAE,EACrD,MAAM,EAAE,aAAa,GACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAsBtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,KAAK,EAAE,WAAW,GACjB,IAAI,CAGN;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,gBAAgB,GAAG,SAAS,CAM9B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,cAAc,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|