pqb 0.0.1

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.
Files changed (122) hide show
  1. package/dist/index.d.ts +3630 -0
  2. package/dist/index.esm.js +4587 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +4691 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +59 -0
  7. package/rollup.config.js +35 -0
  8. package/src/adapter.test.ts +10 -0
  9. package/src/adapter.ts +171 -0
  10. package/src/columnSchema/array.ts +21 -0
  11. package/src/columnSchema/boolean.ts +10 -0
  12. package/src/columnSchema/columnType.test.ts +129 -0
  13. package/src/columnSchema/columnType.ts +77 -0
  14. package/src/columnSchema/columnTypes.ts +145 -0
  15. package/src/columnSchema/columnsSchema.test.ts +32 -0
  16. package/src/columnSchema/columnsSchema.ts +100 -0
  17. package/src/columnSchema/commonMethods.ts +130 -0
  18. package/src/columnSchema/dateTime.ts +104 -0
  19. package/src/columnSchema/enum.ts +13 -0
  20. package/src/columnSchema/index.ts +11 -0
  21. package/src/columnSchema/json/array.ts +55 -0
  22. package/src/columnSchema/json/discriminatedUnion.ts +91 -0
  23. package/src/columnSchema/json/enum.ts +29 -0
  24. package/src/columnSchema/json/instanceOf.ts +16 -0
  25. package/src/columnSchema/json/intersection.ts +23 -0
  26. package/src/columnSchema/json/lazy.ts +22 -0
  27. package/src/columnSchema/json/literal.ts +12 -0
  28. package/src/columnSchema/json/map.ts +29 -0
  29. package/src/columnSchema/json/nativeEnum.ts +30 -0
  30. package/src/columnSchema/json/nullable.ts +33 -0
  31. package/src/columnSchema/json/nullish.ts +30 -0
  32. package/src/columnSchema/json/object.ts +206 -0
  33. package/src/columnSchema/json/optional.ts +28 -0
  34. package/src/columnSchema/json/record.ts +40 -0
  35. package/src/columnSchema/json/scalarTypes.ts +117 -0
  36. package/src/columnSchema/json/set.ts +34 -0
  37. package/src/columnSchema/json/tuple.ts +40 -0
  38. package/src/columnSchema/json/typeBase.ts +202 -0
  39. package/src/columnSchema/json/union.ts +16 -0
  40. package/src/columnSchema/json.ts +64 -0
  41. package/src/columnSchema/number.ts +122 -0
  42. package/src/columnSchema/string.ts +222 -0
  43. package/src/columnSchema/utils.ts +27 -0
  44. package/src/common.ts +86 -0
  45. package/src/db.test.ts +67 -0
  46. package/src/db.ts +212 -0
  47. package/src/errors.ts +7 -0
  48. package/src/index.ts +18 -0
  49. package/src/operators.test.ts +608 -0
  50. package/src/operators.ts +177 -0
  51. package/src/query.ts +292 -0
  52. package/src/queryDataUtils.ts +50 -0
  53. package/src/queryMethods/aggregate.test.ts +583 -0
  54. package/src/queryMethods/aggregate.ts +878 -0
  55. package/src/queryMethods/callbacks.test.ts +69 -0
  56. package/src/queryMethods/callbacks.ts +55 -0
  57. package/src/queryMethods/clear.test.ts +64 -0
  58. package/src/queryMethods/clear.ts +58 -0
  59. package/src/queryMethods/columnInfo.test.ts +45 -0
  60. package/src/queryMethods/columnInfo.ts +67 -0
  61. package/src/queryMethods/delete.test.ts +135 -0
  62. package/src/queryMethods/delete.ts +50 -0
  63. package/src/queryMethods/for.test.ts +57 -0
  64. package/src/queryMethods/for.ts +99 -0
  65. package/src/queryMethods/from.test.ts +66 -0
  66. package/src/queryMethods/from.ts +58 -0
  67. package/src/queryMethods/get.test.ts +66 -0
  68. package/src/queryMethods/get.ts +88 -0
  69. package/src/queryMethods/having.test.ts +247 -0
  70. package/src/queryMethods/having.ts +99 -0
  71. package/src/queryMethods/insert.test.ts +555 -0
  72. package/src/queryMethods/insert.ts +453 -0
  73. package/src/queryMethods/join.test.ts +150 -0
  74. package/src/queryMethods/join.ts +508 -0
  75. package/src/queryMethods/json.test.ts +398 -0
  76. package/src/queryMethods/json.ts +259 -0
  77. package/src/queryMethods/log.test.ts +172 -0
  78. package/src/queryMethods/log.ts +123 -0
  79. package/src/queryMethods/queryMethods.test.ts +629 -0
  80. package/src/queryMethods/queryMethods.ts +428 -0
  81. package/src/queryMethods/select.test.ts +479 -0
  82. package/src/queryMethods/select.ts +249 -0
  83. package/src/queryMethods/then.ts +236 -0
  84. package/src/queryMethods/transaction.test.ts +66 -0
  85. package/src/queryMethods/transaction.ts +66 -0
  86. package/src/queryMethods/union.test.ts +59 -0
  87. package/src/queryMethods/union.ts +89 -0
  88. package/src/queryMethods/update.test.ts +417 -0
  89. package/src/queryMethods/update.ts +350 -0
  90. package/src/queryMethods/upsert.test.ts +56 -0
  91. package/src/queryMethods/upsert.ts +43 -0
  92. package/src/queryMethods/where.test.ts +1594 -0
  93. package/src/queryMethods/where.ts +450 -0
  94. package/src/queryMethods/window.test.ts +66 -0
  95. package/src/queryMethods/window.ts +108 -0
  96. package/src/queryMethods/with.test.ts +191 -0
  97. package/src/queryMethods/with.ts +92 -0
  98. package/src/quote.ts +36 -0
  99. package/src/relations.ts +194 -0
  100. package/src/sql/aggregate.ts +80 -0
  101. package/src/sql/columnInfo.ts +22 -0
  102. package/src/sql/common.ts +42 -0
  103. package/src/sql/delete.ts +41 -0
  104. package/src/sql/distinct.ts +19 -0
  105. package/src/sql/fromAndAs.ts +51 -0
  106. package/src/sql/having.ts +140 -0
  107. package/src/sql/index.ts +2 -0
  108. package/src/sql/insert.ts +102 -0
  109. package/src/sql/join.ts +242 -0
  110. package/src/sql/orderBy.ts +41 -0
  111. package/src/sql/select.ts +153 -0
  112. package/src/sql/toSql.ts +153 -0
  113. package/src/sql/truncate.ts +13 -0
  114. package/src/sql/types.ts +355 -0
  115. package/src/sql/update.ts +62 -0
  116. package/src/sql/where.ts +314 -0
  117. package/src/sql/window.ts +38 -0
  118. package/src/sql/with.ts +32 -0
  119. package/src/test-utils.ts +172 -0
  120. package/src/utils.ts +140 -0
  121. package/tsconfig.build.json +6 -0
  122. package/tsconfig.json +8 -0
