prostgles-types 4.0.274 → 4.0.277
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/JSONBSchemaValidation/JSONBSchema.d.ts +82 -63
- package/dist/JSONBSchemaValidation/JSONBSchema.d.ts.map +1 -1
- package/dist/JSONBSchemaValidation/JSONBSchema.js +1 -0
- package/dist/JSONBSchemaValidation/JSONBSchema.js.map +1 -1
- package/dist/JSONBSchemaValidation/JSONBSchemaValidation.d.ts +14 -0
- package/dist/JSONBSchemaValidation/JSONBSchemaValidation.d.ts.map +1 -1
- package/dist/JSONBSchemaValidation/JSONBSchemaValidation.js +124 -14
- package/dist/JSONBSchemaValidation/JSONBSchemaValidation.js.map +1 -1
- package/dist/JSONBSchemaValidation/getJSONBSchemaAsJSONSchema.d.ts.map +1 -1
- package/dist/JSONBSchemaValidation/getJSONBSchemaAsJSONSchema.js +5 -4
- package/dist/JSONBSchemaValidation/getJSONBSchemaAsJSONSchema.js.map +1 -1
- package/dist/JSONBSchemaValidation/getJSONBSchemaTSTypes.d.ts.map +1 -1
- package/dist/JSONBSchemaValidation/getJSONBSchemaTSTypes.js +21 -40
- package/dist/JSONBSchemaValidation/getJSONBSchemaTSTypes.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/index_umd.js +1 -1
- package/lib/JSONBSchemaValidation/JSONBSchema.ts +102 -79
- package/lib/JSONBSchemaValidation/JSONBSchemaValidation.ts +163 -12
- package/lib/JSONBSchemaValidation/getJSONBSchemaAsJSONSchema.ts +4 -4
- package/lib/JSONBSchemaValidation/getJSONBSchemaTSTypes.ts +29 -44
- package/lib/index.ts +7 -14
- package/package.json +3 -2
- package/scripts/check-type-instantiations.mjs +40 -0
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DBHandler } from "lib";
|
|
2
2
|
import { getKeys, isDefined, isEmpty, isObject } from "../util";
|
|
3
|
-
import { safeGetKeys, safeGetProperty, safeHasOwn } from "./utils";
|
|
4
3
|
import { includes } from "../utilFuncs/includes";
|
|
4
|
+
import type { JSONB, PrimitiveTypeMap } from "./JSONBSchema";
|
|
5
|
+
import { safeGetKeys, safeGetProperty, safeHasOwn } from "./utils";
|
|
5
6
|
|
|
6
7
|
type ValidationOptions = {
|
|
7
8
|
allowExtraProperties?: boolean;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
type PendingLookupValidation = {
|
|
12
|
+
schema: JSONB.Lookup;
|
|
13
|
+
value: unknown;
|
|
14
|
+
path: string[];
|
|
15
|
+
};
|
|
16
|
+
|
|
10
17
|
export const getFieldTypeObj = (rawFieldType: JSONB.FieldType): JSONB.FieldTypeObj => {
|
|
11
18
|
if (typeof rawFieldType === "string") return { type: rawFieldType };
|
|
12
19
|
|
|
13
20
|
return rawFieldType;
|
|
14
21
|
};
|
|
15
22
|
|
|
16
|
-
const
|
|
23
|
+
const isUint8ArrayOrBuffer = (val: unknown): val is Uint8Array => {
|
|
17
24
|
return (
|
|
18
25
|
val instanceof Blob ||
|
|
19
26
|
//@ts-ignore
|
|
@@ -23,7 +30,7 @@ const isBlob = (val: unknown): val is Blob => {
|
|
|
23
30
|
);
|
|
24
31
|
};
|
|
25
32
|
|
|
26
|
-
type DataType = JSONB.
|
|
33
|
+
type DataType = JSONB.BasicType["type"];
|
|
27
34
|
type ElementType<T extends DataType> = T extends `${infer E}[]` ? E : never;
|
|
28
35
|
type ArrayTypes = Extract<DataType, `${string}[]`>;
|
|
29
36
|
type NonArrayTypes = Extract<Exclude<DataType, ArrayTypes>, string>;
|
|
@@ -47,10 +54,8 @@ const PRIMITIVE_VALIDATORS: {
|
|
|
47
54
|
any: (val): val is any => typeof val !== "function" && typeof val !== "symbol",
|
|
48
55
|
unknown: (val): val is unknown => typeof val !== "function" && typeof val !== "symbol",
|
|
49
56
|
Date: (val) => typeof val === "string",
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
},
|
|
53
|
-
Blob: isBlob,
|
|
57
|
+
Uint8Array: isUint8ArrayOrBuffer,
|
|
58
|
+
Blob: isUint8ArrayOrBuffer,
|
|
54
59
|
FileLike: (val, s): val is PrimitiveTypeMap["FileLike"] => {
|
|
55
60
|
if (s.type !== "FileLike") {
|
|
56
61
|
throw new Error("FileLike type must have type 'FileLike'");
|
|
@@ -59,7 +64,7 @@ const PRIMITIVE_VALIDATORS: {
|
|
|
59
64
|
isObject(val) &&
|
|
60
65
|
typeof val.name === "string" &&
|
|
61
66
|
typeof val.type === "string" &&
|
|
62
|
-
|
|
67
|
+
isUint8ArrayOrBuffer(val.data);
|
|
63
68
|
if (validStructure && s.mimeTypes) {
|
|
64
69
|
const validMime = Object.keys(s.mimeTypes).some((mime) => val.type === mime);
|
|
65
70
|
if (!validMime) {
|
|
@@ -107,6 +112,7 @@ const getPropertyValidationError = (
|
|
|
107
112
|
rawFieldType: JSONB.FieldType,
|
|
108
113
|
path: string[] = [],
|
|
109
114
|
opts: ValidationOptions | undefined,
|
|
115
|
+
pendingLookupValidations?: PendingLookupValidation[],
|
|
110
116
|
): string | undefined => {
|
|
111
117
|
const err = `${path.join(".")} is of invalid type. Expecting ${getTypeDescription(rawFieldType).replaceAll("\n", "")}`;
|
|
112
118
|
const fieldDefinition = getFieldTypeObj(rawFieldType);
|
|
@@ -147,6 +153,7 @@ const getPropertyValidationError = (
|
|
|
147
153
|
subSchema,
|
|
148
154
|
[...path, subKey],
|
|
149
155
|
opts,
|
|
156
|
+
pendingLookupValidations,
|
|
150
157
|
);
|
|
151
158
|
if (error !== undefined) {
|
|
152
159
|
return error;
|
|
@@ -166,7 +173,38 @@ const getPropertyValidationError = (
|
|
|
166
173
|
return;
|
|
167
174
|
}
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
if (type.includes("Lookup")) {
|
|
177
|
+
if (!pendingLookupValidations) {
|
|
178
|
+
throw new Error("Lookup types are not supported for validation");
|
|
179
|
+
}
|
|
180
|
+
const isArray = type.endsWith("[]");
|
|
181
|
+
if (isArray !== Array.isArray(value)) return err;
|
|
182
|
+
|
|
183
|
+
const lookupType = type.replace("[]", "");
|
|
184
|
+
const values = isArray ? value : [value];
|
|
185
|
+
const isValid = values.every((item: unknown) => {
|
|
186
|
+
if (lookupType === "RowLookup") return isObject(item);
|
|
187
|
+
if (lookupType === "ValueLookup") {
|
|
188
|
+
return typeof item !== "function" && typeof item !== "symbol";
|
|
189
|
+
}
|
|
190
|
+
if (lookupType === "TableLookup") return typeof item === "string";
|
|
191
|
+
return (
|
|
192
|
+
isObject(item) &&
|
|
193
|
+
typeof safeGetProperty(item, "table") === "string" &&
|
|
194
|
+
typeof safeGetProperty(item, "column") === "string" &&
|
|
195
|
+
safeGetKeys(item).every((key) => key === "table" || key === "column")
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
if (!isValid) return err;
|
|
199
|
+
|
|
200
|
+
pendingLookupValidations.push({
|
|
201
|
+
schema: fieldDefinition as JSONB.Lookup,
|
|
202
|
+
value,
|
|
203
|
+
path,
|
|
204
|
+
});
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const { validator } = getValidator(type as DataType, fieldDefinition);
|
|
170
208
|
const isValid = validator(value, fieldDefinition);
|
|
171
209
|
if (!isValid) {
|
|
172
210
|
return err;
|
|
@@ -192,6 +230,7 @@ const getPropertyValidationError = (
|
|
|
192
230
|
tuple[index]!,
|
|
193
231
|
[...path, `${index}`],
|
|
194
232
|
opts,
|
|
233
|
+
pendingLookupValidations,
|
|
195
234
|
);
|
|
196
235
|
|
|
197
236
|
if (elementError !== undefined) {
|
|
@@ -221,7 +260,13 @@ const getPropertyValidationError = (
|
|
|
221
260
|
}
|
|
222
261
|
const error = value
|
|
223
262
|
.map((element, i) => {
|
|
224
|
-
return getPropertyValidationError(
|
|
263
|
+
return getPropertyValidationError(
|
|
264
|
+
element,
|
|
265
|
+
arrayOf,
|
|
266
|
+
[...path, `${i}`],
|
|
267
|
+
opts,
|
|
268
|
+
pendingLookupValidations,
|
|
269
|
+
);
|
|
225
270
|
})
|
|
226
271
|
.filter(isDefined)[0];
|
|
227
272
|
if (error !== undefined) {
|
|
@@ -237,7 +282,11 @@ const getPropertyValidationError = (
|
|
|
237
282
|
}
|
|
238
283
|
let firstError: string | undefined;
|
|
239
284
|
const validMember = oneOf.find((member) => {
|
|
240
|
-
const
|
|
285
|
+
const pendingLookupCount = pendingLookupValidations?.length;
|
|
286
|
+
const error = getPropertyValidationError(value, member, path, opts, pendingLookupValidations);
|
|
287
|
+
if (error !== undefined && pendingLookupCount !== undefined) {
|
|
288
|
+
pendingLookupValidations!.length = pendingLookupCount;
|
|
289
|
+
}
|
|
241
290
|
firstError ??= error;
|
|
242
291
|
return error === undefined;
|
|
243
292
|
});
|
|
@@ -271,6 +320,7 @@ const getPropertyValidationError = (
|
|
|
271
320
|
valuesSchema,
|
|
272
321
|
[...path, propKey],
|
|
273
322
|
opts,
|
|
323
|
+
pendingLookupValidations,
|
|
274
324
|
);
|
|
275
325
|
if (valError !== undefined) {
|
|
276
326
|
return `${valError}`;
|
|
@@ -358,6 +408,107 @@ export const getJSONBSchemaValidationError = <S extends JSONB.FieldType>(
|
|
|
358
408
|
}
|
|
359
409
|
return { data: obj as JSONB.GetType<S> };
|
|
360
410
|
};
|
|
411
|
+
|
|
412
|
+
const getLookupValuePath = (path: string[], index?: number): string => {
|
|
413
|
+
const result = [...path, ...(index === undefined ? [] : [String(index)])].join(".");
|
|
414
|
+
return result || "value";
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const getLookupTableHandler = (db: DBHandler, table: string): DBHandler[string] | undefined => {
|
|
418
|
+
if (!safeHasOwn(db, table)) return;
|
|
419
|
+
const handler = safeGetProperty(db, table);
|
|
420
|
+
return isObject(handler) ? (handler as DBHandler[string]) : undefined;
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const getLookupValidationError = async (
|
|
424
|
+
lookup: PendingLookupValidation,
|
|
425
|
+
db: DBHandler,
|
|
426
|
+
): Promise<string | undefined> => {
|
|
427
|
+
const { schema, path } = lookup;
|
|
428
|
+
const isArray = schema.type.endsWith("[]");
|
|
429
|
+
const values = isArray ? (lookup.value as unknown[]) : [lookup.value];
|
|
430
|
+
|
|
431
|
+
for (const [index, value] of values.entries()) {
|
|
432
|
+
const valuePath = getLookupValuePath(path, isArray ? index : undefined);
|
|
433
|
+
|
|
434
|
+
if (schema.type === "TableLookup" || schema.type === "TableLookup[]") {
|
|
435
|
+
if (!getLookupTableHandler(db, value as string)) {
|
|
436
|
+
return `${valuePath} references an unknown table ${JSON.stringify(value)}`;
|
|
437
|
+
}
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (schema.type === "ColumnLookup" || schema.type === "ColumnLookup[]") {
|
|
442
|
+
const reference = value as { table: string; column: string };
|
|
443
|
+
if (schema.filter?.table && reference.table !== schema.filter.table) {
|
|
444
|
+
return `${valuePath} references a column that does not match the lookup filter`;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const tableHandler = getLookupTableHandler(db, reference.table);
|
|
448
|
+
if (!tableHandler) {
|
|
449
|
+
return `${valuePath} references an unknown table ${JSON.stringify(reference.table)}`;
|
|
450
|
+
}
|
|
451
|
+
if (typeof tableHandler.getColumns !== "function") {
|
|
452
|
+
throw new Error(
|
|
453
|
+
`Cannot validate ColumnLookup: table ${JSON.stringify(reference.table)} does not expose getColumns`,
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
const columns = await tableHandler.getColumns();
|
|
457
|
+
const column = columns.find(({ name }) => name === reference.column);
|
|
458
|
+
if (
|
|
459
|
+
!column ||
|
|
460
|
+
(schema.filter?.tsDataType && column.tsDataType !== schema.filter.tsDataType) ||
|
|
461
|
+
(schema.filter?.udt_name && column.udt_name !== schema.filter.udt_name)
|
|
462
|
+
) {
|
|
463
|
+
return `${valuePath} references an unknown or disallowed column ${JSON.stringify(`${reference.table}.${reference.column}`)}`;
|
|
464
|
+
}
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const dataLookup = schema as JSONB.RowLookup | JSONB.ValueLookup;
|
|
469
|
+
const tableHandler = getLookupTableHandler(db, dataLookup.table);
|
|
470
|
+
|
|
471
|
+
if (!tableHandler) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
`Cannot validate ${dataLookup.type}: table ${JSON.stringify(dataLookup.table)} does not expose findOne`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const valueFilter =
|
|
478
|
+
dataLookup.type === "RowLookup" || dataLookup.type === "RowLookup[]" ?
|
|
479
|
+
(value as Record<string, unknown>)
|
|
480
|
+
: { [(dataLookup as JSONB.ValueLookup).column]: value };
|
|
481
|
+
const filter = dataLookup.filter ? { $and: [dataLookup.filter, valueFilter] } : valueFilter;
|
|
482
|
+
const row = await tableHandler?.findOne?.(filter);
|
|
483
|
+
if (row === undefined) {
|
|
484
|
+
return `${valuePath} does not reference an existing row in ${JSON.stringify(dataLookup.table)}`;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Validates lookup values as well as the synchronous JSONB schema rules.
|
|
491
|
+
* A prostgles DB handler validates every lookup kind. A fetch-row callback
|
|
492
|
+
* validates RowLookup and ValueLookup records, while table/column lookups are
|
|
493
|
+
* structurally validated.
|
|
494
|
+
*/
|
|
495
|
+
export const getJSONBSchemaValidationErrorAsync = async <S extends JSONB.FieldType>(
|
|
496
|
+
schema: S,
|
|
497
|
+
obj: any,
|
|
498
|
+
source: DBHandler,
|
|
499
|
+
opts?: ValidationOptions,
|
|
500
|
+
): Promise<{ error: string; data?: undefined } | { error?: undefined; data: JSONB.GetType<S> }> => {
|
|
501
|
+
const pendingLookupValidations: PendingLookupValidation[] = [];
|
|
502
|
+
const error = getPropertyValidationError(obj, schema, undefined, opts, pendingLookupValidations);
|
|
503
|
+
if (error) return { error };
|
|
504
|
+
|
|
505
|
+
for (const lookup of pendingLookupValidations) {
|
|
506
|
+
const lookupError = await getLookupValidationError(lookup, source);
|
|
507
|
+
if (lookupError) return { error: lookupError };
|
|
508
|
+
}
|
|
509
|
+
return { data: obj as JSONB.GetType<S> };
|
|
510
|
+
};
|
|
511
|
+
|
|
361
512
|
export const validateJSONBObjectAgainstSchema = <S extends JSONB.ObjectType["type"]>(
|
|
362
513
|
schema: S,
|
|
363
514
|
obj: any,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSONSchema7, JSONSchema7Definition, JSONSchema7TypeName } from "json-schema";
|
|
2
|
-
import type { JSONB
|
|
2
|
+
import type { JSONB } from "./JSONBSchema";
|
|
3
3
|
import { getObjectEntries, isObject } from "../util";
|
|
4
4
|
import { safeGetKeys } from "./utils";
|
|
5
5
|
|
|
@@ -7,8 +7,7 @@ const getJSONSchemaType = (
|
|
|
7
7
|
rawType: JSONB.BasicType["type"] | JSONB.Lookup["type"] | undefined,
|
|
8
8
|
): { type: JSONSchema7TypeName | undefined; isArray: boolean } | undefined => {
|
|
9
9
|
if (!rawType) return;
|
|
10
|
-
const type
|
|
11
|
-
rawType.endsWith("[]") ? (rawType.slice(0, -2) as any) : rawType;
|
|
10
|
+
const type = rawType.endsWith("[]") ? rawType.slice(0, -2) : rawType;
|
|
12
11
|
|
|
13
12
|
return {
|
|
14
13
|
type:
|
|
@@ -17,7 +16,8 @@ const getJSONSchemaType = (
|
|
|
17
16
|
: type === "number" ? "number"
|
|
18
17
|
: type === "any" ? undefined
|
|
19
18
|
: type === "unknown" ? undefined
|
|
20
|
-
: type
|
|
19
|
+
: type.endsWith("Lookup") ? undefined
|
|
20
|
+
: type === "Uint8Array" ? undefined
|
|
21
21
|
: type === "Blob" ? undefined
|
|
22
22
|
: type === "FileLike" ? undefined
|
|
23
23
|
: "string",
|
|
@@ -24,6 +24,33 @@ const valueToString = (v: any): string => {
|
|
|
24
24
|
return String(v);
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
const getLookupTSType = (tables: TableSchema[], fieldType: JSONB.Lookup): string => {
|
|
28
|
+
const nullType = fieldType.nullable ? "null | " : "";
|
|
29
|
+
const arrayType = fieldType.type.endsWith("[]") ? "[]" : "";
|
|
30
|
+
|
|
31
|
+
if (fieldType.type === "TableLookup" || fieldType.type === "TableLookup[]") {
|
|
32
|
+
return `${nullType}string${arrayType}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (fieldType.type === "ColumnLookup" || fieldType.type === "ColumnLookup[]") {
|
|
36
|
+
return `${nullType}{ "table": string; "column": string; }${arrayType}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const dataLookup = fieldType as JSONB.RowLookup | JSONB.ValueLookup;
|
|
40
|
+
const cols = tables.find((table) => table.name === dataLookup.table)?.columns;
|
|
41
|
+
if (fieldType.type === "ValueLookup" || fieldType.type === "ValueLookup[]") {
|
|
42
|
+
const valueLookup = fieldType as JSONB.ValueLookup;
|
|
43
|
+
const udtName = cols?.find((column) => column.name === valueLookup.column)?.udt_name;
|
|
44
|
+
return `${nullType}${postgresToTsType(udtName ?? "text")}${arrayType}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const rowType =
|
|
48
|
+
!cols ? "any" : (
|
|
49
|
+
`{ ${cols.map((column) => `${JSON.stringify(column.name)}: ${column.is_nullable ? "null | " : ""} ${postgresToTsType(column.udt_name)}; `).join(" ")} }`
|
|
50
|
+
);
|
|
51
|
+
return `${nullType}${rowType}${arrayType}`;
|
|
52
|
+
};
|
|
53
|
+
|
|
27
54
|
export const getJSONBTSTypes = (
|
|
28
55
|
tables: TableSchema[],
|
|
29
56
|
rawFieldType: JSONB.FieldType,
|
|
@@ -33,51 +60,9 @@ export const getJSONBTSTypes = (
|
|
|
33
60
|
): string => {
|
|
34
61
|
const fieldType = getFieldTypeObj(rawFieldType);
|
|
35
62
|
const nullType = fieldType.nullable ? `null | ` : "";
|
|
36
|
-
if (fieldType.
|
|
37
|
-
|
|
38
|
-
if (l.type === "data-def") {
|
|
39
|
-
return `${fieldType.nullable ? `null |` : ""} ${getJSONBTSTypes(tables, {
|
|
40
|
-
type: {
|
|
41
|
-
table: "string",
|
|
42
|
-
column: "string",
|
|
43
|
-
filter: { record: {}, optional: true },
|
|
44
|
-
isArray: { type: "boolean", optional: true },
|
|
45
|
-
searchColumns: { type: "string[]", optional: true },
|
|
46
|
-
isFullRow: {
|
|
47
|
-
optional: true,
|
|
48
|
-
type: {
|
|
49
|
-
displayColumns: { type: "string[]", optional: true },
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
showInRowCard: { optional: true, record: {} },
|
|
53
|
-
},
|
|
54
|
-
})}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const isSChema = l.type === "schema";
|
|
58
|
-
let type =
|
|
59
|
-
isSChema ?
|
|
60
|
-
l.object === "table" ?
|
|
61
|
-
"string"
|
|
62
|
-
: `{ "table": string; "column": string; }`
|
|
63
|
-
: "";
|
|
64
|
-
if (!isSChema) {
|
|
65
|
-
const cols = tables.find((t) => t.name === l.table)?.columns;
|
|
66
|
-
if (!l.isFullRow) {
|
|
67
|
-
type = postgresToTsType(cols?.find((c) => c.name === l.column)?.udt_name ?? "text");
|
|
68
|
-
} else {
|
|
69
|
-
type =
|
|
70
|
-
!cols ? "any" : (
|
|
71
|
-
`{ ${cols.map((c) => `${JSON.stringify(c.name)}: ${c.is_nullable ? "null | " : ""} ${postgresToTsType(c.udt_name)}; `).join(" ")} }`
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return `${fieldType.nullable ? `null | ` : ""}${type}${l.isArray ? "[]" : ""}`;
|
|
63
|
+
if (typeof fieldType.type === "string" && fieldType.type.includes("Lookup")) {
|
|
64
|
+
return getLookupTSType(tables, fieldType as JSONB.Lookup);
|
|
76
65
|
} else if (typeof fieldType.type === "string") {
|
|
77
|
-
if (fieldType.type.toLowerCase().includes("lookup")) {
|
|
78
|
-
throw new Error(`getJSONBTSTypes: Lookup type not handled correctly`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
66
|
/** Primitives */
|
|
82
67
|
const correctType = fieldType.type
|
|
83
68
|
.replace("integer", "number")
|
package/lib/index.ts
CHANGED
|
@@ -48,7 +48,7 @@ export type PG_COLUMN_UDT_DATA_TYPE =
|
|
|
48
48
|
| (typeof _PG_bytes)[number];
|
|
49
49
|
|
|
50
50
|
const TS_PG_PRIMITIVES = {
|
|
51
|
-
|
|
51
|
+
Uint8Array: _PG_bytes,
|
|
52
52
|
string: [
|
|
53
53
|
..._PG_strings,
|
|
54
54
|
..._PG_numbers_str,
|
|
@@ -74,7 +74,6 @@ export const TS_PG_Types = {
|
|
|
74
74
|
"string[]": TS_PG_PRIMITIVES.string.map((s) => `_${s}` as const),
|
|
75
75
|
"any[]": TS_PG_PRIMITIVES.any.map((s) => `_${s}` as const),
|
|
76
76
|
// "Date[]": _PG_date.map(s => `_${s}` as const),
|
|
77
|
-
// "any": [],
|
|
78
77
|
} as const;
|
|
79
78
|
export type TS_COLUMN_DATA_TYPES = keyof typeof TS_PG_Types;
|
|
80
79
|
|
|
@@ -113,7 +112,7 @@ export type DBTableSchema = {
|
|
|
113
112
|
update?: boolean;
|
|
114
113
|
delete?: boolean;
|
|
115
114
|
/**
|
|
116
|
-
* Used in update,
|
|
115
|
+
* Used in update, insert, select and filters
|
|
117
116
|
* fields that are nullable or with a default value are be optional
|
|
118
117
|
*/
|
|
119
118
|
columns: AnyObject;
|
|
@@ -138,7 +137,7 @@ export type ColumnInfo = {
|
|
|
138
137
|
name: string;
|
|
139
138
|
|
|
140
139
|
/**
|
|
141
|
-
* Column display name. Will be first non empty value from i18n data,
|
|
140
|
+
* Column display name. Will be first non empty value from i18n data, or prettified name
|
|
142
141
|
*/
|
|
143
142
|
label: string;
|
|
144
143
|
|
|
@@ -230,7 +229,7 @@ export type ColumnInfo = {
|
|
|
230
229
|
|
|
231
230
|
/**
|
|
232
231
|
* JSONB schema (a simplified version of json schema) for the column (if defined in the tableConfig)
|
|
233
|
-
* A check constraint will use this schema for runtime data validation and
|
|
232
|
+
* A check constraint will use this schema for runtime data validation and appropriate TS types will be generated
|
|
234
233
|
*/
|
|
235
234
|
jsonbSchema?: JSONB.JSONBSchema;
|
|
236
235
|
|
|
@@ -741,9 +740,7 @@ export type InsertParams<T extends AnyObject | void = void, S extends DBSchema |
|
|
|
741
740
|
* - DoUpdate: will update all non primary key columns of the conflicting row
|
|
742
741
|
*/
|
|
743
742
|
onConflict?:
|
|
744
|
-
| "DoNothing"
|
|
745
|
-
| "DoUpdate"
|
|
746
|
-
| { action: "DoNothing" | "DoUpdate"; conflictColumns: string[] };
|
|
743
|
+
"DoNothing" | "DoUpdate" | { action: "DoNothing" | "DoUpdate"; conflictColumns: string[] };
|
|
747
744
|
|
|
748
745
|
/**
|
|
749
746
|
* Used for sync.
|
|
@@ -918,7 +915,7 @@ export type InsertDataWithNested<
|
|
|
918
915
|
export type TableHandler<
|
|
919
916
|
TD extends AnyObject = AnyObject,
|
|
920
917
|
S extends DBSchema | void = void,
|
|
921
|
-
TName extends S extends DBSchema ? keyof S : never = never,
|
|
918
|
+
TName extends (S extends DBSchema ? keyof S : never) = never,
|
|
922
919
|
> = {
|
|
923
920
|
/**
|
|
924
921
|
* Retrieves the table/view info
|
|
@@ -1210,11 +1207,7 @@ type DeleteMethods<T extends DBTableSchema> =
|
|
|
1210
1207
|
T["delete"] extends true ? keyof Pick<TableHandler, "delete"> : never;
|
|
1211
1208
|
|
|
1212
1209
|
export type ValidatedMethods<T extends DBTableSchema> =
|
|
1213
|
-
|
|
|
1214
|
-
| UpdateMethods<T>
|
|
1215
|
-
| InsertMethods<T>
|
|
1216
|
-
| UpsertMethods<T>
|
|
1217
|
-
| DeleteMethods<T>;
|
|
1210
|
+
SelectMethods<T> | UpdateMethods<T> | InsertMethods<T> | UpsertMethods<T> | DeleteMethods<T>;
|
|
1218
1211
|
// | SyncMethods<T>
|
|
1219
1212
|
|
|
1220
1213
|
export type DBHandler<S = void> =
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prostgles-types",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.277",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index_umd.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"directories": {},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"start": "tsc --watch",
|
|
10
|
-
"test": "npm run build && node --test dist/*.spec.js dist/**/*.spec.js",
|
|
10
|
+
"test": "npm run build && npm run test:type-instantiations && node --test dist/*.spec.js dist/**/*.spec.js",
|
|
11
|
+
"test:type-instantiations": "node scripts/check-type-instantiations.mjs",
|
|
11
12
|
"build": "npm i && rm -rf ./dist/* && tsc && webpack --config webpack.prod.js",
|
|
12
13
|
"prebuild": "tsc --noEmit -p tsconfig.browser.json",
|
|
13
14
|
"perf": "tsc --extendedDiagnostics 2>&1 | grep -E \"Instantiations|Check time\"",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
|
|
4
|
+
// Baseline: 108,997. The small margin avoids hiding meaningful inference regressions.
|
|
5
|
+
const MAX_INSTANTIATIONS = 105_000;
|
|
6
|
+
const tscPath = fileURLToPath(new URL("../node_modules/typescript/bin/tsc", import.meta.url));
|
|
7
|
+
const result = spawnSync(
|
|
8
|
+
process.execPath,
|
|
9
|
+
[tscPath, "--noEmit", "--extendedDiagnostics", "--pretty", "false"],
|
|
10
|
+
{ encoding: "utf8" },
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
if (result.error) {
|
|
14
|
+
throw result.error;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (result.status !== 0) {
|
|
18
|
+
process.stdout.write(result.stdout);
|
|
19
|
+
process.stderr.write(result.stderr);
|
|
20
|
+
process.exit(result.status ?? 1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const output = result.stdout + result.stderr;
|
|
24
|
+
const label = "Instantiations:";
|
|
25
|
+
const line = output.split("\n").find((outputLine) => outputLine.startsWith(label));
|
|
26
|
+
const instantiations = Number(line?.slice(label.length).trim());
|
|
27
|
+
|
|
28
|
+
if (!Number.isFinite(instantiations)) {
|
|
29
|
+
throw new Error(`Could not read type instantiations from tsc output:\n${output}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (instantiations > MAX_INSTANTIATIONS) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Type instantiations increased to ${instantiations.toLocaleString()} (maximum: ${MAX_INSTANTIATIONS.toLocaleString()}).`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(
|
|
39
|
+
`Type instantiations: ${instantiations.toLocaleString()} / ${MAX_INSTANTIATIONS.toLocaleString()}`,
|
|
40
|
+
);
|