pqb 0.0.1 → 0.0.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/README.md +5 -0
- package/package.json +5 -2
- package/rollup.config.js +2 -34
- package/src/adapter.ts +11 -9
- package/src/columnSchema/array.ts +115 -3
- package/src/columnSchema/boolean.ts +4 -1
- package/src/columnSchema/columnType.test.ts +1 -1
- package/src/columnSchema/columnType.ts +227 -5
- package/src/columnSchema/columnTypes.test.ts +568 -0
- package/src/columnSchema/columnTypes.ts +136 -24
- package/src/columnSchema/columnsSchema.ts +1 -1
- package/src/columnSchema/commonMethods.ts +162 -80
- package/src/columnSchema/dateTime.ts +41 -10
- package/src/columnSchema/enum.ts +11 -6
- package/src/columnSchema/json/discriminatedUnion.ts +51 -42
- package/src/columnSchema/json/enum.ts +9 -9
- package/src/columnSchema/json/lazy.ts +5 -3
- package/src/columnSchema/json/nativeEnum.ts +1 -1
- package/src/columnSchema/json/nullish.ts +1 -1
- package/src/columnSchema/json/record.ts +14 -11
- package/src/columnSchema/json/scalarTypes.ts +17 -8
- package/src/columnSchema/json/set.ts +4 -4
- package/src/columnSchema/json/tuple.ts +17 -2
- package/src/columnSchema/json/typeBase.ts +11 -16
- package/src/columnSchema/json/union.ts +1 -1
- package/src/columnSchema/json.ts +4 -4
- package/src/columnSchema/number.ts +41 -30
- package/src/columnSchema/string.ts +28 -19
- package/src/columnSchema/utils.ts +0 -2
- package/src/{operators.test.ts → columnsOperators.test.ts} +0 -0
- package/src/{operators.ts → columnsOperators.ts} +0 -0
- package/src/common.ts +18 -16
- package/src/db.ts +10 -8
- package/src/index.ts +2 -7
- package/src/query.ts +2 -2
- package/src/queryMethods/aggregate.ts +6 -3
- package/src/queryMethods/get.ts +6 -3
- package/src/queryMethods/index.ts +22 -0
- package/src/queryMethods/join.ts +1 -1
- package/src/queryMethods/log.ts +5 -5
- package/src/queryMethods/select.test.ts +2 -2
- package/src/queryMethods/select.ts +10 -7
- package/src/queryMethods/then.ts +8 -19
- package/src/queryMethods/transaction.test.ts +2 -2
- package/src/queryMethods/transaction.ts +5 -5
- package/src/queryMethods/update.ts +11 -14
- package/src/sql/having.ts +1 -1
- package/src/test-utils.ts +3 -3
- package/src/utils.ts +3 -0
- package/dist/index.d.ts +0 -3630
- package/dist/index.esm.js +0 -4587
- package/dist/index.esm.js.map +0 -1
- package/dist/index.js +0 -4691
- package/dist/index.js.map +0 -1
- package/tsconfig.build.json +0 -6
package/README.md
ADDED
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pqb",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Postgres query builder",
|
|
5
|
+
"homepage": "https://porm.netlify.app/guide/query-builder.html",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/romeerez/porm"
|
|
8
|
+
"url": "git+https://github.com/romeerez/porm/tree/main/packages/pqb"
|
|
8
9
|
},
|
|
9
10
|
"main": "dist/index.js",
|
|
10
11
|
"module": "dist/index.esm.js",
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
33
|
+
"pg",
|
|
32
34
|
"postgres",
|
|
33
35
|
"query-builder"
|
|
34
36
|
],
|
|
@@ -39,6 +41,7 @@
|
|
|
39
41
|
"rollup": "^2.79.0",
|
|
40
42
|
"rollup-plugin-dts": "^4.2.2",
|
|
41
43
|
"rollup-plugin-esbuild": "^4.10.1",
|
|
44
|
+
"esbuild": "^0.15.10",
|
|
42
45
|
"@swc/core": "^1.2.210",
|
|
43
46
|
"@swc/jest": "^0.2.21",
|
|
44
47
|
"@types/jest": "^28.1.2",
|
package/rollup.config.js
CHANGED
|
@@ -1,35 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import esbuild from 'rollup-plugin-esbuild';
|
|
1
|
+
import config from '../../rollup.config';
|
|
3
2
|
|
|
4
|
-
export default
|
|
5
|
-
{
|
|
6
|
-
input: 'src/index.ts',
|
|
7
|
-
plugins: [esbuild()],
|
|
8
|
-
output: [
|
|
9
|
-
{
|
|
10
|
-
file: 'dist/index.js',
|
|
11
|
-
format: 'cjs',
|
|
12
|
-
sourcemap: true,
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
input: 'src/index.ts',
|
|
18
|
-
plugins: [esbuild()],
|
|
19
|
-
output: [
|
|
20
|
-
{
|
|
21
|
-
file: 'dist/index.esm.js',
|
|
22
|
-
format: 'es',
|
|
23
|
-
sourcemap: true,
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
input: 'src/index.ts',
|
|
29
|
-
plugins: [dts()],
|
|
30
|
-
output: {
|
|
31
|
-
file: `dist/index.d.ts`,
|
|
32
|
-
format: 'es',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
];
|
|
3
|
+
export default config;
|
package/src/adapter.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface QueryResultRow {
|
|
|
7
7
|
|
|
8
8
|
export type TypeParsers = Record<number, (input: string) => unknown>;
|
|
9
9
|
|
|
10
|
-
type
|
|
10
|
+
export type QueryInput = string | { text: string; values?: unknown[] };
|
|
11
11
|
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
13
|
export type QueryResult<T extends QueryResultRow = any> = {
|
|
@@ -34,6 +34,7 @@ for (const key in types.builtins) {
|
|
|
34
34
|
types.builtins.TIMESTAMP,
|
|
35
35
|
types.builtins.TIMESTAMPTZ,
|
|
36
36
|
types.builtins.TIME,
|
|
37
|
+
types.builtins.CIRCLE,
|
|
37
38
|
].forEach((id) => {
|
|
38
39
|
delete defaultTypeParsers[id];
|
|
39
40
|
});
|
|
@@ -55,7 +56,7 @@ export class Adapter {
|
|
|
55
56
|
|
|
56
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
58
|
async query<T extends QueryResultRow = any>(
|
|
58
|
-
query:
|
|
59
|
+
query: QueryInput,
|
|
59
60
|
types: TypeParsers = this.types,
|
|
60
61
|
): Promise<QueryResult<T>> {
|
|
61
62
|
const client = await this.pool.connect();
|
|
@@ -68,7 +69,7 @@ export class Adapter {
|
|
|
68
69
|
|
|
69
70
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
71
|
async arrays<R extends any[] = any[]>(
|
|
71
|
-
query:
|
|
72
|
+
query: QueryInput,
|
|
72
73
|
types: TypeParsers = this.types,
|
|
73
74
|
): Promise<QueryArraysResult<R>> {
|
|
74
75
|
const client = await this.pool.connect();
|
|
@@ -80,7 +81,7 @@ export class Adapter {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
async transaction<Result>(
|
|
83
|
-
cb: (adapter:
|
|
84
|
+
cb: (adapter: TransactionAdapter) => Promise<Result>,
|
|
84
85
|
): Promise<Result> {
|
|
85
86
|
const client = await this.pool.connect();
|
|
86
87
|
try {
|
|
@@ -97,6 +98,7 @@ export class Adapter {
|
|
|
97
98
|
client.release();
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
|
|
100
102
|
destroy(): Promise<void> {
|
|
101
103
|
return this.pool.end();
|
|
102
104
|
}
|
|
@@ -104,7 +106,7 @@ export class Adapter {
|
|
|
104
106
|
|
|
105
107
|
const performQuery = <T extends QueryResultRow>(
|
|
106
108
|
client: PoolClient,
|
|
107
|
-
query:
|
|
109
|
+
query: QueryInput,
|
|
108
110
|
types: TypeParsers,
|
|
109
111
|
) => {
|
|
110
112
|
return client.query<T>({
|
|
@@ -121,7 +123,7 @@ const performQuery = <T extends QueryResultRow>(
|
|
|
121
123
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
122
124
|
const performQueryArrays = <T extends any[] = any[]>(
|
|
123
125
|
client: PoolClient,
|
|
124
|
-
query:
|
|
126
|
+
query: QueryInput,
|
|
125
127
|
types: TypeParsers,
|
|
126
128
|
) => {
|
|
127
129
|
return client.query<T>({
|
|
@@ -145,7 +147,7 @@ export class TransactionAdapter implements Adapter {
|
|
|
145
147
|
|
|
146
148
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
149
|
async query<T extends QueryResultRow = any>(
|
|
148
|
-
query:
|
|
150
|
+
query: QueryInput,
|
|
149
151
|
types: TypeParsers = this.types,
|
|
150
152
|
): Promise<QueryResult<T>> {
|
|
151
153
|
return await performQuery<T>(this.client, query, types);
|
|
@@ -153,14 +155,14 @@ export class TransactionAdapter implements Adapter {
|
|
|
153
155
|
|
|
154
156
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
157
|
async arrays<R extends any[] = any[]>(
|
|
156
|
-
query:
|
|
158
|
+
query: QueryInput,
|
|
157
159
|
types: TypeParsers = this.types,
|
|
158
160
|
): Promise<QueryArraysResult<R>> {
|
|
159
161
|
return await performQueryArrays<R>(this.client, query, types);
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
async transaction<Result>(
|
|
163
|
-
cb: (adapter:
|
|
165
|
+
cb: (adapter: TransactionAdapter) => Promise<Result>,
|
|
164
166
|
): Promise<Result> {
|
|
165
167
|
return await cb(this);
|
|
166
168
|
}
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { ColumnType } from './columnType';
|
|
2
|
-
import { Operators } from '../
|
|
1
|
+
import { ColumnData, ColumnType } from './columnType';
|
|
2
|
+
import { Operators } from '../columnsOperators';
|
|
3
|
+
import { assignMethodsToClass } from './utils';
|
|
4
|
+
import { arrayMethods } from './commonMethods';
|
|
5
|
+
|
|
6
|
+
export type ArrayData<Item extends ColumnType> = ColumnData & {
|
|
7
|
+
item: Item;
|
|
8
|
+
min?: number;
|
|
9
|
+
max?: number;
|
|
10
|
+
length?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ArrayMethods = typeof arrayMethods;
|
|
14
|
+
|
|
15
|
+
export interface ArrayColumn<Item extends ColumnType>
|
|
16
|
+
extends ColumnType<Item['type'][], typeof Operators.array>,
|
|
17
|
+
ArrayMethods {}
|
|
3
18
|
|
|
4
19
|
export class ArrayColumn<Item extends ColumnType> extends ColumnType<
|
|
5
20
|
Item['type'][],
|
|
@@ -7,7 +22,7 @@ export class ArrayColumn<Item extends ColumnType> extends ColumnType<
|
|
|
7
22
|
> {
|
|
8
23
|
dataType = 'array' as const;
|
|
9
24
|
operators = Operators.array;
|
|
10
|
-
data:
|
|
25
|
+
data: ArrayData<Item>;
|
|
11
26
|
|
|
12
27
|
constructor(item: Item) {
|
|
13
28
|
super();
|
|
@@ -18,4 +33,101 @@ export class ArrayColumn<Item extends ColumnType> extends ColumnType<
|
|
|
18
33
|
toSQL() {
|
|
19
34
|
return `${this.data.item.toSQL()}[]`;
|
|
20
35
|
}
|
|
36
|
+
|
|
37
|
+
parseFn = (input: unknown) => {
|
|
38
|
+
const entries: unknown[] = [];
|
|
39
|
+
parseArray(
|
|
40
|
+
input as string,
|
|
41
|
+
0,
|
|
42
|
+
(input as string).length,
|
|
43
|
+
entries,
|
|
44
|
+
false,
|
|
45
|
+
this.data.item,
|
|
46
|
+
);
|
|
47
|
+
return entries;
|
|
48
|
+
};
|
|
21
49
|
}
|
|
50
|
+
|
|
51
|
+
const parseArray = (
|
|
52
|
+
input: string,
|
|
53
|
+
pos: number,
|
|
54
|
+
len: number,
|
|
55
|
+
entries: unknown[],
|
|
56
|
+
nested: boolean,
|
|
57
|
+
item: ColumnType,
|
|
58
|
+
): number => {
|
|
59
|
+
if (input[0] === '[') {
|
|
60
|
+
while (pos < len) {
|
|
61
|
+
let char = input[pos++];
|
|
62
|
+
if (char === '\\') {
|
|
63
|
+
char = input[pos++];
|
|
64
|
+
}
|
|
65
|
+
if (char === '=') break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let quote = false;
|
|
70
|
+
let start = pos;
|
|
71
|
+
while (pos < len) {
|
|
72
|
+
let char = input[pos++];
|
|
73
|
+
const escaped = char === '\\';
|
|
74
|
+
if (escaped) {
|
|
75
|
+
char = input[pos++];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (char === '"' && !escaped) {
|
|
79
|
+
if (quote) {
|
|
80
|
+
pushEntry(input, start, pos, entries, item);
|
|
81
|
+
} else {
|
|
82
|
+
start = pos;
|
|
83
|
+
}
|
|
84
|
+
quote = !quote;
|
|
85
|
+
} else if (char === ',' && !quote) {
|
|
86
|
+
if (start !== pos) {
|
|
87
|
+
pushEntry(input, start, pos, entries, item);
|
|
88
|
+
}
|
|
89
|
+
start = pos;
|
|
90
|
+
} else if (char === '{' && !quote) {
|
|
91
|
+
let array: unknown[];
|
|
92
|
+
let nestedItem = item;
|
|
93
|
+
if (nested) {
|
|
94
|
+
array = [];
|
|
95
|
+
entries.push(array);
|
|
96
|
+
if ('item' in item.data) {
|
|
97
|
+
nestedItem = (item as ArrayColumn<ColumnType>).data
|
|
98
|
+
.item as ColumnType;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
array = entries;
|
|
102
|
+
}
|
|
103
|
+
pos = parseArray(input, pos, len, array, true, nestedItem);
|
|
104
|
+
start = pos + 1;
|
|
105
|
+
} else if (char === '}' && !quote) {
|
|
106
|
+
if (start !== pos) {
|
|
107
|
+
pushEntry(input, start, pos, entries, item);
|
|
108
|
+
}
|
|
109
|
+
start = pos + 1;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return pos;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
assignMethodsToClass(ArrayColumn, arrayMethods);
|
|
118
|
+
|
|
119
|
+
const pushEntry = (
|
|
120
|
+
input: string,
|
|
121
|
+
start: number,
|
|
122
|
+
pos: number,
|
|
123
|
+
entries: unknown[],
|
|
124
|
+
item: ColumnType,
|
|
125
|
+
) => {
|
|
126
|
+
let entry: unknown = input.slice(start, pos - 1);
|
|
127
|
+
if (entry === 'NULL') {
|
|
128
|
+
entry = null;
|
|
129
|
+
} else if (item.parseItem) {
|
|
130
|
+
entry = item.parseItem(entry as string);
|
|
131
|
+
}
|
|
132
|
+
entries.push(entry);
|
|
133
|
+
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ColumnType } from './columnType';
|
|
2
|
-
import { Operators } from '../
|
|
2
|
+
import { Operators } from '../columnsOperators';
|
|
3
3
|
|
|
4
|
+
// 1 byte, true or false
|
|
4
5
|
export class BooleanColumn extends ColumnType<
|
|
5
6
|
boolean,
|
|
6
7
|
typeof Operators.boolean
|
|
7
8
|
> {
|
|
8
9
|
dataType = 'boolean' as const;
|
|
9
10
|
operators = Operators.boolean;
|
|
11
|
+
|
|
12
|
+
parseItem = (input: string) => input[0] === 't';
|
|
10
13
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { Operator, Operators } from '../
|
|
2
|
-
import {
|
|
1
|
+
import { Operator, Operators } from '../columnsOperators';
|
|
2
|
+
import { JSONTypeAny } from './json/typeBase';
|
|
3
|
+
import { ColumnsShape } from './columnsSchema';
|
|
4
|
+
import { RawExpression, StringKey } from '../common';
|
|
5
|
+
import { MaybeArray } from '../utils';
|
|
3
6
|
|
|
4
7
|
export type ColumnOutput<T extends ColumnType> = T['type'];
|
|
5
8
|
|
|
@@ -7,9 +10,10 @@ export type ColumnInput<T extends ColumnType> = T['inputType'];
|
|
|
7
10
|
|
|
8
11
|
export type NullableColumn<T extends ColumnType> = Omit<
|
|
9
12
|
T,
|
|
10
|
-
'type' | 'operators'
|
|
13
|
+
'type' | 'inputType' | 'operators'
|
|
11
14
|
> & {
|
|
12
15
|
type: T['type'] | null;
|
|
16
|
+
inputType: T['inputType'] | null;
|
|
13
17
|
isNullable: true;
|
|
14
18
|
operators: Omit<T['operators'], 'equals' | 'not'> & {
|
|
15
19
|
equals: Operator<T['type'] | null>;
|
|
@@ -20,8 +24,90 @@ export type NullableColumn<T extends ColumnType> = Omit<
|
|
|
20
24
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
25
|
export type AnyColumnType = ColumnType<any, Record<string, Operator<any>>>;
|
|
22
26
|
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
|
28
|
+
export type AnyColumnTypeCreator = (...args: any[]) => AnyColumnType | {};
|
|
29
|
+
|
|
30
|
+
export type ColumnTypesBase = Record<
|
|
31
|
+
string,
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
33
|
+
AnyColumnTypeCreator
|
|
34
|
+
>;
|
|
35
|
+
|
|
23
36
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
-
export type
|
|
37
|
+
export type ValidationContext = any;
|
|
38
|
+
|
|
39
|
+
export type ColumnData = {
|
|
40
|
+
default?: unknown;
|
|
41
|
+
validationDefault?: unknown;
|
|
42
|
+
index?: Omit<SingleColumnIndexOptions, 'column'>;
|
|
43
|
+
comment?: string;
|
|
44
|
+
collate?: string;
|
|
45
|
+
compression?: string;
|
|
46
|
+
foreignKey?: ForeignKey<string, string[]>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type ForeignKeyMatch = 'FULL' | 'PARTIAL' | 'SIMPLE';
|
|
50
|
+
|
|
51
|
+
type ForeignKeyAction =
|
|
52
|
+
| 'NO ACTION'
|
|
53
|
+
| 'RESTRICT'
|
|
54
|
+
| 'CASCADE'
|
|
55
|
+
| 'SET NULL'
|
|
56
|
+
| 'SET DEFAULT';
|
|
57
|
+
|
|
58
|
+
export type ForeignKey<Table extends string, Columns extends string[]> = (
|
|
59
|
+
| {
|
|
60
|
+
fn(): new () => { table: Table };
|
|
61
|
+
}
|
|
62
|
+
| {
|
|
63
|
+
table: Table;
|
|
64
|
+
}
|
|
65
|
+
) & {
|
|
66
|
+
columns: Columns;
|
|
67
|
+
} & ForeignKeyOptions;
|
|
68
|
+
|
|
69
|
+
export type DropMode = 'CASCADE' | 'RESTRICT';
|
|
70
|
+
|
|
71
|
+
export type ForeignKeyOptions = {
|
|
72
|
+
name?: string;
|
|
73
|
+
match?: ForeignKeyMatch;
|
|
74
|
+
onUpdate?: ForeignKeyAction;
|
|
75
|
+
onDelete?: ForeignKeyAction;
|
|
76
|
+
dropMode?: DropMode;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type IndexColumnOptions = {
|
|
80
|
+
column: string;
|
|
81
|
+
expression?: number | string;
|
|
82
|
+
collate?: string;
|
|
83
|
+
operator?: string;
|
|
84
|
+
order?: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type IndexOptions = {
|
|
88
|
+
name?: string;
|
|
89
|
+
unique?: boolean;
|
|
90
|
+
using?: string;
|
|
91
|
+
include?: MaybeArray<string>;
|
|
92
|
+
with?: string;
|
|
93
|
+
tablespace?: string;
|
|
94
|
+
where?: string;
|
|
95
|
+
dropMode?: 'CASCADE' | 'RESTRICT';
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export type SingleColumnIndexOptions = IndexColumnOptions & IndexOptions;
|
|
99
|
+
|
|
100
|
+
export type ForeignKeyModel = new () => {
|
|
101
|
+
table: string;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export type ForeignKeyModelWithColumns = new () => {
|
|
105
|
+
table: string;
|
|
106
|
+
columns: { shape: ColumnsShape };
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export type ColumnNameOfModel<Model extends ForeignKeyModelWithColumns> =
|
|
110
|
+
StringKey<keyof InstanceType<Model>['columns']['shape']>;
|
|
25
111
|
|
|
26
112
|
export abstract class ColumnType<
|
|
27
113
|
Type = unknown,
|
|
@@ -33,18 +119,68 @@ export abstract class ColumnType<
|
|
|
33
119
|
|
|
34
120
|
type!: Type;
|
|
35
121
|
inputType!: InputType;
|
|
36
|
-
data = {} as
|
|
122
|
+
data = {} as ColumnData;
|
|
37
123
|
isPrimaryKey = false;
|
|
38
124
|
isHidden = false;
|
|
39
125
|
isNullable = false;
|
|
126
|
+
|
|
40
127
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
128
|
encodeFn?: (input: any) => unknown;
|
|
42
129
|
parseFn?: (input: unknown) => unknown;
|
|
130
|
+
// parse item in array:
|
|
131
|
+
parseItem?: (input: string) => unknown;
|
|
132
|
+
|
|
133
|
+
chain = [] as (
|
|
134
|
+
| ['transform', (input: unknown, ctx: ValidationContext) => unknown]
|
|
135
|
+
| ['to', (input: unknown) => JSONTypeAny | undefined, JSONTypeAny]
|
|
136
|
+
| ['refine', (input: unknown) => unknown]
|
|
137
|
+
| ['superRefine', (input: unknown, ctx: ValidationContext) => unknown]
|
|
138
|
+
)[];
|
|
43
139
|
|
|
44
140
|
primaryKey<T extends ColumnType>(this: T): T & { isPrimaryKey: true } {
|
|
45
141
|
return Object.assign(this, { isPrimaryKey: true as const });
|
|
46
142
|
}
|
|
47
143
|
|
|
144
|
+
foreignKey<
|
|
145
|
+
T extends ColumnType,
|
|
146
|
+
Model extends ForeignKeyModelWithColumns,
|
|
147
|
+
Column extends ColumnNameOfModel<Model>,
|
|
148
|
+
>(
|
|
149
|
+
this: T,
|
|
150
|
+
fn: () => Model,
|
|
151
|
+
column: Column,
|
|
152
|
+
options?: ForeignKeyOptions,
|
|
153
|
+
): Omit<T, 'foreignKeyData'> & {
|
|
154
|
+
foreignKeyData: ForeignKey<InstanceType<Model>['table'], [Column]>;
|
|
155
|
+
};
|
|
156
|
+
foreignKey<T extends ColumnType, Table extends string, Column extends string>(
|
|
157
|
+
this: T,
|
|
158
|
+
table: Table,
|
|
159
|
+
column: Column,
|
|
160
|
+
options?: ForeignKeyOptions,
|
|
161
|
+
): Omit<T, 'foreignKeyData'> & {
|
|
162
|
+
foreignKeyData: ForeignKey<Table, [Column]>;
|
|
163
|
+
};
|
|
164
|
+
foreignKey(
|
|
165
|
+
fnOrTable: (() => ForeignKeyModel) | string,
|
|
166
|
+
column: string,
|
|
167
|
+
options: ForeignKeyOptions = {},
|
|
168
|
+
) {
|
|
169
|
+
const cloned = Object.create(this);
|
|
170
|
+
if (typeof fnOrTable === 'string') {
|
|
171
|
+
cloned.data = {
|
|
172
|
+
...this.data,
|
|
173
|
+
foreignKey: { table: fnOrTable, columns: [column], ...options },
|
|
174
|
+
};
|
|
175
|
+
} else {
|
|
176
|
+
cloned.data = {
|
|
177
|
+
...this.data,
|
|
178
|
+
foreignKey: { fn: fnOrTable, columns: [column], ...options },
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return cloned;
|
|
182
|
+
}
|
|
183
|
+
|
|
48
184
|
hidden<T extends ColumnType>(this: T): T & { isHidden: true } {
|
|
49
185
|
return Object.assign(this, { isHidden: true as const });
|
|
50
186
|
}
|
|
@@ -68,10 +204,96 @@ export abstract class ColumnType<
|
|
|
68
204
|
fn: (input: T['type']) => Output,
|
|
69
205
|
): Omit<T, 'type'> & { type: Output } {
|
|
70
206
|
this.parseFn = fn;
|
|
207
|
+
this.parseItem = fn;
|
|
71
208
|
return this as unknown as Omit<T, 'type'> & { type: Output };
|
|
72
209
|
}
|
|
73
210
|
|
|
74
211
|
toSQL() {
|
|
75
212
|
return this.dataType;
|
|
76
213
|
}
|
|
214
|
+
|
|
215
|
+
default<T extends ColumnType>(this: T, value: T['type'] | RawExpression): T {
|
|
216
|
+
const cloned = Object.create(this);
|
|
217
|
+
cloned.data = { ...cloned.data, default: value };
|
|
218
|
+
return cloned;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
index<T extends ColumnType>(
|
|
222
|
+
this: T,
|
|
223
|
+
options: Omit<SingleColumnIndexOptions, 'column'> = {},
|
|
224
|
+
) {
|
|
225
|
+
const cloned = Object.create(this);
|
|
226
|
+
cloned.data = { ...cloned.data, index: options };
|
|
227
|
+
return cloned;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
unique<T extends ColumnType>(
|
|
231
|
+
this: T,
|
|
232
|
+
options: Omit<SingleColumnIndexOptions, 'column' | 'unique'> = {},
|
|
233
|
+
): T {
|
|
234
|
+
const cloned = Object.create(this);
|
|
235
|
+
cloned.data = { ...cloned.data, index: { ...options, unique: true } };
|
|
236
|
+
return cloned;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
comment<T extends ColumnType>(this: T, comment: string): T {
|
|
240
|
+
const cloned = Object.create(this);
|
|
241
|
+
cloned.data = { ...cloned.data, comment };
|
|
242
|
+
return cloned;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
validationDefault<T extends ColumnType>(this: T, value: T['type']): T {
|
|
246
|
+
const cloned = Object.create(this);
|
|
247
|
+
cloned.data = { ...cloned.data, validationDefault: value };
|
|
248
|
+
return cloned;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
compression<T extends ColumnType>(this: T, compression: string): T {
|
|
252
|
+
const cloned = Object.create(this);
|
|
253
|
+
cloned.data = { ...cloned.data, compression };
|
|
254
|
+
return cloned;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
collate<T extends ColumnType>(this: T, collate: string): T {
|
|
258
|
+
const cloned = Object.create(this);
|
|
259
|
+
cloned.data = { ...cloned.data, collate };
|
|
260
|
+
return cloned;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
transform<T extends ColumnType, Transformed>(
|
|
264
|
+
this: T,
|
|
265
|
+
fn: (input: T['type'], ctx: ValidationContext) => Transformed,
|
|
266
|
+
): Omit<T, 'type'> & { type: Transformed } {
|
|
267
|
+
const cloned = Object.create(this);
|
|
268
|
+
cloned.chain = [...this.chain, ['transform', fn]];
|
|
269
|
+
return cloned as Omit<T, 'type'> & { type: Transformed };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
to<T extends ColumnType, ToType extends ColumnType>(
|
|
273
|
+
this: T,
|
|
274
|
+
fn: (input: T['type']) => ToType['type'] | undefined,
|
|
275
|
+
type: ToType,
|
|
276
|
+
): ToType {
|
|
277
|
+
const cloned = Object.create(type);
|
|
278
|
+
cloned.chain = [...this.chain, ['to', fn, type], ...cloned.chain];
|
|
279
|
+
return cloned as ToType;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
refine<T extends ColumnType, RefinedOutput extends T['type']>(
|
|
283
|
+
this: T,
|
|
284
|
+
check: (arg: T['type']) => unknown,
|
|
285
|
+
): T & { type: RefinedOutput } {
|
|
286
|
+
const cloned = Object.create(this);
|
|
287
|
+
cloned.chain = [...this.chain, ['refine', check]];
|
|
288
|
+
return cloned as T & { type: RefinedOutput };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
superRefine<T extends ColumnType, RefinedOutput extends T['type']>(
|
|
292
|
+
this: T,
|
|
293
|
+
check: (arg: T['type'], ctx: ValidationContext) => unknown,
|
|
294
|
+
): T & { type: RefinedOutput } {
|
|
295
|
+
const cloned = Object.create(this);
|
|
296
|
+
cloned.chain = [...this.chain, ['superRefine', check]];
|
|
297
|
+
return cloned as T & { type: RefinedOutput };
|
|
298
|
+
}
|
|
77
299
|
}
|