kysely 0.30.0-beta.0 → 0.30.0-beta.2
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 +1 -1
- package/dist/dialect/database-introspector.d.ts +38 -4
- package/dist/dialect/mssql/mssql-introspector.d.ts +2 -2
- package/dist/dialect/mssql/mssql-introspector.js +32 -2
- package/dist/dialect/mysql/mysql-dialect-config.d.ts +31 -6
- package/dist/dialect/mysql/mysql-dialect.d.ts +2 -2
- package/dist/dialect/mysql/mysql-dialect.js +2 -2
- package/dist/dialect/mysql/mysql-driver.js +28 -2
- package/dist/dialect/mysql/mysql-introspector.d.ts +2 -2
- package/dist/dialect/mysql/mysql-introspector.js +34 -11
- package/dist/dialect/postgres/postgres-introspector.d.ts +2 -2
- package/dist/dialect/postgres/postgres-introspector.js +18 -7
- package/dist/dialect/sqlite/sqlite-driver.js +7 -8
- package/dist/dialect/sqlite/sqlite-introspector.js +7 -3
- package/dist/driver/dummy-driver.d.ts +2 -2
- package/dist/driver/dummy-driver.js +2 -2
- package/dist/kysely.d.ts +27 -7
- package/dist/kysely.js +0 -14
- package/dist/migration/file-migration-provider.d.ts +1 -1
- package/dist/migration/file-migration-provider.js +1 -1
- package/dist/migration/migrator.d.ts +48 -9
- package/dist/migration/migrator.js +62 -19
- package/dist/query-builder/delete-query-builder.d.ts +2 -2
- package/dist/query-builder/function-module.d.ts +8 -2
- package/dist/query-builder/join-builder.d.ts +2 -2
- package/dist/query-builder/merge-query-builder.d.ts +9 -1
- package/dist/query-builder/select-query-builder.d.ts +28 -6
- package/dist/query-builder/update-query-builder.d.ts +1 -1
- package/dist/query-creator.d.ts +9 -0
- package/dist/raw-builder/raw-builder.d.ts +5 -0
- package/dist/raw-builder/raw-builder.js +12 -0
- package/dist/readonly/readonly-kysely.d.ts +64 -10
- package/dist/readonly/readonly-query-creator.d.ts +9 -1
- package/dist/schema/create-type-builder.d.ts +1 -1
- package/dist/schema/create-type-builder.js +1 -1
- package/dist/util/abort.js +2 -0
- package/package.json +18 -16
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](https://stand-with-ukraine.pp.ua)
|
|
2
2
|
|
|
3
3
|
[](https://github.com/kysely-org/kysely/releases/latest)
|
|
4
|
-
[](https://socket.dev/npm/package/kysely/overview/0.30.0-beta.2)
|
|
5
5
|
[](https://github.com/kysely-org/kysely)
|
|
6
6
|
[](https://github.com/kysely-org/kysely/blob/master/LICENSE)
|
|
7
7
|
[](https://github.com/kysely-org/kysely/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Expression } from '../expression/expression.js';
|
|
2
|
+
import type { SqlBool } from '../util/type-utils.js';
|
|
1
3
|
/**
|
|
2
4
|
* An interface for getting the database metadata (names of the tables and columns etc.)
|
|
3
5
|
*/
|
|
@@ -5,27 +7,59 @@ export interface DatabaseIntrospector {
|
|
|
5
7
|
/**
|
|
6
8
|
* Get schema metadata.
|
|
7
9
|
*/
|
|
8
|
-
getSchemas(): Promise<SchemaMetadata[]>;
|
|
10
|
+
getSchemas(options?: DatabaseSchemaMetadataOptions): Promise<SchemaMetadata[]>;
|
|
9
11
|
/**
|
|
10
12
|
* Get tables and views metadata.
|
|
11
13
|
*/
|
|
12
14
|
getTables(options?: DatabaseMetadataOptions): Promise<TableMetadata[]>;
|
|
13
15
|
}
|
|
16
|
+
export interface DatabaseSchemaMetadataOptions {
|
|
17
|
+
/**
|
|
18
|
+
* An optional SQL `where` expression for filtering the schemas returned by
|
|
19
|
+
* the introspector.
|
|
20
|
+
*
|
|
21
|
+
* The refs argument contains an SQL reference to the schema name column
|
|
22
|
+
* within the catalog query this expression will be used in.
|
|
23
|
+
*/
|
|
24
|
+
where?: (refs: Readonly<{
|
|
25
|
+
schema: Expression<string>;
|
|
26
|
+
}>) => Expression<SqlBool>;
|
|
27
|
+
}
|
|
14
28
|
export interface DatabaseMetadataOptions {
|
|
29
|
+
/**
|
|
30
|
+
* An optional SQL `where` expression for filtering the tables returned by
|
|
31
|
+
* the introspector.
|
|
32
|
+
*
|
|
33
|
+
* The refs argument contains SQL references to the table name and optional
|
|
34
|
+
* schema name columns within the catalog query this expression will be used
|
|
35
|
+
* in.
|
|
36
|
+
*/
|
|
37
|
+
where?: (refs: Readonly<{
|
|
38
|
+
table: Expression<string>;
|
|
39
|
+
schema?: Expression<string>;
|
|
40
|
+
}>) => Expression<SqlBool>;
|
|
15
41
|
/**
|
|
16
42
|
* If this is true, the metadata contains the internal kysely tables
|
|
17
43
|
* such as the migration tables.
|
|
18
44
|
*/
|
|
19
45
|
withInternalKyselyTables: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* If this is true, tables from non-default databases are also returned.
|
|
48
|
+
*
|
|
49
|
+
* This option only affects MySQL and defaults to false. System databases are
|
|
50
|
+
* excluded regardless of this option.
|
|
51
|
+
*/
|
|
52
|
+
withNonDefaultDatabases?: boolean;
|
|
20
53
|
}
|
|
21
54
|
export interface SchemaMetadata {
|
|
22
55
|
readonly name: string;
|
|
23
56
|
}
|
|
24
57
|
export interface TableMetadata {
|
|
25
|
-
readonly name: string;
|
|
26
|
-
readonly isView: boolean;
|
|
27
|
-
readonly isForeign: boolean;
|
|
28
58
|
readonly columns: ColumnMetadata[];
|
|
59
|
+
readonly comment?: string;
|
|
60
|
+
readonly isForeign: boolean;
|
|
61
|
+
readonly isView: boolean;
|
|
62
|
+
readonly name: string;
|
|
29
63
|
readonly schema?: string;
|
|
30
64
|
}
|
|
31
65
|
export interface ColumnMetadata {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Kysely } from '../../kysely.js';
|
|
2
|
-
import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
2
|
+
import type { DatabaseIntrospector, DatabaseMetadataOptions, DatabaseSchemaMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
3
3
|
export declare class MssqlIntrospector implements DatabaseIntrospector {
|
|
4
4
|
#private;
|
|
5
5
|
constructor(db: Kysely<any>);
|
|
6
6
|
/**
|
|
7
7
|
* Get schema metadata.
|
|
8
8
|
*/
|
|
9
|
-
getSchemas(): Promise<SchemaMetadata[]>;
|
|
9
|
+
getSchemas(options?: DatabaseSchemaMetadataOptions): Promise<SchemaMetadata[]>;
|
|
10
10
|
/**
|
|
11
11
|
* Get tables and views metadata.
|
|
12
12
|
*/
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
/// <reference types="./mssql-introspector.d.ts" />
|
|
2
2
|
import { DEFAULT_MIGRATION_LOCK_TABLE, DEFAULT_MIGRATION_TABLE, } from '../../migration/migrator.js';
|
|
3
|
+
import { sql } from '../../raw-builder/sql.js';
|
|
3
4
|
import { freeze } from '../../util/object-utils.js';
|
|
4
5
|
export class MssqlIntrospector {
|
|
5
6
|
#db;
|
|
6
7
|
constructor(db) {
|
|
7
8
|
this.#db = db;
|
|
8
9
|
}
|
|
9
|
-
async getSchemas() {
|
|
10
|
-
|
|
10
|
+
async getSchemas(options = {}) {
|
|
11
|
+
let query = this.#db.selectFrom('sys.schemas').select('name');
|
|
12
|
+
if (options.where) {
|
|
13
|
+
query = query.where(options.where({ schema: sql.ref('name') }));
|
|
14
|
+
}
|
|
15
|
+
return await query.execute();
|
|
11
16
|
}
|
|
12
17
|
async getTables(options = { withInternalKyselyTables: false }) {
|
|
18
|
+
const tablesWhere = options.where?.({
|
|
19
|
+
schema: sql.ref('table_schemas.name'),
|
|
20
|
+
table: sql.ref('tables.name'),
|
|
21
|
+
});
|
|
22
|
+
const viewsWhere = options.where?.({
|
|
23
|
+
schema: sql.ref('view_schemas.name'),
|
|
24
|
+
table: sql.ref('views.name'),
|
|
25
|
+
});
|
|
13
26
|
const rawColumns = await this.#db
|
|
14
27
|
.selectFrom('sys.tables as tables')
|
|
15
28
|
.leftJoin('sys.schemas as table_schemas', 'table_schemas.schema_id', 'tables.schema_id')
|
|
@@ -17,12 +30,19 @@ export class MssqlIntrospector {
|
|
|
17
30
|
.innerJoin('sys.types as types', 'types.user_type_id', 'columns.user_type_id')
|
|
18
31
|
.leftJoin('sys.schemas as type_schemas', 'type_schemas.schema_id', 'types.schema_id')
|
|
19
32
|
.leftJoin('sys.extended_properties as comments', (join) => join
|
|
33
|
+
.on('comments.class', '=', 1)
|
|
20
34
|
.onRef('comments.major_id', '=', 'tables.object_id')
|
|
21
35
|
.onRef('comments.minor_id', '=', 'columns.column_id')
|
|
22
36
|
.on('comments.name', '=', 'MS_Description'))
|
|
37
|
+
.leftJoin('sys.extended_properties as table_comments', (join) => join
|
|
38
|
+
.on('table_comments.class', '=', 1)
|
|
39
|
+
.onRef('table_comments.major_id', '=', 'tables.object_id')
|
|
40
|
+
.on('table_comments.minor_id', '=', 0)
|
|
41
|
+
.on('table_comments.name', '=', 'MS_Description'))
|
|
23
42
|
.$if(!options.withInternalKyselyTables, (qb) => qb
|
|
24
43
|
.where('tables.name', '!=', DEFAULT_MIGRATION_TABLE)
|
|
25
44
|
.where('tables.name', '!=', DEFAULT_MIGRATION_LOCK_TABLE))
|
|
45
|
+
.$if(!!tablesWhere, (qb) => qb.where(tablesWhere))
|
|
26
46
|
.select([
|
|
27
47
|
'tables.name as table_name',
|
|
28
48
|
(eb) => eb
|
|
@@ -41,6 +61,7 @@ export class MssqlIntrospector {
|
|
|
41
61
|
'types.name as type_name',
|
|
42
62
|
'type_schemas.name as type_schema_name',
|
|
43
63
|
'comments.value as column_comment',
|
|
64
|
+
'table_comments.value as table_comment',
|
|
44
65
|
])
|
|
45
66
|
.unionAll(this.#db
|
|
46
67
|
.selectFrom('sys.views as views')
|
|
@@ -49,9 +70,16 @@ export class MssqlIntrospector {
|
|
|
49
70
|
.innerJoin('sys.types as types', 'types.user_type_id', 'columns.user_type_id')
|
|
50
71
|
.leftJoin('sys.schemas as type_schemas', 'type_schemas.schema_id', 'types.schema_id')
|
|
51
72
|
.leftJoin('sys.extended_properties as comments', (join) => join
|
|
73
|
+
.on('comments.class', '=', 1)
|
|
52
74
|
.onRef('comments.major_id', '=', 'views.object_id')
|
|
53
75
|
.onRef('comments.minor_id', '=', 'columns.column_id')
|
|
54
76
|
.on('comments.name', '=', 'MS_Description'))
|
|
77
|
+
.leftJoin('sys.extended_properties as table_comments', (join) => join
|
|
78
|
+
.on('table_comments.class', '=', 1)
|
|
79
|
+
.onRef('table_comments.major_id', '=', 'views.object_id')
|
|
80
|
+
.on('table_comments.minor_id', '=', 0)
|
|
81
|
+
.on('table_comments.name', '=', 'MS_Description'))
|
|
82
|
+
.$if(!!viewsWhere, (qb) => qb.where(viewsWhere))
|
|
55
83
|
.select([
|
|
56
84
|
'views.name as table_name',
|
|
57
85
|
'views.type as table_type',
|
|
@@ -67,6 +95,7 @@ export class MssqlIntrospector {
|
|
|
67
95
|
'types.name as type_name',
|
|
68
96
|
'type_schemas.name as type_schema_name',
|
|
69
97
|
'comments.value as column_comment',
|
|
98
|
+
'table_comments.value as table_comment',
|
|
70
99
|
]))
|
|
71
100
|
.orderBy('table_schema_name')
|
|
72
101
|
.orderBy('table_name')
|
|
@@ -79,6 +108,7 @@ export class MssqlIntrospector {
|
|
|
79
108
|
tableDictionary[key] ||
|
|
80
109
|
freeze({
|
|
81
110
|
columns: [],
|
|
111
|
+
comment: rawColumn.table_comment ?? undefined,
|
|
82
112
|
isForeign: false,
|
|
83
113
|
isView: rawColumn.table_type === 'V ',
|
|
84
114
|
name: rawColumn.table_name,
|
|
@@ -5,23 +5,25 @@ import type { AbortableOperationOptions } from '../../util/abort.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface MysqlDialectConfig {
|
|
7
7
|
/**
|
|
8
|
-
* A `
|
|
9
|
-
* outside of the `pool` to avoid
|
|
8
|
+
* A `createConnection` function (from either `mysql2` or `mysql2/promise`),
|
|
9
|
+
* to be used for connecting to the database outside of the `pool` to avoid
|
|
10
|
+
* waiting for an idle connection.
|
|
10
11
|
*
|
|
11
12
|
* This is useful for cancelling queries on the database side.
|
|
12
13
|
*/
|
|
13
14
|
controlConnection?: {
|
|
14
|
-
(connectionUri: string): MysqlConnection
|
|
15
|
-
(config: object): MysqlConnection
|
|
15
|
+
(connectionUri: string): MysqlConnection | Promise<MysqlPromiseConnection>;
|
|
16
|
+
(config: object): MysqlConnection | Promise<MysqlPromiseConnection>;
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
|
-
* A mysql2 Pool instance
|
|
19
|
+
* A mysql2 Pool instance (from either `mysql2` or `mysql2/promise`) or a
|
|
20
|
+
* function that returns one.
|
|
19
21
|
*
|
|
20
22
|
* If a function is provided, it's called once when the first query is executed.
|
|
21
23
|
*
|
|
22
24
|
* https://github.com/sidorares/node-mysql2#using-connection-pools
|
|
23
25
|
*/
|
|
24
|
-
pool: MysqlPool | ((options?: AbortableOperationOptions) => Promise<MysqlPool>);
|
|
26
|
+
pool: MysqlPool | MysqlPromisePool | ((options?: AbortableOperationOptions) => Promise<MysqlPool | MysqlPromisePool>);
|
|
25
27
|
/**
|
|
26
28
|
* Called once for each created connection.
|
|
27
29
|
*/
|
|
@@ -43,6 +45,17 @@ export interface MysqlPool {
|
|
|
43
45
|
getConnection(callback: (error: unknown, connection: MysqlPoolConnection) => void): void;
|
|
44
46
|
end(callback: (error: unknown) => void): void;
|
|
45
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* This interface is the subset of `mysql2/promise`'s `Pool` class that
|
|
50
|
+
* kysely needs.
|
|
51
|
+
*
|
|
52
|
+
* It's a thin promise wrapper around the callback pool, which it exposes
|
|
53
|
+
* as its `pool` property. The dialect unwraps it and uses the callback
|
|
54
|
+
* pool directly.
|
|
55
|
+
*/
|
|
56
|
+
export interface MysqlPromisePool {
|
|
57
|
+
pool: MysqlPool;
|
|
58
|
+
}
|
|
46
59
|
export interface MysqlConnection {
|
|
47
60
|
config: object;
|
|
48
61
|
connect(callback?: (error: unknown) => void): void;
|
|
@@ -52,6 +65,18 @@ export interface MysqlConnection {
|
|
|
52
65
|
};
|
|
53
66
|
threadId: number;
|
|
54
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* This interface is the subset of `mysql2/promise`'s `Connection` class that
|
|
70
|
+
* kysely needs.
|
|
71
|
+
*
|
|
72
|
+
* It's a thin promise wrapper around the callback connection. It's already
|
|
73
|
+
* connected when the `createConnection` promise resolves, so the dialect
|
|
74
|
+
* uses its promise-based API directly.
|
|
75
|
+
*/
|
|
76
|
+
export interface MysqlPromiseConnection {
|
|
77
|
+
destroy(): void;
|
|
78
|
+
query(sql: string, values?: unknown[]): Promise<unknown>;
|
|
79
|
+
}
|
|
55
80
|
export type MysqlConectionConstructor = new (opts?: object) => MysqlConnection;
|
|
56
81
|
export interface MysqlPoolConnection extends MysqlConnection {
|
|
57
82
|
release(): void;
|
|
@@ -11,7 +11,7 @@ import type { MysqlDialectConfig } from './mysql-dialect-config.js';
|
|
|
11
11
|
* The constructor takes an instance of {@link MysqlDialectConfig}.
|
|
12
12
|
*
|
|
13
13
|
* ```ts
|
|
14
|
-
* import { createPool } from 'mysql2'
|
|
14
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
15
15
|
*
|
|
16
16
|
* new MysqlDialect({
|
|
17
17
|
* pool: createPool({
|
|
@@ -25,7 +25,7 @@ import type { MysqlDialectConfig } from './mysql-dialect-config.js';
|
|
|
25
25
|
* can be a function:
|
|
26
26
|
*
|
|
27
27
|
* ```ts
|
|
28
|
-
* import { createPool } from 'mysql2'
|
|
28
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
29
29
|
*
|
|
30
30
|
* new MysqlDialect({
|
|
31
31
|
* pool: async () => createPool({
|
|
@@ -9,7 +9,7 @@ import { MysqlAdapter } from './mysql-adapter.js';
|
|
|
9
9
|
* The constructor takes an instance of {@link MysqlDialectConfig}.
|
|
10
10
|
*
|
|
11
11
|
* ```ts
|
|
12
|
-
* import { createPool } from 'mysql2'
|
|
12
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
13
13
|
*
|
|
14
14
|
* new MysqlDialect({
|
|
15
15
|
* pool: createPool({
|
|
@@ -23,7 +23,7 @@ import { MysqlAdapter } from './mysql-adapter.js';
|
|
|
23
23
|
* can be a function:
|
|
24
24
|
*
|
|
25
25
|
* ```ts
|
|
26
|
-
* import { createPool } from 'mysql2'
|
|
26
|
+
* import { createPool } from 'mysql2/promise' // or just 'mysql2' — both work
|
|
27
27
|
*
|
|
28
28
|
* new MysqlDialect({
|
|
29
29
|
* pool: async () => createPool({
|
|
@@ -13,9 +13,12 @@ export class MysqlDriver {
|
|
|
13
13
|
this.#config = freeze({ ...config });
|
|
14
14
|
}
|
|
15
15
|
async init(options) {
|
|
16
|
-
|
|
16
|
+
const pool = isFunction(this.#config.pool)
|
|
17
17
|
? await this.#config.pool(options)
|
|
18
18
|
: this.#config.pool;
|
|
19
|
+
// A `mysql2/promise` pool's `getConnection` ignores the callback we pass
|
|
20
|
+
// it, hanging any query forever. Unwrap the callback pool it decorates.
|
|
21
|
+
this.#pool = isPromisePool(pool) ? pool.pool : pool;
|
|
19
22
|
}
|
|
20
23
|
async acquireConnection(options) {
|
|
21
24
|
const rawConnection = await this.#acquireConnection();
|
|
@@ -93,6 +96,12 @@ export class MysqlDriver {
|
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
}
|
|
99
|
+
function isPromisePool(pool) {
|
|
100
|
+
return ('pool' in pool && isObject(pool.pool) && isFunction(pool.pool.getConnection));
|
|
101
|
+
}
|
|
102
|
+
function isPromiseConnection(connection) {
|
|
103
|
+
return isFunction(connection.then);
|
|
104
|
+
}
|
|
96
105
|
function isOkPacket(obj) {
|
|
97
106
|
return isObject(obj) && 'insertId' in obj && 'affectedRows' in obj;
|
|
98
107
|
}
|
|
@@ -224,7 +233,24 @@ class MysqlConnection {
|
|
|
224
233
|
const {
|
|
225
234
|
// omitting these as they cause a warning and perhaps a future error when passed.
|
|
226
235
|
clientFlags: _, maxPacketSize: __, ...cfg } = config;
|
|
227
|
-
const
|
|
236
|
+
const controlConnectionOrPromise = this.#controlConnection(cfg);
|
|
237
|
+
// `mysql2/promise`'s `createConnection` returns a promise of a connection
|
|
238
|
+
// that's already connected, with a promise-based API. Use it directly.
|
|
239
|
+
if (isPromiseConnection(controlConnectionOrPromise)) {
|
|
240
|
+
const controlConnection = await controlConnectionOrPromise;
|
|
241
|
+
try {
|
|
242
|
+
// by the time we get the connection, another query might have been executed.
|
|
243
|
+
// we need to ensure we're not canceling the wrong query.
|
|
244
|
+
if (queryIdToCancel.queryId === this.#queryId?.queryId) {
|
|
245
|
+
await controlConnection.query(query, []);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
controlConnection.destroy();
|
|
250
|
+
}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const controlConnection = controlConnectionOrPromise;
|
|
228
254
|
try {
|
|
229
255
|
await new Promise((resolve, reject) => {
|
|
230
256
|
controlConnection.connect((connectError) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
1
|
+
import type { DatabaseIntrospector, DatabaseMetadataOptions, DatabaseSchemaMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
2
2
|
import type { Kysely } from '../../kysely.js';
|
|
3
3
|
export declare class MysqlIntrospector implements DatabaseIntrospector {
|
|
4
4
|
#private;
|
|
@@ -6,7 +6,7 @@ export declare class MysqlIntrospector implements DatabaseIntrospector {
|
|
|
6
6
|
/**
|
|
7
7
|
* Get schema metadata.
|
|
8
8
|
*/
|
|
9
|
-
getSchemas(): Promise<SchemaMetadata[]>;
|
|
9
|
+
getSchemas(options?: DatabaseSchemaMetadataOptions): Promise<SchemaMetadata[]>;
|
|
10
10
|
/**
|
|
11
11
|
* Get tables and views metadata.
|
|
12
12
|
*/
|
|
@@ -2,18 +2,27 @@
|
|
|
2
2
|
import { DEFAULT_MIGRATION_LOCK_TABLE, DEFAULT_MIGRATION_TABLE, } from '../../migration/migrator.js';
|
|
3
3
|
import { freeze } from '../../util/object-utils.js';
|
|
4
4
|
import { sql } from '../../raw-builder/sql.js';
|
|
5
|
+
const SYSTEM_DATABASES = [
|
|
6
|
+
'information_schema',
|
|
7
|
+
'mysql',
|
|
8
|
+
'performance_schema',
|
|
9
|
+
'sys',
|
|
10
|
+
'ndbinfo',
|
|
11
|
+
];
|
|
5
12
|
export class MysqlIntrospector {
|
|
6
13
|
#db;
|
|
7
14
|
constructor(db) {
|
|
8
15
|
this.#db = db;
|
|
9
16
|
}
|
|
10
|
-
async getSchemas() {
|
|
11
|
-
let
|
|
17
|
+
async getSchemas(options = {}) {
|
|
18
|
+
let query = this.#db
|
|
12
19
|
.selectFrom('information_schema.schemata')
|
|
13
|
-
.select('schema_name')
|
|
14
|
-
.$
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
.select('schema_name as name')
|
|
21
|
+
.$narrowType();
|
|
22
|
+
if (options.where) {
|
|
23
|
+
query = query.where(options.where({ schema: sql.ref('schema_name') }));
|
|
24
|
+
}
|
|
25
|
+
return await query.execute();
|
|
17
26
|
}
|
|
18
27
|
async getTables(options = { withInternalKyselyTables: false }) {
|
|
19
28
|
let query = this.#db
|
|
@@ -28,34 +37,48 @@ export class MysqlIntrospector {
|
|
|
28
37
|
'columns.TABLE_NAME',
|
|
29
38
|
'columns.TABLE_SCHEMA',
|
|
30
39
|
'tables.TABLE_TYPE',
|
|
40
|
+
'tables.TABLE_COMMENT',
|
|
31
41
|
'tables.ENGINE',
|
|
32
42
|
'columns.IS_NULLABLE',
|
|
33
43
|
'columns.DATA_TYPE',
|
|
34
44
|
'columns.EXTRA',
|
|
35
45
|
'columns.COLUMN_COMMENT',
|
|
36
46
|
])
|
|
37
|
-
.where('columns.TABLE_SCHEMA', '
|
|
47
|
+
.where('columns.TABLE_SCHEMA', 'not in', SYSTEM_DATABASES)
|
|
48
|
+
.orderBy('columns.TABLE_SCHEMA')
|
|
38
49
|
.orderBy('columns.TABLE_NAME')
|
|
39
50
|
.orderBy('columns.ORDINAL_POSITION')
|
|
40
51
|
.$castTo();
|
|
52
|
+
if (!options.withNonDefaultDatabases) {
|
|
53
|
+
query = query.where('columns.TABLE_SCHEMA', '=', sql `database()`);
|
|
54
|
+
}
|
|
41
55
|
if (!options.withInternalKyselyTables) {
|
|
42
56
|
query = query
|
|
43
57
|
.where('columns.TABLE_NAME', '!=', DEFAULT_MIGRATION_TABLE)
|
|
44
58
|
.where('columns.TABLE_NAME', '!=', DEFAULT_MIGRATION_LOCK_TABLE);
|
|
45
59
|
}
|
|
60
|
+
if (options.where) {
|
|
61
|
+
query = query.where(options.where({
|
|
62
|
+
schema: sql.ref('columns.TABLE_SCHEMA'),
|
|
63
|
+
table: sql.ref('columns.TABLE_NAME'),
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
46
66
|
const rawColumns = await query.execute();
|
|
47
67
|
return this.#parseTableMetadata(rawColumns);
|
|
48
68
|
}
|
|
49
69
|
#parseTableMetadata(columns) {
|
|
50
70
|
return columns.reduce((tables, it) => {
|
|
51
|
-
let table = tables.find((tbl) => tbl.name === it.TABLE_NAME);
|
|
71
|
+
let table = tables.find((tbl) => tbl.name === it.TABLE_NAME && tbl.schema === it.TABLE_SCHEMA);
|
|
52
72
|
if (!table) {
|
|
53
73
|
table = freeze({
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
columns: [],
|
|
75
|
+
comment: it.TABLE_TYPE === 'VIEW' || it.TABLE_COMMENT === ''
|
|
76
|
+
? undefined
|
|
77
|
+
: it.TABLE_COMMENT,
|
|
56
78
|
isForeign: it.ENGINE === 'FEDERATED',
|
|
79
|
+
isView: it.TABLE_TYPE === 'VIEW',
|
|
80
|
+
name: it.TABLE_NAME,
|
|
57
81
|
schema: it.TABLE_SCHEMA,
|
|
58
|
-
columns: [],
|
|
59
82
|
});
|
|
60
83
|
tables.push(table);
|
|
61
84
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DatabaseIntrospector, DatabaseMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
1
|
+
import type { DatabaseIntrospector, DatabaseMetadataOptions, DatabaseSchemaMetadataOptions, SchemaMetadata, TableMetadata } from '../database-introspector.js';
|
|
2
2
|
import type { Kysely } from '../../kysely.js';
|
|
3
3
|
export declare class PostgresIntrospector implements DatabaseIntrospector {
|
|
4
4
|
#private;
|
|
@@ -6,7 +6,7 @@ export declare class PostgresIntrospector implements DatabaseIntrospector {
|
|
|
6
6
|
/**
|
|
7
7
|
* Get schema metadata.
|
|
8
8
|
*/
|
|
9
|
-
getSchemas(): Promise<SchemaMetadata[]>;
|
|
9
|
+
getSchemas(options?: DatabaseSchemaMetadataOptions): Promise<SchemaMetadata[]>;
|
|
10
10
|
/**
|
|
11
11
|
* Get tables and views metadata.
|
|
12
12
|
*/
|
|
@@ -7,13 +7,15 @@ export class PostgresIntrospector {
|
|
|
7
7
|
constructor(db) {
|
|
8
8
|
this.#db = db;
|
|
9
9
|
}
|
|
10
|
-
async getSchemas() {
|
|
11
|
-
let
|
|
10
|
+
async getSchemas(options = {}) {
|
|
11
|
+
let query = this.#db
|
|
12
12
|
.selectFrom('pg_catalog.pg_namespace')
|
|
13
|
-
.select('nspname')
|
|
14
|
-
.$
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
.select('nspname as name')
|
|
14
|
+
.$narrowType();
|
|
15
|
+
if (options.where) {
|
|
16
|
+
query = query.where(options.where({ schema: sql.ref('nspname') }));
|
|
17
|
+
}
|
|
18
|
+
return await query.execute();
|
|
17
19
|
}
|
|
18
20
|
async getTables(options = { withInternalKyselyTables: false }) {
|
|
19
21
|
let query = this.#db
|
|
@@ -36,12 +38,14 @@ export class PostgresIntrospector {
|
|
|
36
38
|
'ns.nspname as schema',
|
|
37
39
|
'typ.typname as type',
|
|
38
40
|
'dtns.nspname as type_schema',
|
|
41
|
+
sql `obj_description(c.oid, 'pg_class')`.as('table_description'),
|
|
39
42
|
sql `col_description(a.attrelid, a.attnum)`.as('column_description'),
|
|
40
43
|
sql `pg_get_serial_sequence(quote_ident(ns.nspname) || '.' || quote_ident(c.relname), a.attname)`.as('auto_incrementing'),
|
|
41
44
|
])
|
|
42
45
|
.where('c.relkind', 'in', [
|
|
43
46
|
'r' /*regular table*/,
|
|
44
47
|
'v' /*view*/,
|
|
48
|
+
'm' /*materialized view*/,
|
|
45
49
|
'p' /*partitioned table*/,
|
|
46
50
|
'f' /*foreign table*/,
|
|
47
51
|
])
|
|
@@ -63,6 +67,12 @@ export class PostgresIntrospector {
|
|
|
63
67
|
.where('c.relname', '!=', DEFAULT_MIGRATION_TABLE)
|
|
64
68
|
.where('c.relname', '!=', DEFAULT_MIGRATION_LOCK_TABLE);
|
|
65
69
|
}
|
|
70
|
+
if (options.where) {
|
|
71
|
+
query = query.where(options.where({
|
|
72
|
+
schema: sql.ref('ns.nspname'),
|
|
73
|
+
table: sql.ref('c.relname'),
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
66
76
|
const rawColumns = await query.execute();
|
|
67
77
|
return this.#parseTableMetadata(rawColumns);
|
|
68
78
|
}
|
|
@@ -79,8 +89,9 @@ export class PostgresIntrospector {
|
|
|
79
89
|
if (!table) {
|
|
80
90
|
table = freeze({
|
|
81
91
|
columns: [],
|
|
92
|
+
comment: column.table_description ?? undefined,
|
|
82
93
|
isForeign: column.table_type === 'f',
|
|
83
|
-
isView: column.table_type === 'v',
|
|
94
|
+
isView: column.table_type === 'v' || column.table_type === 'm',
|
|
84
95
|
name: column.table,
|
|
85
96
|
schema: column.schema,
|
|
86
97
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/// <reference types="./sqlite-driver.d.ts" />
|
|
2
|
-
import { SelectQueryNode } from '../../operation-node/select-query-node.js';
|
|
3
2
|
import { parseSavepointCommand } from '../../parser/savepoint-parser.js';
|
|
4
3
|
import { CompiledQuery } from '../../query-compiler/compiled-query.js';
|
|
5
4
|
import { freeze, isFunction } from '../../util/object-utils.js';
|
|
@@ -68,14 +67,14 @@ class SqliteConnection {
|
|
|
68
67
|
rows: [],
|
|
69
68
|
};
|
|
70
69
|
}
|
|
71
|
-
async *streamQuery(compiledQuery
|
|
72
|
-
const { sql, parameters
|
|
73
|
-
const
|
|
74
|
-
if (!
|
|
75
|
-
throw new Error('Sqlite driver only supports streaming of
|
|
70
|
+
async *streamQuery(compiledQuery) {
|
|
71
|
+
const { sql, parameters } = compiledQuery;
|
|
72
|
+
const statement = this.#db.prepare(sql);
|
|
73
|
+
if (!statement.reader) {
|
|
74
|
+
throw new Error('Sqlite driver only supports streaming of queries that return rows');
|
|
76
75
|
}
|
|
77
|
-
const
|
|
78
|
-
for (const row of
|
|
76
|
+
const rows = statement.iterate(parameters);
|
|
77
|
+
for (const row of rows) {
|
|
79
78
|
yield {
|
|
80
79
|
rows: [row],
|
|
81
80
|
};
|
|
@@ -25,6 +25,9 @@ export class SqliteIntrospector {
|
|
|
25
25
|
.where('name', '!=', DEFAULT_MIGRATION_TABLE)
|
|
26
26
|
.where('name', '!=', DEFAULT_MIGRATION_LOCK_TABLE);
|
|
27
27
|
}
|
|
28
|
+
if (options.where) {
|
|
29
|
+
tablesQuery = tablesQuery.where(options.where({ table: sql.ref('name') }));
|
|
30
|
+
}
|
|
28
31
|
return tablesQuery;
|
|
29
32
|
}
|
|
30
33
|
async #getTableMetadata(options) {
|
|
@@ -70,9 +73,6 @@ export class SqliteIntrospector {
|
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
75
|
return {
|
|
73
|
-
name: name,
|
|
74
|
-
isView: type === 'view',
|
|
75
|
-
isForeign: false,
|
|
76
76
|
columns: columns.map((col) => ({
|
|
77
77
|
name: col.name,
|
|
78
78
|
dataType: col.type,
|
|
@@ -81,6 +81,10 @@ export class SqliteIntrospector {
|
|
|
81
81
|
hasDefaultValue: col.dflt_value != null,
|
|
82
82
|
comment: undefined,
|
|
83
83
|
})),
|
|
84
|
+
comment: undefined,
|
|
85
|
+
isForeign: false,
|
|
86
|
+
isView: type === 'view',
|
|
87
|
+
name,
|
|
84
88
|
};
|
|
85
89
|
});
|
|
86
90
|
}
|
|
@@ -29,8 +29,8 @@ import type { Driver } from './driver.js';
|
|
|
29
29
|
* })
|
|
30
30
|
* ```
|
|
31
31
|
*
|
|
32
|
-
* You can use it to build a query and compile it to SQL
|
|
33
|
-
*
|
|
32
|
+
* You can use it to build a query and compile it to SQL. Executing queries
|
|
33
|
+
* returns empty results without communicating with a database.
|
|
34
34
|
*
|
|
35
35
|
* ```ts
|
|
36
36
|
* const { sql } = db.selectFrom('person').selectAll().compile()
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
* })
|
|
29
29
|
* ```
|
|
30
30
|
*
|
|
31
|
-
* You can use it to build a query and compile it to SQL
|
|
32
|
-
*
|
|
31
|
+
* You can use it to build a query and compile it to SQL. Executing queries
|
|
32
|
+
* returns empty results without communicating with a database.
|
|
33
33
|
*
|
|
34
34
|
* ```ts
|
|
35
35
|
* const { sql } = db.selectFrom('person').selectAll().compile()
|