fastify-auto-sqlapi 0.1.2 → 0.1.3
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_BACKEND.md +35 -1
- package/README.md +65 -4
- package/dist/bin/generate-schema.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/adapters/mysql-adapter.d.ts +4 -0
- package/dist/lib/adapters/mysql-adapter.d.ts.map +1 -1
- package/dist/lib/adapters/mysql-adapter.js +28 -17
- package/dist/lib/adapters/pg-adapter.d.ts +4 -0
- package/dist/lib/adapters/pg-adapter.d.ts.map +1 -1
- package/dist/lib/adapters/pg-adapter.js +18 -7
- package/dist/lib/cli/mysql-introspect.d.ts.map +1 -1
- package/dist/lib/cli/mysql-introspect.js +3 -1
- package/dist/lib/cli/pg-introspect.d.ts.map +1 -1
- package/dist/lib/cli/pg-introspect.js +13 -4
- package/dist/lib/cli/schema-codegen.d.ts +2 -1
- package/dist/lib/cli/schema-codegen.d.ts.map +1 -1
- package/dist/lib/cli/schema-codegen.js +17 -3
- package/dist/lib/cli/tables-codegen.d.ts +2 -0
- package/dist/lib/cli/tables-codegen.d.ts.map +1 -1
- package/dist/lib/cli/tables-codegen.js +43 -12
- package/dist/lib/db.d.ts +17 -0
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +47 -0
- package/dist/lib/engine/bulk/bulk-delete.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-delete.js +25 -8
- package/dist/lib/engine/bulk/bulk-upsert.d.ts.map +1 -1
- package/dist/lib/engine/bulk/bulk-upsert.js +9 -8
- package/dist/lib/engine/rest/delete.d.ts.map +1 -1
- package/dist/lib/engine/rest/delete.js +9 -5
- package/dist/lib/engine/rest/get.js +1 -1
- package/dist/lib/engine/rest/insert.d.ts.map +1 -1
- package/dist/lib/engine/rest/insert.js +38 -33
- package/dist/lib/engine/rest/update.d.ts.map +1 -1
- package/dist/lib/engine/rest/update.js +69 -55
- package/dist/lib/engine/search/search.d.ts.map +1 -1
- package/dist/lib/engine/search/search.js +49 -19
- package/dist/lib/table-helpers.d.ts.map +1 -1
- package/dist/lib/table-helpers.js +10 -9
- package/dist/lib/tenant.d.ts +2 -2
- package/dist/lib/tenant.d.ts.map +1 -1
- package/dist/lib/tenant.js +11 -9
- package/dist/routes/auto/bulk-delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-delete.routes.js +1 -0
- package/dist/routes/auto/bulk-upsert.routes.d.ts.map +1 -1
- package/dist/routes/auto/bulk-upsert.routes.js +1 -0
- package/dist/routes/auto/delete.routes.d.ts.map +1 -1
- package/dist/routes/auto/delete.routes.js +1 -0
- package/dist/routes/auto/get.routes.d.ts.map +1 -1
- package/dist/routes/auto/get.routes.js +1 -0
- package/dist/routes/auto/insert.routes.d.ts.map +1 -1
- package/dist/routes/auto/insert.routes.js +1 -0
- package/dist/routes/auto/route-helpers.d.ts +3 -1
- package/dist/routes/auto/route-helpers.d.ts.map +1 -1
- package/dist/routes/auto/route-helpers.js +3 -0
- package/dist/routes/auto/search.routes.d.ts.map +1 -1
- package/dist/routes/auto/search.routes.js +1 -0
- package/dist/routes/auto/update.routes.d.ts.map +1 -1
- package/dist/routes/auto/update.routes.js +1 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/db.d.ts +11 -0
- package/dist/types/db.d.ts.map +1 -1
- package/dist/types/schema.d.ts +2 -0
- package/dist/types/schema.d.ts.map +1 -1
- package/dist/types/table.d.ts +40 -2
- package/dist/types/table.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -50,6 +50,21 @@ function resolveFieldRef(field, schema, tableConf, db, alias) {
|
|
|
50
50
|
err400(`Unknown field: ${field}`);
|
|
51
51
|
}
|
|
52
52
|
// ─── Join lookup ────────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Tenant-scope a join side-query. When the joined table declares its own `tenantScope`,
|
|
55
|
+
* appends the tenant condition to `cb` (direct: `col IN ids`; indirect: condition on the
|
|
56
|
+
* through table) and, for indirect scopes, pushes the INNER JOIN clause into `joins`.
|
|
57
|
+
* No-op without a tenant context (admin) or when the join table is not tenant-scoped.
|
|
58
|
+
*/
|
|
59
|
+
function appendJoinTenantScope(db, joinTableConf, tenant, joinTableName, cb, joins) {
|
|
60
|
+
const scope = joinTableConf?.tenantScope;
|
|
61
|
+
if (!tenant || !scope)
|
|
62
|
+
return;
|
|
63
|
+
cb.append(buildTenantCondition(db, scope, tenant.ids));
|
|
64
|
+
if ('through' in scope) {
|
|
65
|
+
joins?.push(buildTenantJoin(db, scope, joinTableName));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
53
68
|
function findJoinByAlias(tableConf, alias) {
|
|
54
69
|
return tableConf.allowedReadJoins?.find((j) => j.alias === alias);
|
|
55
70
|
}
|
|
@@ -219,7 +234,7 @@ function buildLeftJoinClauses(db, dbTables, tableConf, aliasesNeedingJoin, joinL
|
|
|
219
234
|
// Note: extraFilters declared on joinTableConf are not supported here for
|
|
220
235
|
// joinLeft (they would require alias-aware handlers); only schema fields
|
|
221
236
|
// and computed fields apply.
|
|
222
|
-
const cb = new ConditionBuilder('AND');
|
|
237
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
223
238
|
const joinTableConf = dbTables[joinSchema.tableName];
|
|
224
239
|
const computed = joinTableConf?.computedFields;
|
|
225
240
|
if (ref.filters) {
|
|
@@ -328,7 +343,7 @@ async function buildPagination(db, tableConf, where, values, paginator, extraJoi
|
|
|
328
343
|
};
|
|
329
344
|
}
|
|
330
345
|
// ─── joinMultiple (virtual fetch, child rows in side query) ─
|
|
331
|
-
async function executeJoinMultiple(db, dbTables, tableConf, mainResults, joinMultiple) {
|
|
346
|
+
async function executeJoinMultiple(db, dbTables, tableConf, mainResults, joinMultiple, tenant) {
|
|
332
347
|
const result = {};
|
|
333
348
|
for (const [alias, ref] of Object.entries(joinMultiple)) {
|
|
334
349
|
const joinDef = requireJoin(tableConf, alias, false);
|
|
@@ -342,6 +357,8 @@ async function executeJoinMultiple(db, dbTables, tableConf, mainResults, joinMul
|
|
|
342
357
|
const cb = buildJoinRefCondition(joinTableConf, joinSchema, ref || {}, db);
|
|
343
358
|
const fkCol = joinSchema.col(joinField);
|
|
344
359
|
cb.isIn(db.qi(fkCol), ids);
|
|
360
|
+
const tenantJoins = [];
|
|
361
|
+
appendJoinTenantScope(db, joinTableConf, tenant, joinSchema.tableName, cb, tenantJoins);
|
|
345
362
|
let where = cb.build(1, db.ph);
|
|
346
363
|
let values = cb.getValues();
|
|
347
364
|
// Side-channel: computed-field clauses on the join table
|
|
@@ -356,17 +373,19 @@ async function executeJoinMultiple(db, dbTables, tableConf, mainResults, joinMul
|
|
|
356
373
|
columns,
|
|
357
374
|
where,
|
|
358
375
|
values,
|
|
376
|
+
joins: tenantJoins.length > 0 ? tenantJoins : undefined,
|
|
359
377
|
});
|
|
360
378
|
result[alias] = mapRowsToCamelCase(rows, joinSchema);
|
|
361
379
|
}
|
|
362
380
|
return result;
|
|
363
381
|
}
|
|
364
382
|
// ─── joinLeft (parent fetch via PK IN side query) ───────────
|
|
365
|
-
async function executeJoinLeft(db, tableConf, mainResults, joinLeft) {
|
|
383
|
+
async function executeJoinLeft(db, dbTables, tableConf, mainResults, joinLeft, tenant) {
|
|
366
384
|
const result = {};
|
|
367
385
|
for (const [alias, ref] of Object.entries(joinLeft)) {
|
|
368
386
|
const joinDef = requireJoin(tableConf, alias, true);
|
|
369
387
|
const { joinSchema, joinField, mainField, selection: defaultSelection } = joinDef;
|
|
388
|
+
const joinTableConf = dbTables[joinSchema.tableName];
|
|
370
389
|
// For joinLeft (N:1), mainField on main is the FK pointing to joinField (PK) on parent.
|
|
371
390
|
// We collect the FK values from the main results and look up parents by their PK.
|
|
372
391
|
const ids = collectIds(mainResults, mainField);
|
|
@@ -375,8 +394,10 @@ async function executeJoinLeft(db, tableConf, mainResults, joinLeft) {
|
|
|
375
394
|
continue;
|
|
376
395
|
}
|
|
377
396
|
const fkCol = joinSchema.col(joinField);
|
|
378
|
-
const cb = new ConditionBuilder('AND');
|
|
397
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
379
398
|
cb.isIn(db.qi(fkCol), ids);
|
|
399
|
+
const tenantJoins = [];
|
|
400
|
+
appendJoinTenantScope(db, joinTableConf, tenant, joinSchema.tableName, cb, tenantJoins);
|
|
380
401
|
const where = cb.build(1, db.ph);
|
|
381
402
|
const values = cb.getValues();
|
|
382
403
|
const selection = ref?.selection ?? defaultSelection;
|
|
@@ -386,6 +407,7 @@ async function executeJoinLeft(db, tableConf, mainResults, joinLeft) {
|
|
|
386
407
|
columns,
|
|
387
408
|
where,
|
|
388
409
|
values,
|
|
410
|
+
joins: tenantJoins.length > 0 ? tenantJoins : undefined,
|
|
389
411
|
});
|
|
390
412
|
result[alias] = mapRowsToCamelCase(rows, joinSchema);
|
|
391
413
|
}
|
|
@@ -412,7 +434,7 @@ function buildByExpression(by, joinSchema, joinTableConf, db) {
|
|
|
412
434
|
err400(`Unknown field: ${by}`);
|
|
413
435
|
}
|
|
414
436
|
// ─── joinGroup (aggregations) ───────────────────────────────
|
|
415
|
-
async function executeJoinGroup(db, dbTables, tableConf, mainResults, joinGroup) {
|
|
437
|
+
async function executeJoinGroup(db, dbTables, tableConf, mainResults, joinGroup, tenant) {
|
|
416
438
|
const result = {};
|
|
417
439
|
for (const [alias, groupReq] of Object.entries(joinGroup)) {
|
|
418
440
|
const joinDef = requireJoin(tableConf, alias, false);
|
|
@@ -454,6 +476,8 @@ async function executeJoinGroup(db, dbTables, tableConf, mainResults, joinGroup)
|
|
|
454
476
|
const cb = buildJoinRefCondition(joinTableConf, joinSchema, groupRef, db);
|
|
455
477
|
const fkCol = joinSchema.col(joinField);
|
|
456
478
|
cb.isIn(db.qi(fkCol), ids);
|
|
479
|
+
const tenantJoins = [];
|
|
480
|
+
appendJoinTenantScope(db, joinTableConf, tenant, joinSchema.tableName, cb, tenantJoins);
|
|
457
481
|
let where = cb.build(1, db.ph);
|
|
458
482
|
let values = cb.getValues();
|
|
459
483
|
// Side-channel: computed-field clauses on the join table
|
|
@@ -462,7 +486,8 @@ async function executeJoinGroup(db, dbTables, tableConf, mainResults, joinGroup)
|
|
|
462
486
|
({ where, values } = appendComputedConditions(where, values, computedClauses, db));
|
|
463
487
|
}
|
|
464
488
|
const groupBy = groupByParts.length > 0 ? `GROUP BY ${groupByParts.join(', ')}` : '';
|
|
465
|
-
const
|
|
489
|
+
const fromJoins = tenantJoins.length > 0 ? ` ${tenantJoins.join(' ')}` : '';
|
|
490
|
+
const sql = `SELECT ${selectParts.join(', ')} FROM ${db.qi(joinSchema.tableName)}${fromJoins} WHERE ${where} ${groupBy}`;
|
|
466
491
|
const queryResult = await db.query(sql, values);
|
|
467
492
|
const rows = queryResult.rows;
|
|
468
493
|
const formatted = {};
|
|
@@ -520,8 +545,8 @@ function dispatchConditionMethod(cb, method, colOrExpr, params) {
|
|
|
520
545
|
}
|
|
521
546
|
function buildJoinRefCondition(joinTableConf, joinSchema, ref, db) {
|
|
522
547
|
const cb = (ref.filters && joinTableConf)
|
|
523
|
-
? joinTableConf.filters(ref.filters)
|
|
524
|
-
: new ConditionBuilder('AND');
|
|
548
|
+
? joinTableConf.filters(ref.filters, db.cbDialect)
|
|
549
|
+
: new ConditionBuilder('AND', db.cbDialect);
|
|
525
550
|
if (ref.conditions?.length) {
|
|
526
551
|
for (const c of ref.conditions) {
|
|
527
552
|
if (!ALLOWED_SET.has(c.method)) {
|
|
@@ -641,7 +666,7 @@ function appendComputedConditions(currentWhere, currentValues, clauses, db) {
|
|
|
641
666
|
// Append the computed's own bound values first; the expr placeholders
|
|
642
667
|
// (if any) reference them via stable indices set by the consumer.
|
|
643
668
|
values = [...values, ...c.values];
|
|
644
|
-
const tmpCb = new ConditionBuilder('AND');
|
|
669
|
+
const tmpCb = new ConditionBuilder('AND', db.cbDialect);
|
|
645
670
|
dispatchConditionMethod(tmpCb, c.method, c.expr, c.params);
|
|
646
671
|
const startIdx = values.length + 1;
|
|
647
672
|
const clauseSql = tmpCb.build(startIdx, db.ph);
|
|
@@ -666,7 +691,7 @@ function appendAggConditions(currentWhere, currentValues, conditions, db, dbTabl
|
|
|
666
691
|
const [alias, fn, field] = parts;
|
|
667
692
|
const { expr, values: exprValues } = buildAggOrderExpr(db, dbTables, tableConf, alias, fn, field, joinGroup, values.length + 1);
|
|
668
693
|
values = [...values, ...exprValues];
|
|
669
|
-
const tmpCb = new ConditionBuilder('AND');
|
|
694
|
+
const tmpCb = new ConditionBuilder('AND', db.cbDialect);
|
|
670
695
|
dispatchConditionMethod(tmpCb, c.method, expr, c.params);
|
|
671
696
|
const startIdx = values.length + 1;
|
|
672
697
|
const clause = tmpCb.build(startIdx, db.ph);
|
|
@@ -676,7 +701,7 @@ function appendAggConditions(currentWhere, currentValues, conditions, db, dbTabl
|
|
|
676
701
|
return { where, values };
|
|
677
702
|
}
|
|
678
703
|
// ─── joinMustExist (EXISTS subquery filter on main) ─────────
|
|
679
|
-
function buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, currentWhere, currentValues) {
|
|
704
|
+
function buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, currentWhere, currentValues, tenant) {
|
|
680
705
|
let where = currentWhere;
|
|
681
706
|
const values = [...currentValues];
|
|
682
707
|
for (const [alias, ref] of Object.entries(joinMustExist)) {
|
|
@@ -685,6 +710,8 @@ function buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, curre
|
|
|
685
710
|
const joinTableConf = dbTables[joinSchema.tableName];
|
|
686
711
|
const refs = extractJoinRefs(db, tableConf, joinDef);
|
|
687
712
|
const filterCondition = buildJoinRefCondition(joinTableConf, joinSchema, ref, db);
|
|
713
|
+
const tenantJoins = [];
|
|
714
|
+
appendJoinTenantScope(db, joinTableConf, tenant, joinSchema.tableName, filterCondition, tenantJoins);
|
|
688
715
|
const startIdx = values.length + 1;
|
|
689
716
|
let filterWhere = filterCondition.build(startIdx, db.ph);
|
|
690
717
|
let filterVals = [...filterCondition.getValues()];
|
|
@@ -699,10 +726,13 @@ function buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, curre
|
|
|
699
726
|
filterVals = cvalues.slice(values.length);
|
|
700
727
|
filterWhere = cwhere;
|
|
701
728
|
}
|
|
729
|
+
// Qualify the FK with the join table: the EXISTS FROM may include the tenant
|
|
730
|
+
// through-join, so a bare column could become ambiguous.
|
|
702
731
|
const innerWhere = filterWhere
|
|
703
|
-
? `${refs.fkCol} = ${refs.mainTable}.${refs.mainCol} AND ${filterWhere}`
|
|
704
|
-
: `${refs.fkCol} = ${refs.mainTable}.${refs.mainCol}`;
|
|
705
|
-
|
|
732
|
+
? `${refs.joinTable}.${refs.fkCol} = ${refs.mainTable}.${refs.mainCol} AND ${filterWhere}`
|
|
733
|
+
: `${refs.joinTable}.${refs.fkCol} = ${refs.mainTable}.${refs.mainCol}`;
|
|
734
|
+
const existsJoins = tenantJoins.length > 0 ? ` ${tenantJoins.join(' ')}` : '';
|
|
735
|
+
where += ` AND EXISTS (SELECT 1 FROM ${refs.joinTable}${existsJoins} WHERE ${innerWhere})`;
|
|
706
736
|
values.push(...filterVals);
|
|
707
737
|
}
|
|
708
738
|
return { where, values };
|
|
@@ -724,7 +754,7 @@ export async function searchEngine(dbTables, params) {
|
|
|
724
754
|
for (const a of Object.keys(joinLeft))
|
|
725
755
|
requireJoin(tableConf, a, true);
|
|
726
756
|
// Build main condition
|
|
727
|
-
const condition = tableConf.filters(filters || {});
|
|
757
|
+
const condition = tableConf.filters(filters || {}, db.cbDialect);
|
|
728
758
|
// Filters that target computed fields (declared on tableConf.computedFields)
|
|
729
759
|
// are applied via the side-channel pattern further down.
|
|
730
760
|
let computedFilterClauses = [];
|
|
@@ -755,7 +785,7 @@ export async function searchEngine(dbTables, params) {
|
|
|
755
785
|
}
|
|
756
786
|
// joinMustExist (EXISTS)
|
|
757
787
|
if (joinMustExist && Object.keys(joinMustExist).length > 0) {
|
|
758
|
-
({ where, values } = buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, where, values));
|
|
788
|
+
({ where, values } = buildJoinMustExistClauses(db, dbTables, tableConf, joinMustExist, where, values, tenant));
|
|
759
789
|
}
|
|
760
790
|
// Aggregation conditions (HAVING-style)
|
|
761
791
|
if (conditions?.length) {
|
|
@@ -805,13 +835,13 @@ export async function searchEngine(dbTables, params) {
|
|
|
805
835
|
}
|
|
806
836
|
const result = { main };
|
|
807
837
|
if (joinMultiple && Object.keys(joinMultiple).length > 0) {
|
|
808
|
-
result.joinMultiple = await executeJoinMultiple(db, dbTables, tableConf, main, joinMultiple);
|
|
838
|
+
result.joinMultiple = await executeJoinMultiple(db, dbTables, tableConf, main, joinMultiple, tenant);
|
|
809
839
|
}
|
|
810
840
|
if (joinLeft && Object.keys(joinLeft).length > 0) {
|
|
811
|
-
result.joinLeft = await executeJoinLeft(db, tableConf, main, joinLeft);
|
|
841
|
+
result.joinLeft = await executeJoinLeft(db, dbTables, tableConf, main, joinLeft, tenant);
|
|
812
842
|
}
|
|
813
843
|
if (joinGroup && Object.keys(joinGroup).length > 0) {
|
|
814
|
-
result.joinGroup = await executeJoinGroup(db, dbTables, tableConf, main, joinGroup);
|
|
844
|
+
result.joinGroup = await executeJoinGroup(db, dbTables, tableConf, main, joinGroup, tenant);
|
|
815
845
|
}
|
|
816
846
|
if (pagination) {
|
|
817
847
|
result.pagination = pagination;
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"table-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/table-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,yBAAyB,EAAiC,MAAM,wBAAwB,CAAC;AACzH,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;AAarB,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"}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { ConditionBuilder } from 'node-condition-builder';
|
|
2
2
|
import { getDialect } from './dialect.js';
|
|
3
|
-
// Quote an identifier using the
|
|
4
|
-
// Needed so that DB columns with uppercase letters
|
|
5
|
-
// are preserved on PostgreSQL (which folds unquoted
|
|
6
|
-
// and on MySQL (which is case-sensitive on Linux
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
// Quote an identifier using the given ConditionBuilder dialect (or the global
|
|
4
|
+
// default when not provided). Needed so that DB columns with uppercase letters
|
|
5
|
+
// (e.g. betterauth "userId") are preserved on PostgreSQL (which folds unquoted
|
|
6
|
+
// identifiers to lowercase) and on MySQL (which is case-sensitive on Linux
|
|
7
|
+
// filesystems).
|
|
8
|
+
function qi(field, dialect) {
|
|
9
|
+
return getDialect(dialect ?? ConditionBuilder.DIALECT).qi(field);
|
|
9
10
|
}
|
|
10
11
|
export function exportTableInfo(Schema, extraFilters = {}, extendedCondition) {
|
|
11
|
-
const filters = (filterValues) => {
|
|
12
|
-
const condition = new ConditionBuilder('AND');
|
|
12
|
+
const filters = (filterValues, dialect) => {
|
|
13
|
+
const condition = new ConditionBuilder('AND', dialect);
|
|
13
14
|
// Only auto-match real schema fields (DB columns)
|
|
14
15
|
for (const field of Object.keys(Schema.fields)) {
|
|
15
16
|
if (field in filterValues && filterValues[field] !== null && filterValues[field] !== undefined) {
|
|
16
|
-
condition.isEqual(qi(Schema.col(field)), filterValues[field]);
|
|
17
|
+
condition.isEqual(qi(Schema.col(field), dialect), filterValues[field]);
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
// extraFilters are handled exclusively by extendedCondition
|
package/dist/lib/tenant.d.ts
CHANGED
|
@@ -32,13 +32,13 @@ export declare function enforceTenantOnWrites(db: QueryClient, tenant: TenantCon
|
|
|
32
32
|
* Returns undefined for indirect or no-tenant scenarios — those are handled separately
|
|
33
33
|
* (indirect uses pre-check via `assertTenantOwnership`).
|
|
34
34
|
*/
|
|
35
|
-
export declare function buildTenantUpdateExtra(tenant: TenantContext | undefined): ConditionBuilder | undefined;
|
|
35
|
+
export declare function buildTenantUpdateExtra(db: QueryClient, tenant: TenantContext | undefined): ConditionBuilder | undefined;
|
|
36
36
|
/**
|
|
37
37
|
* For update with indirect tenant: pre-check ownership via `SELECT 1 ... INNER JOIN ... LIMIT 1`.
|
|
38
38
|
* Throws 404 if the record either does not exist or does not belong to the tenant.
|
|
39
39
|
* No-op for direct or no-tenant — those are enforced via `extraCondition` in the UPDATE itself.
|
|
40
40
|
*/
|
|
41
|
-
export declare function assertTenantOwnership(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string, pkValue: ConditionValue): Promise<void>;
|
|
41
|
+
export declare function assertTenantOwnership(db: QueryClient, tenant: TenantContext | undefined, tableName: string, pkCol: string | string[], pkValue: ConditionValue | ConditionValue[]): Promise<void>;
|
|
42
42
|
/**
|
|
43
43
|
* Assert that EVERY pk in `ids` exists and belongs to the tenant, for both direct and indirect
|
|
44
44
|
* scopes. Throws 404 if any id is missing or not owned. No-op when `tenant` is undefined or `ids`
|
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;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,
|
|
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,EAAE,EAAE,WAAW,EACf,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,GAAG,MAAM,EAAE,EACxB,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,GACzC,OAAO,CAAC,IAAI,CAAC,CAYf;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"}
|
package/dist/lib/tenant.js
CHANGED
|
@@ -24,7 +24,7 @@ export function buildTenantCondition(db, scope, tenantIds) {
|
|
|
24
24
|
else {
|
|
25
25
|
qualifier = db.qi(col);
|
|
26
26
|
}
|
|
27
|
-
const cb = new ConditionBuilder('AND');
|
|
27
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
28
28
|
cb.isIn(qualifier, tenantIds);
|
|
29
29
|
return cb;
|
|
30
30
|
}
|
|
@@ -59,7 +59,7 @@ export async function validateTenantFK(db, scope, tenantIds, fkValues) {
|
|
|
59
59
|
const throughTable = scope.through.schema.tableName;
|
|
60
60
|
const foreignField = scope.through.foreignField;
|
|
61
61
|
const tenantCol = scope.column;
|
|
62
|
-
const cb = new ConditionBuilder('AND');
|
|
62
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
63
63
|
cb.isIn(db.qi(foreignField), uniqueFKs);
|
|
64
64
|
cb.isNotIn(db.qi(tenantCol), tenantIds);
|
|
65
65
|
const where = cb.build(1, db.ph);
|
|
@@ -77,7 +77,7 @@ export async function validateTenantFK(db, scope, tenantIds, fkValues) {
|
|
|
77
77
|
*/
|
|
78
78
|
export function buildTenantDeleteWhere(db, tableName, pkCol, pkValue, tenant) {
|
|
79
79
|
if (isIndirect(tenant.scope)) {
|
|
80
|
-
const innerCb = new ConditionBuilder('AND');
|
|
80
|
+
const innerCb = new ConditionBuilder('AND', db.cbDialect);
|
|
81
81
|
innerCb.isIn(`${db.qi(tableName)}.${db.qi(pkCol)}`, (Array.isArray(pkValue) ? pkValue : [pkValue]));
|
|
82
82
|
innerCb.append(buildTenantCondition(db, tenant.scope, tenant.ids));
|
|
83
83
|
const innerWhere = innerCb.build(1, db.ph);
|
|
@@ -86,7 +86,7 @@ export function buildTenantDeleteWhere(db, tableName, pkCol, pkValue, tenant) {
|
|
|
86
86
|
const where = `${db.qi(pkCol)} IN (SELECT ${db.qi(tableName)}.${db.qi(pkCol)} FROM ${db.qi(tableName)} ${joinSql} WHERE ${innerWhere})`;
|
|
87
87
|
return { where, values };
|
|
88
88
|
}
|
|
89
|
-
const cb = new ConditionBuilder('AND');
|
|
89
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
90
90
|
if (Array.isArray(pkValue)) {
|
|
91
91
|
cb.isIn(db.qi(pkCol), pkValue);
|
|
92
92
|
}
|
|
@@ -129,10 +129,10 @@ export async function enforceTenantOnWrites(db, tenant, records) {
|
|
|
129
129
|
* Returns undefined for indirect or no-tenant scenarios — those are handled separately
|
|
130
130
|
* (indirect uses pre-check via `assertTenantOwnership`).
|
|
131
131
|
*/
|
|
132
|
-
export function buildTenantUpdateExtra(tenant) {
|
|
132
|
+
export function buildTenantUpdateExtra(db, tenant) {
|
|
133
133
|
if (!tenant || isIndirect(tenant.scope))
|
|
134
134
|
return undefined;
|
|
135
|
-
const cb = new ConditionBuilder('AND');
|
|
135
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
136
136
|
if (tenant.ids.length === 1)
|
|
137
137
|
cb.isEqual(tenant.scope.column, tenant.ids[0]);
|
|
138
138
|
else
|
|
@@ -147,8 +147,10 @@ export function buildTenantUpdateExtra(tenant) {
|
|
|
147
147
|
export async function assertTenantOwnership(db, tenant, tableName, pkCol, pkValue) {
|
|
148
148
|
if (!tenant || !isIndirect(tenant.scope))
|
|
149
149
|
return;
|
|
150
|
-
const cb = new ConditionBuilder('AND');
|
|
151
|
-
|
|
150
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
151
|
+
const cols = Array.isArray(pkCol) ? pkCol : [pkCol];
|
|
152
|
+
const vals = Array.isArray(pkValue) ? pkValue : [pkValue];
|
|
153
|
+
cols.forEach((c, i) => cb.isEqual(`${db.qi(tableName)}.${db.qi(c)}`, vals[i]));
|
|
152
154
|
cb.append(buildTenantCondition(db, tenant.scope, tenant.ids));
|
|
153
155
|
const sql = `SELECT 1 FROM ${db.qi(tableName)} ${buildTenantJoin(db, tenant.scope, tableName)} WHERE ${cb.build(1, db.ph)} LIMIT 1`;
|
|
154
156
|
const r = await db.query(sql, cb.getValues());
|
|
@@ -166,7 +168,7 @@ export async function assertTenantOwnsAll(db, tenant, tableName, pkCol, ids) {
|
|
|
166
168
|
if (!tenant || !ids.length)
|
|
167
169
|
return;
|
|
168
170
|
const qualifiedPk = `${db.qi(tableName)}.${db.qi(pkCol)}`;
|
|
169
|
-
const cb = new ConditionBuilder('AND');
|
|
171
|
+
const cb = new ConditionBuilder('AND', db.cbDialect);
|
|
170
172
|
cb.isIn(qualifiedPk, ids);
|
|
171
173
|
cb.append(buildTenantCondition(db, tenant.scope, tenant.ids));
|
|
172
174
|
const join = isIndirect(tenant.scope) ? ` ${buildTenantJoin(db, tenant.scope, tableName)}` : '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"bulk-delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -3,6 +3,7 @@ import { primaryAsString } from '../../types.js';
|
|
|
3
3
|
import { registerForAllTables } from './route-helpers.js';
|
|
4
4
|
export default async function bulkDeleteRoutes(fastify, options) {
|
|
5
5
|
await registerForAllTables(fastify, options, {
|
|
6
|
+
operation: 'bulkDelete',
|
|
6
7
|
method: 'POST',
|
|
7
8
|
url: (tc) => `/bulk/${tc.Schema.tableName}/delete`,
|
|
8
9
|
successStatus: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk-upsert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-upsert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,gBAAgB,CAAC;AAE1E,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"bulk-upsert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/bulk-upsert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,gBAAgB,CAAC;AAE1E,wBAA8B,gBAAgB,CAC5C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -2,6 +2,7 @@ import { BulkUpsertTableBody, BulkUpsertTableResponse } from '../../lib/schema/b
|
|
|
2
2
|
import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
|
|
3
3
|
export default async function bulkUpsertRoutes(fastify, options) {
|
|
4
4
|
await registerForAllTables(fastify, options, {
|
|
5
|
+
operation: 'bulkUpsert',
|
|
5
6
|
method: 'PUT',
|
|
6
7
|
url: (tc) => `/bulk/${tc.Schema.tableName}`,
|
|
7
8
|
successStatus: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"delete.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/delete.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAoBf"}
|
|
@@ -3,6 +3,7 @@ import { primaryAsString } from '../../types.js';
|
|
|
3
3
|
import { registerForAllTables } from './route-helpers.js';
|
|
4
4
|
export default async function deleteRoutes(fastify, options) {
|
|
5
5
|
await registerForAllTables(fastify, options, {
|
|
6
|
+
operation: 'delete',
|
|
6
7
|
method: 'DELETE',
|
|
7
8
|
url: (tc) => `/rest/${tc.Schema.tableName}/:id`,
|
|
8
9
|
successStatus: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/get.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,SAAS,CACrC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"get.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/get.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,SAAS,CACrC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -2,6 +2,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
2
2
|
import { registerForAllTables } from './route-helpers.js';
|
|
3
3
|
export default async function getRoutes(fastify, options) {
|
|
4
4
|
await registerForAllTables(fastify, options, {
|
|
5
|
+
operation: 'get',
|
|
5
6
|
method: 'GET',
|
|
6
7
|
url: (tc) => `/rest/${tc.Schema.tableName}/:id`,
|
|
7
8
|
successStatus: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/insert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"insert.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/insert.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
|
@@ -2,6 +2,7 @@ import { InsertTableBody, InsertTableResponse } from '../../lib/schema/insert.js
|
|
|
2
2
|
import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
|
|
3
3
|
export default async function insertRoutes(fastify, options) {
|
|
4
4
|
await registerForAllTables(fastify, options, {
|
|
5
|
+
operation: 'insert',
|
|
5
6
|
method: 'POST',
|
|
6
7
|
url: (tc) => `/rest/${tc.Schema.tableName}`,
|
|
7
8
|
successStatus: 201,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
|
|
2
|
-
import type { ITable, SqlApiPluginOptions, DbTables } from '../../types.js';
|
|
2
|
+
import type { ITable, SqlApiPluginOptions, DbTables, TableOperation } from '../../types.js';
|
|
3
3
|
type RequestHook = (request: FastifyRequest, reply: FastifyReply) => Promise<void | FastifyReply>;
|
|
4
4
|
export declare function mergeOnRequests(options: SqlApiPluginOptions, tableConf: ITable): RequestHook[];
|
|
5
5
|
export declare function buildWriteDescription(action: string, tableName: string, tableConf: ITable): string;
|
|
@@ -10,6 +10,8 @@ interface RouteSchema {
|
|
|
10
10
|
response?: any;
|
|
11
11
|
}
|
|
12
12
|
export interface AutoRouteSpec {
|
|
13
|
+
/** Operation key matched against `ITable.operations` to decide whether to register the route. */
|
|
14
|
+
operation: TableOperation;
|
|
13
15
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
14
16
|
/** URL builder receiving the table configuration to read `Schema.tableName`. */
|
|
15
17
|
url: (tableConf: ITable) => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/route-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"route-helpers.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/route-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE5F,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;AAElG,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAE9F;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQlG;AAED,UAAU,WAAW;IAEnB,IAAI,CAAC,EAAE,GAAG,CAAC;IAEX,MAAM,CAAC,EAAE,GAAG,CAAC;IAEb,WAAW,CAAC,EAAE,GAAG,CAAC;IAElB,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC1C,gFAAgF;IAChF,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,aAAa,EAAE,GAAG,GAAG,GAAG,CAAC;IACzB,wIAAwI;IACxI,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,WAAW,CAAC;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,KAAK,MAAM,CAAC;IACpF;2EACuE;IACvE,MAAM,EAAE,CACN,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,OAAO,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -18,6 +18,9 @@ export function buildWriteDescription(action, tableName, tableConf) {
|
|
|
18
18
|
export async function registerForAllTables(fastify, options, spec) {
|
|
19
19
|
const { DbTables } = options;
|
|
20
20
|
for (const [tableName, tableConf] of Object.entries(DbTables)) {
|
|
21
|
+
// operations acts as a whitelist; when omitted every operation is exposed.
|
|
22
|
+
if (tableConf.operations && !tableConf.operations.includes(spec.operation))
|
|
23
|
+
continue;
|
|
21
24
|
const schemas = spec.schemas(DbTables, tableName, tableConf);
|
|
22
25
|
// Only include schema keys that are actually defined: Fastify checks for key
|
|
23
26
|
// *presence* (not undefined value) to decide whether to emit FSTWRN001.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/search.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"search.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/search.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkDf"}
|
|
@@ -2,6 +2,7 @@ import { SearchTableBodyPost, SearchTableQueryString, SearchTableResponse } from
|
|
|
2
2
|
import { registerForAllTables } from './route-helpers.js';
|
|
3
3
|
export default async function searchRoutes(fastify, options) {
|
|
4
4
|
await registerForAllTables(fastify, options, {
|
|
5
|
+
operation: 'search',
|
|
5
6
|
method: 'POST',
|
|
6
7
|
url: (tc) => `/search/${tc.Schema.tableName}`,
|
|
7
8
|
successStatus: 200,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/update.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"update.routes.d.ts","sourceRoot":"","sources":["../../../src/routes/auto/update.routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,wBAA8B,YAAY,CACxC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAyBf"}
|
|
@@ -2,6 +2,7 @@ import { UpdateTableBody, UpdateTableResponse } from '../../lib/schema/update.js
|
|
|
2
2
|
import { registerForAllTables, buildWriteDescription } from './route-helpers.js';
|
|
3
3
|
export default async function updateRoutes(fastify, options) {
|
|
4
4
|
await registerForAllTables(fastify, options, {
|
|
5
|
+
operation: 'update',
|
|
5
6
|
method: 'PUT',
|
|
6
7
|
url: (tc) => `/rest/${tc.Schema.tableName}`,
|
|
7
8
|
successStatus: 200,
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -11,12 +11,18 @@ export interface ColumnInfo {
|
|
|
11
11
|
udt_name: string;
|
|
12
12
|
column_default: string | null;
|
|
13
13
|
is_nullable: string;
|
|
14
|
+
/** True when the column is part of the table's PRIMARY KEY (from information_schema). */
|
|
15
|
+
is_primary?: boolean;
|
|
16
|
+
/** True for auto-generated columns without a visible default (mysql AUTO_INCREMENT). */
|
|
17
|
+
is_auto_increment?: boolean;
|
|
14
18
|
}
|
|
15
19
|
export interface TableMap {
|
|
16
20
|
[schemaName: string]: {
|
|
17
21
|
name: string;
|
|
18
22
|
fields: Record<string, string>;
|
|
19
23
|
colMap: Record<string, string>;
|
|
24
|
+
/** PRIMARY KEY fields (camelCase), in table column order. Empty when unknown. */
|
|
25
|
+
primary: string[];
|
|
20
26
|
};
|
|
21
27
|
}
|
|
22
28
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/types/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/types/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/types/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wFAAwF;IACxF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,QAAQ;IACvB,CAAC,UAAU,EAAE,MAAM,GAAG;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/B,iFAAiF;QACjF,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;CACH"}
|
package/dist/types/db.d.ts
CHANGED
|
@@ -4,8 +4,19 @@ export interface SqlResult<T = Record<string, unknown>> {
|
|
|
4
4
|
affectedRows: number;
|
|
5
5
|
insertId?: number;
|
|
6
6
|
}
|
|
7
|
+
/** A dedicated connection checked out from a pool, used to run a transaction. */
|
|
8
|
+
export interface TransactionQueryable extends Queryable {
|
|
9
|
+
/** Return the connection to the pool. Always called, even on error. */
|
|
10
|
+
release(): void | Promise<void>;
|
|
11
|
+
}
|
|
7
12
|
export interface Queryable {
|
|
8
13
|
query<T = Record<string, unknown>>(text: string, values?: unknown[]): Promise<SqlResult<T>>;
|
|
14
|
+
/**
|
|
15
|
+
* Optional: check out a dedicated connection for `QueryClient.withTransaction`.
|
|
16
|
+
* When absent, `withTransaction` degrades to running its callback without
|
|
17
|
+
* transactional guarantees (legacy custom adapters keep working unchanged).
|
|
18
|
+
*/
|
|
19
|
+
connect?(): Promise<TransactionQueryable>;
|
|
9
20
|
}
|
|
10
21
|
export type DbRecordValue = string | number | boolean | null | Expression;
|
|
11
22
|
export type DbRecord = Record<string, DbRecordValue>;
|
package/dist/types/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/types/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/types/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,uEAAuE;IACvE,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,UAAU,CAAC;AAEf,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
package/dist/types/schema.d.ts
CHANGED
|
@@ -6,5 +6,7 @@ export interface SchemaDefinition<T = Record<string, TSchema>> {
|
|
|
6
6
|
validation: TObject;
|
|
7
7
|
tableName: string;
|
|
8
8
|
partialValidation: TObject;
|
|
9
|
+
/** PRIMARY KEY fields (camelCase) as introspected from the DB. Set by generated schemas. */
|
|
10
|
+
primaryKey?: string[];
|
|
9
11
|
}
|
|
10
12
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3D,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,CAAC,CAAC;IACV,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/types/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3D,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,CAAC,CAAC;IACV,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB"}
|