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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/dialect/database-introspector.d.ts +38 -4
  3. package/dist/dialect/mssql/mssql-introspector.d.ts +2 -2
  4. package/dist/dialect/mssql/mssql-introspector.js +32 -2
  5. package/dist/dialect/mysql/mysql-dialect-config.d.ts +31 -6
  6. package/dist/dialect/mysql/mysql-dialect.d.ts +2 -2
  7. package/dist/dialect/mysql/mysql-dialect.js +2 -2
  8. package/dist/dialect/mysql/mysql-driver.js +28 -2
  9. package/dist/dialect/mysql/mysql-introspector.d.ts +2 -2
  10. package/dist/dialect/mysql/mysql-introspector.js +34 -11
  11. package/dist/dialect/postgres/postgres-introspector.d.ts +2 -2
  12. package/dist/dialect/postgres/postgres-introspector.js +18 -7
  13. package/dist/dialect/sqlite/sqlite-driver.js +7 -8
  14. package/dist/dialect/sqlite/sqlite-introspector.js +7 -3
  15. package/dist/driver/dummy-driver.d.ts +2 -2
  16. package/dist/driver/dummy-driver.js +2 -2
  17. package/dist/kysely.d.ts +27 -7
  18. package/dist/kysely.js +0 -14
  19. package/dist/migration/file-migration-provider.d.ts +1 -1
  20. package/dist/migration/file-migration-provider.js +1 -1
  21. package/dist/migration/migrator.d.ts +48 -9
  22. package/dist/migration/migrator.js +62 -19
  23. package/dist/query-builder/delete-query-builder.d.ts +2 -2
  24. package/dist/query-builder/function-module.d.ts +8 -2
  25. package/dist/query-builder/join-builder.d.ts +2 -2
  26. package/dist/query-builder/merge-query-builder.d.ts +9 -1
  27. package/dist/query-builder/select-query-builder.d.ts +28 -6
  28. package/dist/query-builder/update-query-builder.d.ts +1 -1
  29. package/dist/query-creator.d.ts +9 -0
  30. package/dist/raw-builder/raw-builder.d.ts +5 -0
  31. package/dist/raw-builder/raw-builder.js +12 -0
  32. package/dist/readonly/readonly-kysely.d.ts +64 -10
  33. package/dist/readonly/readonly-query-creator.d.ts +9 -1
  34. package/dist/schema/create-type-builder.d.ts +1 -1
  35. package/dist/schema/create-type-builder.js +1 -1
  36. package/dist/util/abort.js +2 -0
  37. package/package.json +18 -16
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua)
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/kysely?style=flat&label=latest)](https://github.com/kysely-org/kysely/releases/latest)
4
- [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.30.0-beta.0)](https://socket.dev/npm/package/kysely/overview/0.30.0-beta.0)
4
+ [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.30.0-beta.2)](https://socket.dev/npm/package/kysely/overview/0.30.0-beta.2)
5
5
  [![Tests](https://github.com/kysely-org/kysely/actions/workflows/test.yml/badge.svg)](https://github.com/kysely-org/kysely)
6
6
  [![License](https://img.shields.io/github/license/kysely-org/kysely?style=flat)](https://github.com/kysely-org/kysely/blob/master/LICENSE)
7
7
  [![Issues](https://img.shields.io/github/issues-closed/kysely-org/kysely?logo=github)](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
- return await this.#db.selectFrom('sys.schemas').select('name').execute();
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 `mysql2` `Client` constructor, to be used for connecting to the database
9
- * outside of the `pool` to avoid waiting for an idle connection.
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 or a function that returns one.
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
- this.#pool = isFunction(this.#config.pool)
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 controlConnection = this.#controlConnection(cfg);
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 rawSchemas = await this.#db
17
+ async getSchemas(options = {}) {
18
+ let query = this.#db
12
19
  .selectFrom('information_schema.schemata')
13
- .select('schema_name')
14
- .$castTo()
15
- .execute();
16
- return rawSchemas.map((it) => ({ name: it.SCHEMA_NAME }));
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', '=', sql `database()`)
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
- name: it.TABLE_NAME,
55
- isView: it.TABLE_TYPE === 'VIEW',
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 rawSchemas = await this.#db
10
+ async getSchemas(options = {}) {
11
+ let query = this.#db
12
12
  .selectFrom('pg_catalog.pg_namespace')
13
- .select('nspname')
14
- .$castTo()
15
- .execute();
16
- return rawSchemas.map((it) => ({ name: it.nspname }));
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, _chunkSize) {
72
- const { sql, parameters, query } = compiledQuery;
73
- const stmt = this.#db.prepare(sql);
74
- if (!SelectQueryNode.is(query)) {
75
- throw new Error('Sqlite driver only supports streaming of select queries');
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 iter = stmt.iterate(parameters);
78
- for (const row of iter) {
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 but trying to
33
- * execute the query will throw an error.
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 but trying to
32
- * execute the query will throw an error.
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()