@@ -0,0 +1,100 @@
1
+ import { ColumnInput, ColumnOutput, ColumnType } from './columnType';
2
+ import { Operators } from '../operators';
3
+ import { UnionToIntersection } from '../utils';
4
+
5
+ export type ColumnsShape = Record<string, ColumnType>;
6
+
7
+ export type ColumnShapeOutput<Shape extends ColumnsShape> = {
8
+ [K in keyof Shape]: ColumnOutput<Shape[K]>;
9
+ };
10
+
11
+ export type ColumnShapeInput<Shape extends ColumnsShape> = {
12
+ [K in keyof Shape]: ColumnInput<Shape[K]>;
13
+ };
14
+
15
+ export class ColumnsObject<Shape extends ColumnsShape> extends ColumnType<
16
+ { [K in keyof Shape]: Shape[K]['type'] },
17
+ typeof Operators.any
18
+ > {
19
+ dataType = 'object';
20
+ operators = Operators.any;
21
+
22
+ constructor(public shape: Shape) {
23
+ super();
24
+ }
25
+ }
26
+
27
+ export class ArrayOfColumnsObjects<
28
+ Shape extends ColumnsShape,
29
+ > extends ColumnType<
30
+ { [K in keyof Shape]: Shape[K]['type'] }[],
31
+ typeof Operators.any
32
+ > {
33
+ dataType = 'array';
34
+ operators = Operators.any;
35
+
36
+ constructor(public shape: Shape) {
37
+ super();
38
+ }
39
+ }
40
+
41
+ type UnionKeyofToOvlds<S, U> = UnionToIntersection<
42
+ U extends keyof S ? (f: U) => void : never
43
+ >;
44
+
45
+ type PopKeyofColumnShapeUnion<
46
+ S extends ColumnsShape,
47
+ U extends keyof S,
48
+ > = UnionKeyofToOvlds<S, U> extends (a: infer A extends keyof S) => void
49
+ ? A
50
+ : never;
51
+
52
+ type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
53
+
54
+ export type UnionToArray<
55
+ S extends ColumnsShape,
56
+ T extends keyof S,
57
+ A extends [...(keyof S)[]] = [],
58
+ > = IsUnion<T> extends true
59
+ ? UnionToArray<
60
+ S,
61
+ Exclude<T, PopKeyofColumnShapeUnion<S, T>>,
62
+ [PopKeyofColumnShapeUnion<S, T>, ...A]
63
+ >
64
+ : [T, ...A];
65
+
66
+ type GetPrimaryKeys<S extends ColumnsShape> = UnionToArray<
67
+ S,
68
+ { [K in keyof S]: S[K] extends { isPrimaryKey: true } ? K : never }[keyof S]
69
+ >;
70
+
71
+ type GetPrimaryTypes<
72
+ S extends ColumnsShape,
73
+ Keys extends [...(keyof S | string)[]] = GetPrimaryKeys<S>,
74
+ > = GetTypesFromKeys<S, Keys>;
75
+
76
+ type GetTypesFromKeys<
77
+ S extends ColumnsShape,
78
+ T extends [...(keyof S)[]],
79
+ > = T extends [
80
+ infer Head extends keyof S,
81
+ ...infer Tail extends [...(keyof S)[]],
82
+ ]
83
+ ? [GetTypeFromKey<S, Head>, ...GetTypesFromKeys<S, Tail>]
84
+ : [];
85
+
86
+ type GetTypeFromKey<S extends ColumnsShape, T extends keyof S> = S[T]['type'];
87
+
88
+ export class TableSchema<Shape extends ColumnsShape> {
89
+ primaryKeys: string extends keyof Shape ? string[] : GetPrimaryKeys<Shape>;
90
+ primaryTypes!: GetPrimaryTypes<Shape>;
91
+
92
+ constructor(public shape: Shape) {
93
+ this.primaryKeys = Object.entries(this.shape)
94
+ .filter(([, column]) => {
95
+ return column.isPrimaryKey;
96
+ })
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ .map(([key]) => key) as any;
99
+ }
100
+ }
@@ -0,0 +1,130 @@
1
+ import { BaseStringData } from './string';
2
+ import { BaseNumberData } from './number';
3
+
4
+ export type ArrayMethods = typeof arrayMethods;
5
+
6
+ export const arrayMethods = {
7
+ min<T extends { data: { min?: number } }, Value extends number>(
8
+ this: T,
9
+ value: Value,
10
+ ) {
11
+ this.data.min = value;
12
+ return this as T & { data: Omit<T['data'], 'min'> & { min: Value } };
13
+ },
14
+
15
+ max<T extends { data: { max?: number } }, Value extends number>(
16
+ this: T,
17
+ value: Value,
18
+ ) {
19
+ this.data.max = value;
20
+ return this as T & { data: Omit<T['data'], 'max'> & { max: Value } };
21
+ },
22
+
23
+ length<T extends { data: { length?: number } }, Value extends number>(
24
+ this: T,
25
+ value: Value,
26
+ ) {
27
+ this.data.length = value;
28
+ return this as T & { data: Omit<T['data'], 'length'> & { length: Value } };
29
+ },
30
+ };
31
+
32
+ export const stringTypeMethods = <Base extends { data: BaseStringData }>() => ({
33
+ ...arrayMethods,
34
+
35
+ email<T extends Base>(this: T) {
36
+ this.data.email = true;
37
+ return this as T & { data: Omit<T['data'], 'email'> & { email: true } };
38
+ },
39
+
40
+ url<T extends Base>(this: T) {
41
+ this.data.url = true;
42
+ return this as T & { data: Omit<T['data'], 'url'> & { url: true } };
43
+ },
44
+
45
+ uuid<T extends Base>(this: T) {
46
+ this.data.uuid = true;
47
+ return this as T & { data: Omit<T['data'], 'uuid'> & { uuid: true } };
48
+ },
49
+
50
+ cuid<T extends Base>(this: T) {
51
+ this.data.cuid = true;
52
+ return this as T & { data: Omit<T['data'], 'cuid'> & { cuid: true } };
53
+ },
54
+
55
+ regex<T extends Base, Value extends RegExp>(this: T, value: Value) {
56
+ this.data.regex = value;
57
+ return this as T & { data: Omit<T['data'], 'regex'> & { regex: Value } };
58
+ },
59
+
60
+ trim<T extends Base>(this: T) {
61
+ this.data.trim = true;
62
+ return this as T & { data: Omit<T['data'], 'cuid'> & { trim: true } };
63
+ },
64
+ });
65
+
66
+ export const numberTypeMethods = <Base extends { data: BaseNumberData }>() => ({
67
+ lt<T extends Base, Value extends number>(this: T, value: Value) {
68
+ this.data.lt = value;
69
+ return this as T & { data: Omit<T['data'], 'lt'> & { lt: Value } };
70
+ },
71
+
72
+ lte<T extends Base, Value extends number>(this: T, value: Value) {
73
+ this.data.lte = value;
74
+ return this as T & { data: Omit<T['data'], 'lte'> & { lte: Value } };
75
+ },
76
+
77
+ max<T extends Base, Value extends number>(this: T, value: Value) {
78
+ this.data.lte = value;
79
+ return this as T & { data: Omit<T['data'], 'lte'> & { lte: Value } };
80
+ },
81
+
82
+ gt<T extends Base, Value extends number>(this: T, value: Value) {
83
+ this.data.gt = value;
84
+ return this as T & { data: Omit<T['data'], 'gt'> & { gt: Value } };
85
+ },
86
+
87
+ gte<T extends Base, Value extends number>(this: T, value: Value) {
88
+ this.data.gte = value;
89
+ return this as T & { data: Omit<T['data'], 'gte'> & { gte: Value } };
90
+ },
91
+
92
+ min<T extends Base, Value extends number>(this: T, value: Value) {
93
+ this.data.gte = value;
94
+ return this as T & { data: Omit<T['data'], 'gte'> & { gte: Value } };
95
+ },
96
+
97
+ positive<T extends Base>(this: T) {
98
+ this.data.gt = 0;
99
+ return this as T & { data: Omit<T['data'], 'gt'> & { gt: 0 } };
100
+ },
101
+
102
+ nonNegative<T extends Base>(this: T) {
103
+ this.data.gte = 0;
104
+ return this as T & { data: Omit<T['data'], 'gte'> & { gte: 0 } };
105
+ },
106
+
107
+ negative<T extends Base>(this: T) {
108
+ this.data.lt = 0;
109
+ return this as T & { data: Omit<T['data'], 'lt'> & { lt: 0 } };
110
+ },
111
+
112
+ nonPositive<T extends Base>(this: T) {
113
+ this.data.lte = 0;
114
+ return this as T & { data: Omit<T['data'], 'lte'> & { lte: 0 } };
115
+ },
116
+
117
+ multipleOf<T extends Base, Value extends number>(this: T, value: Value) {
118
+ this.data.multipleOf = value;
119
+ return this as T & {
120
+ data: Omit<T['data'], 'multipleOf'> & { multipleOf: Value };
121
+ };
122
+ },
123
+
124
+ step<T extends Base, Value extends number>(this: T, value: Value) {
125
+ this.data.multipleOf = value;
126
+ return this as T & {
127
+ data: Omit<T['data'], 'multipleOf'> & { multipleOf: Value };
128
+ };
129
+ },
130
+ });
@@ -0,0 +1,104 @@
1
+ import { ColumnType } from './columnType';
2
+ import { Operators } from '../operators';
3
+ import { joinTruthy } from '../utils';
4
+
5
+ // date 4 bytes date (no time of day) 4713 BC 5874897 AD 1 day
6
+ export class DateColumn extends ColumnType<string, typeof Operators.date> {
7
+ dataType = 'date' as const;
8
+ operators = Operators.date;
9
+ }
10
+
11
+ export interface DateTimeColumnData {
12
+ precision?: number;
13
+ }
14
+
15
+ export abstract class DateTimeBaseClass<
16
+ Precision extends number | undefined = undefined,
17
+ > extends ColumnType<string, typeof Operators.date, string | number | Date> {
18
+ data: DateTimeColumnData & { precision: Precision };
19
+ operators = Operators.date;
20
+
21
+ constructor(precision?: Precision) {
22
+ super();
23
+
24
+ this.data = { precision } as DateTimeColumnData & { precision: Precision };
25
+ }
26
+
27
+ toSQL() {
28
+ return joinTruthy(
29
+ this.dataType,
30
+ this.data.precision !== undefined && `(${this.data.precision})`,
31
+ );
32
+ }
33
+ }
34
+
35
+ export abstract class DateTimeWithTimeZoneBaseClass<
36
+ Precision extends number | undefined = undefined,
37
+ > extends DateTimeBaseClass<Precision> {
38
+ abstract baseDataType: string;
39
+
40
+ toSQL() {
41
+ return joinTruthy(
42
+ this.baseDataType,
43
+ this.data.precision !== undefined && `(${this.data.precision})`,
44
+ ' with time zone',
45
+ );
46
+ }
47
+ }
48
+
49
+ // timestamp [ (p) ] [ without time zone ] 8 bytes both date and time (no time zone) 4713 BC 294276 AD 1 microsecond
50
+ export class TimestampColumn<
51
+ Precision extends number | undefined = undefined,
52
+ > extends DateTimeBaseClass<Precision> {
53
+ dataType = 'timestamp' as const;
54
+ }
55
+
56
+ // timestamp [ (p) ] with time zone 8 bytes both date and time, with time zone 4713 BC 294276 AD 1 microsecond
57
+ export class TimestampWithTimeZoneColumn<
58
+ Precision extends number | undefined = undefined,
59
+ > extends DateTimeWithTimeZoneBaseClass<Precision> {
60
+ dataType = 'timestamp with time zone' as const;
61
+ baseDataType = 'timestamp' as const;
62
+ }
63
+
64
+ // time [ (p) ] [ without time zone ] 8 bytes time of day (no date) 00:00:00 24:00:00 1 microsecond
65
+ export class TimeColumn<
66
+ Precision extends number | undefined = undefined,
67
+ > extends DateTimeBaseClass<Precision> {
68
+ dataType = 'time' as const;
69
+ }
70
+
71
+ // time [ (p) ] with time zone 12 bytes time of day (no date), with time zone 00:00:00+1559 24:00:00-1559 1 microsecond
72
+ export class TimeWithTimeZoneColumn<
73
+ Precision extends number | undefined = undefined,
74
+ > extends DateTimeWithTimeZoneBaseClass<Precision> {
75
+ dataType = 'time with time zone' as const;
76
+ baseDataType = 'time' as const;
77
+ }
78
+
79
+ // interval [ fields ] [ (p) ] 16 bytes time interval -178000000 years 178000000 years 1 microsecond
80
+ export class IntervalColumn<
81
+ Fields extends string | undefined = undefined,
82
+ Precision extends number | undefined = undefined,
83
+ > extends ColumnType<string, typeof Operators.date> {
84
+ dataType = 'interval' as const;
85
+ data: DateTimeColumnData & { fields: Fields; precision: Precision };
86
+ operators = Operators.date;
87
+
88
+ constructor(fields?: Fields, precision?: Precision) {
89
+ super();
90
+
91
+ this.data = { fields, precision } as DateTimeColumnData & {
92
+ fields: Fields;
93
+ precision: Precision;
94
+ };
95
+ }
96
+
97
+ toSQL() {
98
+ return joinTruthy(
99
+ this.dataType,
100
+ this.data.fields && ` ${this.data.fields}`,
101
+ this.data.precision !== undefined && ` (${this.data.precision})`,
102
+ );
103
+ }
104
+ }
@@ -0,0 +1,13 @@
1
+ import { ColumnType } from './columnType';
2
+ import { Operators } from '../operators';
3
+
4
+ export class EnumColumn<DataType extends string, Type> extends ColumnType<
5
+ Type,
6
+ typeof Operators.any
7
+ > {
8
+ operators = Operators.any;
9
+
10
+ constructor(public dataType: DataType) {
11
+ super();
12
+ }
13
+ }
@@ -0,0 +1,11 @@
1
+ export * from './columnType';
2
+ export * from './columnTypes';
3
+ export * from './columnsSchema';
4
+ export * as columnUtils from './utils';
5
+ export * from './number';
6
+ export * from './string';
7
+ export * from './dateTime';
8
+ export * from './boolean';
9
+ export * from './enum';
10
+ export * from './json';
11
+ export * from './array';
@@ -0,0 +1,55 @@
1
+ import {
2
+ constructType,
3
+ DeepPartial,
4
+ JSONType,
5
+ JSONTypeAny,
6
+ JSONTypeData,
7
+ } from './typeBase';
8
+ import { arrayMethods, ArrayMethods } from '../commonMethods';
9
+
10
+ export type ArrayCardinality = 'many' | 'atLeastOne';
11
+
12
+ type arrayOutputType<
13
+ T extends JSONTypeAny,
14
+ Cardinality extends ArrayCardinality = 'many',
15
+ > = Cardinality extends 'atLeastOne'
16
+ ? [T['type'], ...T['type'][]]
17
+ : T['type'][];
18
+
19
+ export interface JSONArray<
20
+ Type extends JSONTypeAny,
21
+ Cardinality extends ArrayCardinality = 'many',
22
+ > extends JSONType<arrayOutputType<Type, Cardinality>, 'array'>,
23
+ ArrayMethods {
24
+ data: JSONTypeData & {
25
+ min?: number;
26
+ max?: number;
27
+ length?: number;
28
+ };
29
+ element: Type;
30
+ deepPartial(): JSONArray<DeepPartial<Type>, Cardinality>;
31
+ nonEmpty(
32
+ this: JSONArray<Type>,
33
+ ): JSONArray<Type, 'atLeastOne'> & { data: { min: 1 } };
34
+ }
35
+
36
+ export const array = <Type extends JSONTypeAny>(
37
+ element: Type,
38
+ ): JSONArray<Type> => {
39
+ return constructType<JSONArray<Type>>({
40
+ dataType: 'array' as const,
41
+ element,
42
+ deepPartial(this: JSONArray<Type>) {
43
+ return {
44
+ ...this,
45
+ element: this.element.deepPartial(),
46
+ };
47
+ },
48
+ nonEmpty(this: JSONArray<Type>) {
49
+ return this.min(1) as unknown as JSONArray<Type, 'atLeastOne'> & {
50
+ data: { min: 1 };
51
+ };
52
+ },
53
+ ...arrayMethods,
54
+ });
55
+ };
@@ -0,0 +1,91 @@
1
+ import { constructType, JSONType, Primitive } from './typeBase';
2
+ import { JSONObject } from './object';
3
+ import { JSONLiteral } from './literal';
4
+
5
+ export interface JSONDiscriminatedUnion<
6
+ Discriminator extends string,
7
+ Options extends DiscriminatedOptions<Discriminator>,
8
+ > extends JSONType<Options[number]['type'], 'discriminatedUnion'> {
9
+ discriminator: Discriminator;
10
+ options: OptionsMap<Discriminator, Options>;
11
+ // TODO: gave up on deepPartial type
12
+ // deepPartial(): JSONDiscriminatedUnion<
13
+ // Discriminator,
14
+ // {
15
+ // [Index in keyof Options]: {
16
+ // [K in keyof Options[Index]['shape']]: K extends Discriminator
17
+ // ? Options[Index]['shape'][K]
18
+ // : JSONOptional<Options[Index]['shape'][K]>;
19
+ // } extends JSONObject<Record<Discriminator, JSONLiteral<Primitive>>>
20
+ // ? JSONObject<
21
+ // {
22
+ // [K in keyof Options[Index]['shape']]: K extends Discriminator
23
+ // ? Options[Index]['shape'][K]
24
+ // : JSONOptional<Options[Index]['shape'][K]>;
25
+ // },
26
+ // Options[Index]['unknownKeys'],
27
+ // Options[Index]['catchAllType']
28
+ // >
29
+ // : Options[Index];
30
+ // } & {
31
+ // length: Options['length'];
32
+ // }
33
+ // >;
34
+ }
35
+
36
+ type JSONDiscriminatedObject<Discriminator extends string> = JSONObject<
37
+ Record<Discriminator, JSONLiteral<Primitive>>
38
+ >;
39
+
40
+ type DiscriminatedOptions<Discriminator extends string> = readonly [
41
+ JSONDiscriminatedObject<Discriminator>,
42
+ JSONDiscriminatedObject<Discriminator>,
43
+ ...JSONDiscriminatedObject<Discriminator>[],
44
+ ];
45
+
46
+ type OptionsMap<
47
+ Discriminator extends string,
48
+ Options extends DiscriminatedOptions<Discriminator>,
49
+ > = Map<Options[number]['shape'][Discriminator]['value'], Options[number]>;
50
+
51
+ export const discriminatedUnion = <
52
+ Discriminator extends string,
53
+ Options extends DiscriminatedOptions<Discriminator>,
54
+ >(
55
+ discriminator: Discriminator,
56
+ options: Options,
57
+ ) => {
58
+ const optionsMap: OptionsMap<
59
+ Discriminator,
60
+ DiscriminatedOptions<Discriminator>
61
+ > = new Map();
62
+
63
+ options.forEach((option) => {
64
+ const discriminatorValue = option.shape[discriminator].value;
65
+ optionsMap.set(discriminatorValue, option);
66
+ });
67
+
68
+ return constructType<JSONDiscriminatedUnion<Discriminator, Options>>({
69
+ dataType: 'discriminatedUnion',
70
+ discriminator,
71
+ options: optionsMap,
72
+ deepPartial(this: JSONDiscriminatedUnion<Discriminator, Options>) {
73
+ const newOptionsMap: OptionsMap<
74
+ Discriminator,
75
+ DiscriminatedOptions<Discriminator>
76
+ > = new Map();
77
+
78
+ optionsMap.forEach((option, key) => {
79
+ const partial =
80
+ option.deepPartial() as unknown as JSONDiscriminatedObject<Discriminator>;
81
+ partial.shape[discriminator] = option.shape[discriminator];
82
+ newOptionsMap.set(key, partial);
83
+ });
84
+
85
+ return {
86
+ ...this,
87
+ options: newOptionsMap,
88
+ };
89
+ },
90
+ });
91
+ };
@@ -0,0 +1,29 @@
1
+ import { constructType, JSONType } from './typeBase';
2
+
3
+ export interface JSONEnum<T extends EnumValues>
4
+ extends JSONType<T[number], 'enum'> {
5
+ enum: { [k in T[number]]: k };
6
+ options: T;
7
+ }
8
+
9
+ type EnumValues = readonly [string, ...string[]];
10
+
11
+ export const arrayToEnum = <T extends string, U extends readonly [T, ...T[]]>(
12
+ items: U,
13
+ ) => {
14
+ const obj = {} as { [k in U[number]]: k };
15
+ for (const item of items) {
16
+ obj[item] = item;
17
+ }
18
+ return obj;
19
+ };
20
+
21
+ export const enumType = <T extends readonly [string, ...string[]]>(
22
+ options: T,
23
+ ) => {
24
+ return constructType<JSONEnum<T>>({
25
+ dataType: 'enum',
26
+ enum: arrayToEnum(options),
27
+ options,
28
+ });
29
+ };
@@ -0,0 +1,16 @@
1
+ import { constructType, JSONType } from './typeBase';
2
+
3
+ export interface JSONInstanceOf<T extends Class>
4
+ extends JSONType<T, 'instanceOf'> {
5
+ class: T;
6
+ }
7
+
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ type Class = new (...args: any[]) => any;
10
+
11
+ export const instanceOf = <T extends Class>(cls: T) => {
12
+ return constructType<JSONInstanceOf<T>>({
13
+ dataType: 'instanceOf',
14
+ class: cls,
15
+ });
16
+ };
@@ -0,0 +1,23 @@
1
+ import { constructType, JSONType, JSONTypeAny } from './typeBase';
2
+
3
+ export type JSONIntersection<
4
+ Left extends JSONTypeAny,
5
+ Right extends JSONTypeAny,
6
+ > = JSONType<Left['type'] & Right['type'], 'intersection'> & {
7
+ left: Left;
8
+ right: Right;
9
+ };
10
+
11
+ export const intersection = <
12
+ Left extends JSONTypeAny,
13
+ Right extends JSONTypeAny,
14
+ >(
15
+ left: Left,
16
+ right: Right,
17
+ ) => {
18
+ return constructType<JSONIntersection<Left, Right>>({
19
+ dataType: 'intersection',
20
+ left,
21
+ right,
22
+ });
23
+ };
@@ -0,0 +1,22 @@
1
+ import { constructType, JSONType, JSONTypeAny } from './typeBase';
2
+
3
+ export interface JSONLazy<T extends JSONTypeAny>
4
+ extends JSONType<T['type'], 'lazy'> {
5
+ typeCache?: T;
6
+ getter(): T;
7
+ deepPartial(): JSONLazy<ReturnType<T['deepPartial']>>;
8
+ }
9
+
10
+ export const lazy = <T extends JSONTypeAny>(fn: () => T) => {
11
+ constructType<JSONLazy<T>>({
12
+ dataType: 'lazy',
13
+ getter: fn,
14
+ deepPartial(this: JSONLazy<T>) {
15
+ return {
16
+ ...this,
17
+ typeCache: undefined,
18
+ getter: () => this.getter().deepPartial(),
19
+ };
20
+ },
21
+ });
22
+ };
@@ -0,0 +1,12 @@
1
+ import { constructType, JSONType, Primitive } from './typeBase';
2
+
3
+ export interface JSONLiteral<T extends Primitive>
4
+ extends JSONType<T, 'literal'> {
5
+ value: Primitive;
6
+ }
7
+
8
+ export const literal = <T extends Primitive>(value: T) =>
9
+ constructType<JSONLiteral<T>>({
10
+ dataType: 'literal',
11
+ value,
12
+ });
@@ -0,0 +1,29 @@
1
+ import { constructType, JSONType, JSONTypeAny } from './typeBase';
2
+
3
+ export interface JSONMap<Key extends JSONTypeAny, Value extends JSONTypeAny>
4
+ extends JSONType<Map<Key['type'], Value['type']>, 'map'> {
5
+ keyType: Key;
6
+ valueType: Value;
7
+ deepPartial(): JSONMap<
8
+ ReturnType<Key['deepPartial']>,
9
+ ReturnType<Value['deepPartial']>
10
+ >;
11
+ }
12
+
13
+ export const map = <Key extends JSONTypeAny, Value extends JSONTypeAny>(
14
+ keyType: Key,
15
+ valueType: Value,
16
+ ) => {
17
+ return constructType<JSONMap<Key, Value>>({
18
+ dataType: 'map',
19
+ keyType: keyType,
20
+ valueType: valueType,
21
+ deepPartial(this: JSONMap<Key, Value>) {
22
+ return {
23
+ ...this,
24
+ keyType: this.keyType.deepPartial(),
25
+ valueType: this.valueType.deepPartial(),
26
+ };
27
+ },
28
+ });
29
+ };
@@ -0,0 +1,30 @@
1
+ import { constructType, JSONType } from './typeBase';
2
+
3
+ export interface JSONNativeEnum<T extends EnumLike>
4
+ extends JSONType<T[keyof T], 'nativeEnum'> {
5
+ dataType: 'nativeEnum';
6
+ enum: T;
7
+ options: (number | string)[];
8
+ }
9
+
10
+ type EnumLike = { [k: string]: string | number; [nu: number]: string };
11
+
12
+ export const getValidEnumValues = (obj: EnumLike) => {
13
+ const values: (number | string)[] = [];
14
+ Object.keys(obj).forEach((k) => {
15
+ if (typeof obj[obj[k]] !== 'number' && !values.includes(obj[k])) {
16
+ values.push(obj[k]);
17
+ }
18
+ });
19
+ return values;
20
+ };
21
+
22
+ export const nativeEnum = <T extends EnumLike>(givenEnum: T) => {
23
+ const options = getValidEnumValues(givenEnum);
24
+
25
+ return constructType<JSONNativeEnum<T>>({
26
+ dataType: 'nativeEnum',
27
+ enum: givenEnum,
28
+ options,
29
+ });
30
+ };