prostgles-server 4.2.2 → 4.2.4

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.
@@ -0,0 +1,1020 @@
1
+
2
+ type AnyObject = Record<string, any>;
3
+
4
+
5
+ export type Explode<T> = keyof T extends infer K
6
+ ? K extends unknown
7
+ ? { [I in keyof T]: I extends K ? T[I] : never }
8
+ : never
9
+ : never;
10
+ export type AtMostOne<T> = Explode<Partial<T>>;
11
+ export type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
12
+ export type ExactlyOne<T> = AtMostOne<T> & AtLeastOne<T>;
13
+ export type DBTableSchema = {
14
+ is_view?: boolean;
15
+ select?: boolean;
16
+ insert?: boolean;
17
+ update?: boolean;
18
+ delete?: boolean;
19
+ /**
20
+ * Used in update, insertm select and filters
21
+ * fields that are nullable or with a default value are be optional
22
+ */
23
+ columns: AnyObject;
24
+ }
25
+ export type DBSchema = {
26
+ [tov_name: string]: DBTableSchema
27
+ }
28
+
29
+ export type AllowedTSType = string | number | boolean | Date | any;
30
+ export type AllowedTSTypes = AllowedTSType[];
31
+
32
+ export const CompareFilterKeys = ["=", "$eq","<>",">","<",">=","<=","$eq","$ne","$gt","$gte","$lte"] as const;
33
+ export const CompareInFilterKeys = ["$in", "$nin"] as const;
34
+
35
+ export const JsonbOperands = {
36
+ "@>": {
37
+ "Operator": "@>",
38
+ "Right Operand Type": "jsonb",
39
+ "Description": "Does the left JSON value contain the right JSON path/value entries at the top level?",
40
+ "Example": "'{\"a\":1, \"b\":2}'::jsonb @> '{\"b\":2}'::jsonb"
41
+ },
42
+ "<@": {
43
+ "Operator": "<@",
44
+ "Right Operand Type": "jsonb",
45
+ "Description": "Are the left JSON path/value entries contained at the top level within the right JSON value?",
46
+ "Example": "'{\"b\":2}'::jsonb <@ '{\"a\":1, \"b\":2}'::jsonb"
47
+ },
48
+ "?": {
49
+ "Operator": "?",
50
+ "Right Operand Type": "text",
51
+ "Description": "Does the string exist as a top-level key within the JSON value?",
52
+ "Example": "'{\"a\":1, \"b\":2}'::jsonb ? 'b'"
53
+ },
54
+ "?|": {
55
+ "Operator": "?|",
56
+ "Right Operand Type": "text[]",
57
+ "Description": "Do any of these array strings exist as top-level keys?",
58
+ "Example": "'{\"a\":1, \"b\":2, \"c\":3}'::jsonb ?| array['b', 'c']"
59
+ },
60
+ "?&": {
61
+ "Operator": "?&",
62
+ "Right Operand Type": "text[]",
63
+ "Description": "Do all of these array strings exist as top-level keys?",
64
+ "Example": "'[\"a\", \"b\"]'::jsonb ?& array['a', 'b']"
65
+ },
66
+ "||": {
67
+ "Operator": "||",
68
+ "Right Operand Type": "jsonb",
69
+ "Description": "Concatenate two jsonb values into a new jsonb value",
70
+ "Example": "'[\"a\", \"b\"]'::jsonb || '[\"c\", \"d\"]'::jsonb"
71
+ },
72
+ "-": {
73
+ "Operator": "-",
74
+ "Right Operand Type": "integer",
75
+ "Description": "Delete the array element with specified index (Negative integers count from the end). Throws an error if top level container is not an array.",
76
+ "Example": "'[\"a\", \"b\"]'::jsonb - 1"
77
+ },
78
+ "#-": {
79
+ "Operator": "#-",
80
+ "Right Operand Type": "text[]",
81
+ "Description": "Delete the field or element with specified path (for JSON arrays, negative integers count from the end)",
82
+ "Example": "'[\"a\", {\"b\":1}]'::jsonb #- '{1,b}'"
83
+ },
84
+ "@?": {
85
+ "Operator": "@?",
86
+ "Right Operand Type": "jsonpath",
87
+ "Description": "Does JSON path return any item for the specified JSON value?",
88
+ "Example": "'{\"a\":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'"
89
+ },
90
+ "@@": {
91
+ "Operator": "@@",
92
+ "Right Operand Type": "jsonpath",
93
+ "Description": "Returns the result of JSON path predicate check for the specified JSON value. Only the first item of the result is taken into account. If the result is not Boolean, then null is returned.",
94
+ "Example": "'{\"a\":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2'"
95
+ }
96
+ } as const;
97
+
98
+ /**
99
+ * Example: col_name: { $gt: 2 }
100
+ */
101
+ export type CompareFilter<T extends AllowedTSType = string> =
102
+ /**
103
+ * column value equals provided value
104
+ */
105
+ | T
106
+ | ExactlyOne<Record<typeof CompareFilterKeys[number], T>>
107
+
108
+ | ExactlyOne<Record<typeof CompareInFilterKeys[number], T[]>>
109
+ | { "$between": [T, T] }
110
+ ;
111
+ export const TextFilterKeys = ["$ilike", "$like", "$nilike", "$nlike"] as const;
112
+
113
+ export const TextFilterFTSKeys = ["@@", "@>", "<@", "$contains", "$containedBy"] as const;
114
+
115
+ export const TextFilter_FullTextSearchFilterKeys = ["to_tsquery","plainto_tsquery","phraseto_tsquery","websearch_to_tsquery"] as const;
116
+ export type FullTextSearchFilter =
117
+ | ExactlyOne<Record<typeof TextFilter_FullTextSearchFilterKeys[number], string[]>>
118
+ ;
119
+
120
+ export type TextFilter =
121
+ | CompareFilter<string>
122
+ | ExactlyOne<Record<typeof TextFilterKeys[number], string>>
123
+
124
+ | ExactlyOne<Record<typeof TextFilterFTSKeys[number], FullTextSearchFilter>>
125
+ ;
126
+
127
+ export const ArrayFilterOperands = ["@>", "<@", "=", "$eq", "$contains", "$containedBy", "&&", "$overlaps"] as const;
128
+ export type ArrayFilter<T extends AllowedTSType[]> =
129
+ | Record<typeof ArrayFilterOperands[number], T>
130
+ | ExactlyOne<Record<typeof ArrayFilterOperands[number], T>>
131
+ ;
132
+
133
+ /* POSTGIS */
134
+
135
+ /**
136
+ * Makes bounding box from NW and SE points
137
+ * float xmin, float ymin, float xmax, float ymax, integer srid=unknown
138
+ * https://postgis.net/docs/ST_MakeEnvelope.html
139
+ */
140
+ export type GeoBBox = { ST_MakeEnvelope: number[] }
141
+
142
+
143
+ /**
144
+ * Returns TRUE if A's 2D bounding box intersects B's 2D bounding box.
145
+ * https://postgis.net/docs/reference.html#Operators
146
+ */
147
+ export type GeomFilter =
148
+
149
+ /**
150
+ * A's 2D bounding box intersects B's 2D bounding box.
151
+ */
152
+ | { "&&": GeoBBox }
153
+ // | { "&&&": GeoBBox }
154
+ // | { "&<": GeoBBox }
155
+ // | { "&<|": GeoBBox }
156
+ // | { "&>": GeoBBox }
157
+ // | { "<<": GeoBBox }
158
+ // | { "<<|": GeoBBox }
159
+ // | { ">>": GeoBBox }
160
+
161
+ // | { "=": GeoBBox }
162
+
163
+ /**
164
+ * A's bounding box is contained by B's
165
+ */
166
+ | { "@": GeoBBox }
167
+ // | { "|&>": GeoBBox }
168
+ // | { "|>>": GeoBBox }
169
+
170
+ /**
171
+ * A's bounding box contains B's.
172
+ */
173
+ // | { "~": GeoBBox }
174
+ // | { "~=": GeoBBox }
175
+ ;
176
+ export const GeomFilterKeys = ["~","~=","@","|&>","|>>", ">>", "=", "<<|", "<<", "&>", "&<|", "&<", "&&&", "&&"] as const;
177
+ export const GeomFilter_Funcs = [
178
+ "ST_MakeEnvelope",
179
+ "st_makeenvelope",
180
+ "ST_MakePolygon",
181
+ "st_makepolygon",
182
+ ] as const;
183
+
184
+
185
+ // PG will try to cast strings to appropriate type
186
+ export type CastFromTSToPG<T extends AllowedTSType> =
187
+ T extends number ? (T | string)
188
+ : T extends string ? (T | Date)
189
+ : T extends boolean ? (T | string)
190
+ : T extends Date ? (T | string)
191
+ : T
192
+
193
+ export type FilterDataType<T extends AllowedTSType> =
194
+ T extends string ? TextFilter
195
+ : T extends number ? CompareFilter<CastFromTSToPG<T>>
196
+ : T extends boolean ? CompareFilter<CastFromTSToPG<T>>
197
+ : T extends Date ? CompareFilter<CastFromTSToPG<T>>
198
+ : T extends any[] ? ArrayFilter<T>
199
+ : (CompareFilter<T> | TextFilter | GeomFilter)
200
+ ;
201
+
202
+ export const EXISTS_KEYS = ["$exists", "$notExists", "$existsJoined", "$notExistsJoined"] as const;
203
+ export type EXISTS_KEY = typeof EXISTS_KEYS[number];
204
+
205
+ /**
206
+ * {
207
+ * $filter: [
208
+ * { $funcName: [...args] },
209
+ * operand,
210
+ * value | funcFilter
211
+ * ]
212
+ * }
213
+ */
214
+ export const COMPLEX_FILTER_KEY = "$filter" as const;
215
+ export type ComplexFilter = Record<typeof COMPLEX_FILTER_KEY, [
216
+ { [funcName: string]: any[] },
217
+ typeof CompareFilterKeys[number]?,
218
+ any?
219
+ ]>;
220
+
221
+ /**
222
+ * Shortened filter operands
223
+ */
224
+ type BasicFilter<Field extends string, DataType extends any> = Partial<{
225
+ [K in Extract<typeof CompareFilterKeys[number], string> as `${Field}.${K}`]: CastFromTSToPG<DataType>
226
+ }> | Partial<{
227
+ [K in Extract<typeof CompareInFilterKeys[number], string> as `${Field}.${K}`]: CastFromTSToPG<DataType>[]
228
+ }>;
229
+ type StringFilter<Field extends string, DataType extends any> = BasicFilter<Field, DataType> & (Partial<{
230
+ [K in Extract<typeof TextFilterKeys[number], string> as `${Field}.${K}`]: DataType
231
+ }> | Partial<{
232
+ [K in Extract<typeof TextFilterFTSKeys[number], string> as `${Field}.${K}`]: any
233
+ }>);
234
+ export type ValueOf<T> = T[keyof T];
235
+
236
+ type ShorthandFilter<Obj extends Record<string, any>> = ValueOf<{
237
+ [K in keyof Obj]: Obj[K] extends string? StringFilter<K, Required<Obj>[K]> : BasicFilter<K, Required<Obj>[K]>;
238
+ }>
239
+
240
+ /* Traverses object keys to make filter */
241
+ export type FilterForObject<T extends AnyObject = AnyObject> =
242
+ /* { col: { $func: ["value"] } } */
243
+ | {
244
+ [K in keyof Partial<T>]: FilterDataType<T[K]>
245
+ } & Partial<ComplexFilter>
246
+ /**
247
+ * Filters with shorthand notation
248
+ * @example: { "name.$ilike": 'abc' }
249
+ */
250
+ | ShorthandFilter<T>
251
+ ;
252
+
253
+ export type ExistsFilter<S = void> = Partial<{
254
+ [key in EXISTS_KEY]: S extends DBSchema?
255
+ ExactlyOne<{
256
+ [tname in keyof S]:
257
+ | FullFilter<S[tname]["columns"], S>
258
+ | {
259
+ path: RawJoinPath[];
260
+ filter: FullFilter<S[tname]["columns"], S>
261
+ }
262
+ }> : any
263
+ /** ExactlyOne does not for any type. This produces error */
264
+ // ExactlyOne<{
265
+ // [key: string]: FullFilter<AnyObject,S>
266
+ // }>
267
+ }>;
268
+
269
+
270
+ /**
271
+ * Filter that relates to a single column { col: 2 } or
272
+ * an exists filter: { $exists: { } }
273
+ */
274
+ export type FilterItem<T extends AnyObject = AnyObject> =
275
+ | FilterForObject<T>
276
+
277
+
278
+ export type AnyObjIfVoid<T extends AnyObject | void> = T extends AnyObject? T : AnyObject;
279
+ /**
280
+ * Full filter
281
+ * @example { $or: [ { id: 1 }, { status: 'live' } ] }
282
+ */
283
+ export type FullFilter<T extends AnyObject | void, S extends DBSchema | void> =
284
+ | { $and: FullFilter<T, S>[] }
285
+ | { $or: FullFilter<T, S>[] }
286
+ | FilterItem<AnyObjIfVoid<T>>
287
+ | ExistsFilter<S>
288
+ | ComplexFilter
289
+
290
+ /** Not implemented yet */
291
+ // | { $not: FilterItem<T> }
292
+ ;
293
+
294
+ /**
295
+ * Simpler FullFilter to reduce load on compilation
296
+ */
297
+ export type FullFilterBasic<T = { [key: string]: any }> = {
298
+ [key in keyof Partial<T & { [key: string]: any }>]: any
299
+ }
300
+
301
+
302
+ export const _PG_strings = [
303
+ 'bpchar','char','varchar','text','citext','uuid','bytea', 'time','timetz','interval','name',
304
+ 'cidr', 'inet', 'macaddr', 'macaddr8', "int4range", "int8range", "numrange",
305
+ 'tsvector'
306
+ ] as const;
307
+ export const _PG_numbers = ['int2','int4','int8','float4','float8','numeric','money','oid'] as const;
308
+ export const _PG_json = ['json', 'jsonb'] as const;
309
+ export const _PG_bool = ['bool'] as const;
310
+ export const _PG_date = ['date', 'timestamp', 'timestamptz'] as const;
311
+ export const _PG_interval = ['interval'] as const;
312
+ export const _PG_postgis = ['geometry', 'geography'] as const;
313
+ export const _PG_geometric = [
314
+ "point",
315
+ "line",
316
+ "lseg",
317
+ "box",
318
+ "path",
319
+ "polygon",
320
+ "circle",
321
+ ] as const;
322
+
323
+ export type PG_COLUMN_UDT_DATA_TYPE =
324
+ | typeof _PG_strings[number]
325
+ | typeof _PG_numbers[number]
326
+ | typeof _PG_geometric[number]
327
+ | typeof _PG_json[number]
328
+ | typeof _PG_bool[number]
329
+ | typeof _PG_date[number]
330
+ | typeof _PG_interval[number]
331
+ | typeof _PG_postgis[number];
332
+
333
+ const TS_PG_PRIMITIVES = {
334
+ "string": [ ..._PG_strings, ..._PG_date, ..._PG_geometric, ..._PG_postgis, "lseg"],
335
+ "number": _PG_numbers,
336
+ "boolean": _PG_bool,
337
+ "any": [..._PG_json, ..._PG_interval], // consider as any
338
+
339
+ /** Timestamps are kept in original string format to avoid filters failing
340
+ * TODO: cast to dates if udt_name date/timestamp(0 - 3)
341
+ */
342
+ // "Date": _PG_date,
343
+ } as const;
344
+
345
+ export const TS_PG_Types = {
346
+ ...TS_PG_PRIMITIVES,
347
+ "number[]": TS_PG_PRIMITIVES.number.map(s => `_${s}` as const),
348
+ "boolean[]": TS_PG_PRIMITIVES.boolean.map(s => `_${s}` as const),
349
+ "string[]": TS_PG_PRIMITIVES.string.map(s => `_${s}` as const),
350
+ "any[]": TS_PG_PRIMITIVES.any.map(s => `_${s}` as const),
351
+ // "Date[]": _PG_date.map(s => `_${s}` as const),
352
+ // "any": [],
353
+ } as const;
354
+ export type TS_COLUMN_DATA_TYPES = keyof typeof TS_PG_Types;
355
+
356
+ export type ColumnInfo = {
357
+ name: string;
358
+
359
+ /**
360
+ * Column display name. Will be first non empty value from i18n data, comment, name
361
+ */
362
+ label: string;
363
+
364
+ /**
365
+ * Column description (if provided)
366
+ */
367
+ comment: string;
368
+
369
+ /**
370
+ * Ordinal position of the column within the table (count starts at 1)
371
+ */
372
+ ordinal_position: number;
373
+
374
+ /**
375
+ * True if column is nullable. A not-null constraint is one way a column can be known not nullable, but there may be others.
376
+ */
377
+ is_nullable: boolean;
378
+
379
+ is_updatable: boolean;
380
+
381
+ /**
382
+ * Simplified data type
383
+ */
384
+ data_type: string;
385
+
386
+ /**
387
+ * Postgres raw data types. values starting with underscore means it's an array of that data type
388
+ */
389
+ udt_name: PG_COLUMN_UDT_DATA_TYPE;
390
+
391
+ /**
392
+ * Element data type
393
+ */
394
+ element_type: string;
395
+
396
+ /**
397
+ * Element raw data type
398
+ */
399
+ element_udt_name: string;
400
+
401
+ /**
402
+ * PRIMARY KEY constraint on column. A table can have more then one PK
403
+ */
404
+ is_pkey: boolean;
405
+
406
+ /**
407
+ * Foreign key constraint
408
+ * A column can reference multiple tables
409
+ */
410
+ references?: {
411
+ ftable: string;
412
+ fcols: string[];
413
+ cols: string[];
414
+ }[];
415
+
416
+ /**
417
+ * true if column has a default value
418
+ * Used for excluding pkey from insert
419
+ */
420
+ has_default: boolean;
421
+
422
+ /**
423
+ * Column default value
424
+ */
425
+ column_default?: any;
426
+
427
+ /**
428
+ * Extracted from tableConfig
429
+ * Used in SmartForm
430
+ */
431
+ min?: string | number;
432
+ max?: string | number;
433
+ hint?: string;
434
+
435
+ jsonbSchema?: any;
436
+
437
+ /**
438
+ * If degined then this column is referencing the file table
439
+ * Extracted from FileTable config
440
+ * Used in SmartForm
441
+ */
442
+ file?: any;
443
+
444
+ }
445
+
446
+
447
+ export type ValidatedColumnInfo = ColumnInfo & {
448
+
449
+ /**
450
+ * TypeScript data type
451
+ */
452
+ tsDataType: TS_COLUMN_DATA_TYPES;
453
+
454
+ /**
455
+ * Can be viewed/selected
456
+ */
457
+ select: boolean;
458
+
459
+ /**
460
+ * Can be ordered by
461
+ */
462
+ orderBy: boolean;
463
+
464
+ /**
465
+ * Can be filtered by
466
+ */
467
+ filter: boolean;
468
+
469
+ /**
470
+ * Can be inserted
471
+ */
472
+ insert: boolean;
473
+
474
+ /**
475
+ * Can be updated
476
+ */
477
+ update: boolean;
478
+
479
+ /**
480
+ * Can be used in the delete filter
481
+ */
482
+ delete: boolean;
483
+ }
484
+
485
+
486
+ export type DBSchemaTable = {
487
+ name: string;
488
+ info: TableInfo;
489
+ columns: ValidatedColumnInfo[];
490
+ };
491
+
492
+ /**
493
+ * List of fields to include or exclude
494
+ */
495
+ export type FieldFilter<T extends AnyObject = AnyObject> = SelectTyped<T>
496
+
497
+ export type AscOrDesc = 1 | -1 | boolean;
498
+
499
+ /**
500
+ * @example
501
+ * { product_name: -1 } -> SORT BY product_name DESC
502
+ * [{ field_name: (1 | -1 | boolean) }]
503
+ * true | 1 -> ascending
504
+ * false | -1 -> descending
505
+ * Array order is maintained
506
+ * if nullEmpty is true then empty text will be replaced to null (so nulls sorting takes effect on it)
507
+ */
508
+ export type _OrderBy<T extends AnyObject> =
509
+ | { [K in keyof Partial<T>]: AscOrDesc }
510
+ | { [K in keyof Partial<T>]: AscOrDesc }[]
511
+ | { key: keyof T, asc?: AscOrDesc, nulls?: "last" | "first", nullEmpty?: boolean }[]
512
+ | Array<keyof T>
513
+ | keyof T
514
+ ;
515
+
516
+ export type OrderBy<T extends AnyObject | void = void> = T extends AnyObject? _OrderBy<T> : _OrderBy<AnyObject>;
517
+
518
+ type CommonSelect =
519
+ | "*"
520
+ | ""
521
+ | { "*" : 1 }
522
+
523
+ export type SelectTyped<T extends AnyObject> =
524
+ | { [K in keyof Partial<T>]: 1 | true }
525
+ | { [K in keyof Partial<T>]: 0 | false }
526
+ | (keyof T)[]
527
+ | CommonSelect
528
+ ;
529
+
530
+
531
+ export const JOIN_KEYS = ["$innerJoin", "$leftJoin"] as const;
532
+ export const JOIN_PARAMS = ["select", "filter", "$path", "$condition", "offset", "limit", "orderBy"] as const;
533
+
534
+ export type JoinCondition = {
535
+ column: string;
536
+ rootColumn: string;
537
+ } | ComplexFilter;
538
+
539
+ export type JoinPath = {
540
+ table: string;
541
+ /**
542
+ * {
543
+ * leftColumn: "rightColumn"
544
+ * }
545
+ */
546
+ on?: Record<string, string>[];
547
+ };
548
+ export type RawJoinPath = string | (JoinPath | string)[]
549
+
550
+ export type DetailedJoinSelect = Partial<Record<typeof JOIN_KEYS[number], RawJoinPath>> & {
551
+ select: Select;
552
+ filter?: FullFilter<void, void>;
553
+ offset?: number;
554
+ limit?: number;
555
+ orderBy?: OrderBy;
556
+ } & (
557
+ {
558
+ $condition?: undefined;
559
+ } | {
560
+ /**
561
+ * If present then will overwrite $path and any inferred joins
562
+ */
563
+ $condition?: JoinCondition[];
564
+
565
+ }
566
+ );
567
+
568
+ export type SimpleJoinSelect =
569
+ | "*"
570
+ /** Aliased Shorthand join: table_name: { ...select } */
571
+ | Record<string, 1 | "*" | true | FunctionSelect>
572
+ | Record<string, 0 | false>
573
+
574
+ export type JoinSelect =
575
+ | SimpleJoinSelect
576
+ | DetailedJoinSelect;
577
+
578
+ type FunctionShorthand = string;
579
+ type FunctionFull = Record<string, any[] | readonly any[] | FunctionShorthand>;
580
+ type FunctionSelect = FunctionShorthand | FunctionFull;
581
+ /**
582
+ * { computed_field: { funcName: [args] } }
583
+ */
584
+ type FunctionAliasedSelect = Record<string, FunctionFull>;
585
+
586
+ type InclusiveSelect = true | 1 | FunctionSelect | JoinSelect;
587
+
588
+ type SelectFuncs<T extends AnyObject = AnyObject, IsTyped = false> = (
589
+ | ({ [K in keyof Partial<T>]: InclusiveSelect } & Record<string, IsTyped extends true? FunctionFull : InclusiveSelect>)
590
+ | FunctionAliasedSelect
591
+ | { [K in keyof Partial<T>]: true | 1 | string }
592
+ | { [K in keyof Partial<T>]: 0 | false }
593
+ | CommonSelect
594
+ | (keyof Partial<T>)[]
595
+ );
596
+
597
+ /** S param is needed to ensure the non typed select works fine */
598
+ export type Select<T extends AnyObject | void = void, S extends DBSchema | void = void> = { t: T, s: S } extends { t: AnyObject, s: DBSchema } ? SelectFuncs<T & { $rowhash: string }, true> : SelectFuncs<AnyObject & { $rowhash: string }, false>;
599
+
600
+
601
+ export type SelectBasic =
602
+ | { [key: string]: any }
603
+ | {}
604
+ | undefined
605
+ | ""
606
+ | "*"
607
+ ;
608
+
609
+ /* Simpler types */
610
+ type CommonSelectParams = {
611
+
612
+ /**
613
+ * If null then maxLimit if present will be applied
614
+ * If undefined then 1000 will be applied as the default
615
+ */
616
+ limit?: number | null;
617
+ offset?: number;
618
+
619
+ /**
620
+ * Will group by all non aggregated fields specified in select (or all fields by default)
621
+ */
622
+ groupBy?: boolean;
623
+
624
+ returnType?:
625
+
626
+ /**
627
+ * Will return the first row as an object. Will throw an error if more than a row is returned. Use limit: 1 to avoid error.
628
+ */
629
+ | "row"
630
+
631
+ /**
632
+ * Will return the first value from the selected field
633
+ */
634
+ | "value"
635
+
636
+ /**
637
+ * Will return an array of values from the selected field. Similar to array_agg(field).
638
+ */
639
+ | "values"
640
+
641
+ /**
642
+ * Will return the sql statement. Requires publishRawSQL privileges if called by client
643
+ */
644
+ | "statement"
645
+
646
+ /**
647
+ * Will return the sql statement excluding the user header. Requires publishRawSQL privileges if called by client
648
+ */
649
+ | "statement-no-rls"
650
+
651
+ /**
652
+ * Will return the sql statement where condition. Requires publishRawSQL privileges if called by client
653
+ */
654
+ | "statement-where"
655
+
656
+ }
657
+
658
+ export type SelectParams<T extends AnyObject | void = void, S extends DBSchema | void = void> = CommonSelectParams & {
659
+ select?: Select<T, S>;
660
+ orderBy?: OrderBy<S extends DBSchema? T : void>;
661
+ }
662
+ export type SubscribeParams<T extends AnyObject | void = void, S extends DBSchema | void = void> = SelectParams<T, S> & {
663
+ throttle?: number;
664
+ throttleOpts?: {
665
+ /**
666
+ * False by default.
667
+ * If true then the first value will be emitted at the end of the interval. Instant otherwise
668
+ * */
669
+ skipFirst?: boolean;
670
+ };
671
+ };
672
+
673
+ export type UpdateParams<T extends AnyObject | void = void, S extends DBSchema | void = void> = {
674
+ returning?: Select<T, S>;
675
+ onConflictDoNothing?: boolean;
676
+ fixIssues?: boolean;
677
+
678
+ /* true by default. If false the update will fail if affecting more than one row */
679
+ multi?: boolean;
680
+ } & Pick<CommonSelectParams, "returnType">;
681
+
682
+ export type InsertParams<T extends AnyObject | void = void, S extends DBSchema | void = void> = {
683
+ returning?: Select<T, S>;
684
+ onConflictDoNothing?: boolean;
685
+ fixIssues?: boolean;
686
+ } & Pick<CommonSelectParams, "returnType">;
687
+
688
+ export type DeleteParams<T extends AnyObject | void = void, S extends DBSchema | void = void> = {
689
+ returning?: Select<T, S>;
690
+ } & Pick<CommonSelectParams, "returnType">;
691
+
692
+ export type PartialLax<T = AnyObject> = Partial<T> & AnyObject;
693
+
694
+ export type TableInfo = {
695
+ /**
696
+ * OID from the postgres database
697
+ */
698
+ oid: number;
699
+ /**
700
+ * Comment from the postgres database
701
+ */
702
+ comment?: string;
703
+ /**
704
+ * Defined if this is the fileTable
705
+ */
706
+ isFileTable?: {
707
+ /**
708
+ * Defined if direct inserts are disabled.
709
+ * Only nested inserts through the specified tables/columns are allowed
710
+ * */
711
+ allowedNestedInserts?: {
712
+ table: string;
713
+ column: string;
714
+ }[] | undefined;
715
+ };
716
+
717
+ /**
718
+ * True if fileTable is enabled and this table references the fileTable
719
+ */
720
+ hasFiles?: boolean;
721
+
722
+ isView?: boolean;
723
+
724
+ /**
725
+ * Name of the fileTable (if enabled)
726
+ */
727
+ fileTableName?: string;
728
+
729
+ /**
730
+ * Used for getColumns in cases where the columns are dynamic based on the request.
731
+ * See dynamicFields from Update rules
732
+ */
733
+ dynamicRules?: {
734
+ update?: boolean;
735
+ }
736
+
737
+ /**
738
+ * Additional table info provided through TableConfig
739
+ */
740
+ info?: {
741
+ label?: string;
742
+ }
743
+ }
744
+
745
+ export type OnError = (err: any) => void;
746
+
747
+ type JoinedSelect = Record<string, Select>;
748
+
749
+ type ParseSelect<Select extends SelectParams<TD>["select"], TD extends AnyObject> =
750
+ (Select extends { "*": 1 }? Required<TD> : {})
751
+ & {
752
+ [Key in keyof Omit<Select, "*">]: Select[Key] extends 1? Required<TD>[Key] :
753
+ Select[Key] extends Record<string, any[]>? any : //Function select
754
+ Select[Key] extends JoinedSelect? any[] :
755
+ any;
756
+ }
757
+
758
+ type GetSelectDataType<S extends DBSchema | void, O extends SelectParams<TD, S>, TD extends AnyObject> =
759
+ O extends { returnType: "value" }? any :
760
+ O extends { returnType: "values"; select: Record<string, 1> }? ValueOf<Pick<Required<TD>, keyof O["select"]>> :
761
+ O extends { returnType: "values" }? any :
762
+ O extends { select: "*" }? Required<TD> :
763
+ O extends { select: "" }? Record<string, never> :
764
+ O extends { select: Record<string, 0> }? Omit<Required<TD>, keyof O["select"]> :
765
+ O extends { select: Record<string, any> }? ParseSelect<O["select"], Required<TD>> :
766
+ Required<TD>;
767
+
768
+ export type GetSelectReturnType<S extends DBSchema | void, O extends SelectParams<TD, S>, TD extends AnyObject, isMulti extends boolean> =
769
+ O extends { returnType: "statement" }? string :
770
+ isMulti extends true? GetSelectDataType<S, O, TD>[] :
771
+ GetSelectDataType<S, O, TD>;
772
+
773
+ type GetReturningReturnType<O extends UpdateParams<TD, S>, TD extends AnyObject, S extends DBSchema | void = void> =
774
+ O extends { returning: "*" }? Required<TD> :
775
+ O extends { returning: "" }? Record<string, never> :
776
+ O extends { returning: Record<string, 1> }? Pick<Required<TD>, keyof O["returning"]> :
777
+ O extends { returning: Record<string, 0> }? Omit<Required<TD>, keyof O["returning"]> :
778
+ void;
779
+
780
+ type GetUpdateReturnType<O extends UpdateParams<TD, S>, TD extends AnyObject, S extends DBSchema | void = void> =
781
+ O extends { multi: false }?
782
+ GetReturningReturnType<O, TD, S> :
783
+ GetReturningReturnType<O, TD, S>[];
784
+
785
+ type GetInsertReturnType<Data extends AnyObject | AnyObject[], O extends UpdateParams<TD, S>, TD extends AnyObject, S extends DBSchema | void = void> =
786
+ Data extends any[]?
787
+ GetReturningReturnType<O, TD, S>[] :
788
+ GetReturningReturnType<O, TD, S>;
789
+
790
+ export type SubscriptionHandler = {
791
+ unsubscribe: () => Promise<any>;
792
+ filter: FullFilter<void, void> | {};
793
+ }
794
+
795
+ type GetColumns = (lang?: string, params?: { rule: "update", data: AnyObject, filter: AnyObject }) => Promise<ValidatedColumnInfo[]>;
796
+
797
+ export type ViewHandler<TD extends AnyObject = AnyObject, S extends DBSchema | void = void> = {
798
+ getInfo?: (lang?: string) => Promise<TableInfo>;
799
+ getColumns?: GetColumns
800
+ find: <P extends SelectParams<TD, S>>(filter?: FullFilter<TD, S>, selectParams?: P) => Promise<GetSelectReturnType<S, P, TD, true>>;
801
+ findOne: <P extends SelectParams<TD, S>>(filter?: FullFilter<TD, S>, selectParams?: P) => Promise<undefined | GetSelectReturnType<S, P, TD, false>>;
802
+ subscribe: <P extends SubscribeParams<TD, S>>(
803
+ filter: FullFilter<TD, S>,
804
+ params: P,
805
+ onData: (items: GetSelectReturnType<S, P, TD, true>) => any,
806
+ onError?: OnError
807
+ ) => Promise<SubscriptionHandler>;
808
+ subscribeOne: <P extends SubscribeParams<TD, S>>(
809
+ filter: FullFilter<TD, S>,
810
+ params: P,
811
+ onData: (item: GetSelectReturnType<S, P, TD, false> | undefined) => any,
812
+ onError?: OnError
813
+ ) => Promise<SubscriptionHandler>;
814
+ count: <P extends SelectParams<TD, S>>(filter?: FullFilter<TD, S>, selectParams?: P) => Promise<number>;
815
+ /**
816
+ * Returns result size in bits
817
+ */
818
+ size: <P extends SelectParams<TD, S>>(filter?: FullFilter<TD, S>, selectParams?: P) => Promise<string>;
819
+ }
820
+
821
+ export type UpsertDataToPGCast<TD extends AnyObject = AnyObject> = {
822
+ [K in keyof TD]: CastFromTSToPG<TD[K]>
823
+ };
824
+
825
+ type UpsertDataToPGCastLax<T extends AnyObject> = PartialLax<UpsertDataToPGCast<T>>;
826
+ type InsertData<T extends AnyObject> = UpsertDataToPGCast<T> | UpsertDataToPGCast<T>[]
827
+
828
+ export type TableHandler<TD extends AnyObject = AnyObject, S extends DBSchema | void = void> = ViewHandler<TD, S> & {
829
+ update: <P extends UpdateParams<TD, S>>(filter: FullFilter<TD, S>, newData: UpsertDataToPGCastLax<TD>, params?: P) => Promise<GetUpdateReturnType<P ,TD, S> | undefined>;
830
+ updateBatch: <P extends UpdateParams<TD, S>>(data: [FullFilter<TD, S>, UpsertDataToPGCastLax<TD>][], params?: P) => Promise<GetUpdateReturnType<P ,TD, S> | void>;
831
+ upsert: <P extends UpdateParams<TD, S>>(filter: FullFilter<TD, S>, newData: UpsertDataToPGCastLax<TD>, params?: P) => Promise<GetUpdateReturnType<P ,TD, S>>;
832
+ insert: <P extends InsertParams<TD, S>, D extends InsertData<TD>>(data: D, params?: P ) => Promise<GetInsertReturnType<D, P ,TD, S>>;
833
+ delete: <P extends DeleteParams<TD, S>>(filter?: FullFilter<TD, S>, params?: P) => Promise<GetUpdateReturnType<P ,TD, S> | undefined>;
834
+ }
835
+
836
+ export type JoinMakerOptions<TT extends AnyObject = AnyObject> = SelectParams<TT> & { path?: RawJoinPath };
837
+ export type JoinMaker<TT extends AnyObject = AnyObject, S extends DBSchema | void = void> = (filter?: FullFilter<TT, S>, select?: Select<TT>, options?: JoinMakerOptions<TT> ) => any;
838
+ export type JoinMakerBasic = (filter?: FullFilterBasic, select?: SelectBasic, options?: SelectParams & { path?: RawJoinPath }) => any;
839
+
840
+ export type TableJoin = {
841
+ [key: string]: JoinMaker;
842
+ }
843
+ export type TableJoinBasic = {
844
+ [key: string]: JoinMakerBasic;
845
+ }
846
+
847
+ export type DbJoinMaker = {
848
+ innerJoin: TableJoin;
849
+ leftJoin: TableJoin;
850
+ innerJoinOne: TableJoin;
851
+ leftJoinOne: TableJoin;
852
+ }
853
+
854
+ export type TableHandlers = {
855
+ [key: string]: Partial<TableHandler> | TableHandler;
856
+ };
857
+
858
+
859
+ export type SocketSQLStreamPacket = {
860
+ type: "data";
861
+ fields?: any[];
862
+ rows: any[];
863
+ ended?: boolean;
864
+ info?: SQLResultInfo;
865
+ processId: number;
866
+ } | {
867
+ type: "error";
868
+ error: any;
869
+ };
870
+ export type SocketSQLStreamServer = {
871
+ channel: string;
872
+ unsubChannel: string;
873
+ };
874
+ export type SocketSQLStreamHandlers = {
875
+ run: (query: string, params?: any | any[]) => Promise<void>;
876
+ stop: (terminate?: boolean) => Promise<void>;
877
+ };
878
+ export type SocketSQLStreamClient = SocketSQLStreamServer & {
879
+ start: (listener: (packet: SocketSQLStreamPacket) => void) => Promise<SocketSQLStreamHandlers>
880
+ };
881
+
882
+
883
+ export type DBNoticeConfig = {
884
+ socketChannel: string;
885
+ socketUnsubChannel: string;
886
+ }
887
+ export type DBNotifConfig = DBNoticeConfig & {
888
+ notifChannel: string;
889
+ }
890
+
891
+
892
+ export type SQLOptions = {
893
+ /**
894
+ * Return type of the query
895
+ */
896
+ returnType?: Required<SelectParams>["returnType"] | "statement" | "rows" | "noticeSubscription" | "arrayMode" | "stream";
897
+
898
+ /**
899
+ * If allowListen not specified and a LISTEN query is issued then expect error
900
+ */
901
+ allowListen?: boolean;
902
+
903
+ /**
904
+ * Positive integer that works only with returnType="stream".
905
+ * If provided then the query will be cancelled when the specified number of rows have been streamed
906
+ */
907
+ streamLimit?: number;
908
+
909
+ /**
910
+ * If true then the connection will be persisted and used for subsequent queries
911
+ */
912
+ persistStreamConnection?: boolean;
913
+
914
+ /**
915
+ * connectionId of the stream connection to use
916
+ * Acquired from the first query with persistStreamConnection=true
917
+ */
918
+ streamConnectionId?: string;
919
+
920
+ /**
921
+ * If false then the query will not be checked for params. Used to ignore queries with param like text (e.g.: ${someText} )
922
+ * Defaults to true
923
+ */
924
+ hasParams?: boolean;
925
+ };
926
+
927
+ export type SQLRequest = {
928
+ query: string;
929
+ params?: any | any[];
930
+ options?: SQLOptions
931
+ }
932
+
933
+ export type NotifSubscription = {
934
+ socketChannel: string;
935
+ socketUnsubChannel: string;
936
+ notifChannel: string;
937
+ }
938
+
939
+ export type NoticeSubscription = {
940
+ socketChannel: string;
941
+ socketUnsubChannel: string;
942
+ }
943
+
944
+ export type DBEventHandles = {
945
+ socketChannel: string;
946
+ socketUnsubChannel: string;
947
+ addListener: (listener: (event: any) => void) => { removeListener: () => void; }
948
+ };
949
+
950
+ export type CheckForListen<T, O extends SQLOptions> = O["allowListen"] extends true? (DBEventHandles | T) : T;
951
+
952
+ export type SQLResultInfo = {
953
+ command: "SELECT" | "UPDATE" | "DELETE" | "CREATE" | "ALTER" | "LISTEN" | "UNLISTEN" | "INSERT" | string;
954
+ rowCount: number;
955
+ duration: number;
956
+ }
957
+ export type SQLResult<T extends SQLOptions["returnType"]> = SQLResultInfo & {
958
+ rows: (T extends "arrayMode"? any : AnyObject)[];
959
+ fields: {
960
+ name: string;
961
+ dataType: string;
962
+ udt_name: PG_COLUMN_UDT_DATA_TYPE;
963
+ tsDataType: TS_COLUMN_DATA_TYPES;
964
+ tableID?: number;
965
+ tableName?: string;
966
+ tableSchema?: string;
967
+ columnID?: number;
968
+ columnName?: string;
969
+ }[];
970
+ }
971
+ export type GetSQLReturnType<O extends SQLOptions> = CheckForListen<
972
+ (
973
+ O["returnType"] extends "row"? AnyObject | null :
974
+ O["returnType"] extends "rows"? AnyObject[] :
975
+ O["returnType"] extends "value"? any | null :
976
+ O["returnType"] extends "values"? any[] :
977
+ O["returnType"] extends "statement"? string :
978
+ O["returnType"] extends "noticeSubscription"? DBEventHandles :
979
+ O["returnType"] extends "stream"? SocketSQLStreamClient :
980
+ SQLResult<O["returnType"]>
981
+ )
982
+ , O>;
983
+
984
+ export type SQLHandler =
985
+ /**
986
+ *
987
+ * @param query <string> query. e.g.: SELECT * FROM users;
988
+ * @param params <any[] | object> query arguments to be escaped. e.g.: { name: 'dwadaw' }
989
+ * @param options <object> { returnType: "statement" | "rows" | "noticeSubscription" }
990
+ */
991
+ <Opts extends SQLOptions>(
992
+ query: string,
993
+ args?: AnyObject | any[],
994
+ options?: Opts,
995
+ serverSideOptions?: {
996
+ socket: any
997
+ } | {
998
+ httpReq: any;
999
+ }
1000
+ ) => Promise<GetSQLReturnType<Opts>>
1001
+
1002
+
1003
+ export type DbTxTableHandlers = {
1004
+ [key: string]: Omit<Partial<TableHandler>, "dbTx"> | Omit<TableHandler, "dbTx">;
1005
+ };
1006
+ export type TxCB<TH = DbTxTableHandlers> = {
1007
+ (t: TH & Pick<DBHandlerServer, "sql">, _t: any): (any | void);
1008
+ };
1009
+ export type TX<TH = TableHandlers> = {
1010
+ (t: TxCB<TH>): Promise<(any | void)>;
1011
+ };
1012
+ export type DBHandlerServer<TH = TableHandlers> = TH & Partial<DbJoinMaker> & {
1013
+ sql?: SQLHandler;
1014
+ } & {
1015
+ tx?: TX<TH>;
1016
+ };
1017
+ export type DBTableHandlersFromSchema<Schema = void> = Schema extends DBSchema ? {
1018
+ [tov_name in keyof Schema]: Schema[tov_name]["is_view"] extends true ? ViewHandler<Schema[tov_name]["columns"]> : TableHandler<Schema[tov_name]["columns"]>;
1019
+ } : Record<string, TableHandler>;
1020
+ export type DBOFullyTyped<Schema = void> = (DBTableHandlersFromSchema<Schema> & Pick<DBHandlerServer<DBTableHandlersFromSchema<Schema>>, "tx" | "sql">);