Skip to content

Commit

Permalink
feat: Migrate createSchema() to TypeScript (#15339)
Browse files Browse the repository at this point in the history
* Initial refactorings of query-interface.d.ts interfaces to files

Created constructor and initial typings for AbstractQueryInterface

* Add createSchema to AbstractQueryInterfaceTypeScript

* QueryInterface should pass options through to queryGenerator

* Avoid InvalidOptionReceivedErrors on dialects that don't support collate/charset

* Move QueryInterface types to a separate file
  • Loading branch information
evanrittenhouse committed Dec 11, 2022
1 parent a9f2223 commit a3d164f
Show file tree
Hide file tree
Showing 23 changed files with 127 additions and 70 deletions.
27 changes: 27 additions & 0 deletions src/dialects/abstract/query-interface-typescript.ts
@@ -0,0 +1,27 @@
import type { Sequelize } from '../../sequelize';
import type { AbstractQueryGenerator } from './query-generator';
import type { CreateSchemaOptions, QueryInterfaceOptions } from './query-interface.types';

export class AbstractQueryInterfaceTypeScript {
readonly sequelize: Sequelize;
readonly queryGenerator: AbstractQueryGenerator;

constructor(options: QueryInterfaceOptions) {
this.sequelize = options.sequelize;
this.queryGenerator = options.queryGenerator;
}

/**
* Creates a new database schema.
*
* **Note:** this is a schema in the [postgres sense of the word](http://www.postgresql.org/docs/9.1/static/ddl-schemas.html),
* not a database table. In mysql and sqlite, this command will do nothing.
*
* @param schema
* @param options
*/
async createSchema(schema: string, options?: CreateSchemaOptions): Promise<void> {
const sql = this.queryGenerator.createSchemaQuery(schema, options);
await this.sequelize.queryRaw(sql, options);
}
}
12 changes: 3 additions & 9 deletions src/dialects/abstract/query-interface.d.ts
Expand Up @@ -18,6 +18,7 @@ import type { Fn, Literal, Col } from '../../utils/sequelize-method.js';
import type { DataType } from './data-types.js';
import type { TableNameOrModel } from './query-generator-typescript';
import type { AbstractQueryGenerator, AddColumnQueryOptions, RemoveColumnQueryOptions } from './query-generator.js';
import { AbstractQueryInterfaceTypeScript } from './query-interface-typescript';

interface Replaceable {
/**
Expand Down Expand Up @@ -280,7 +281,7 @@ export interface RemoveColumnOptions extends RemoveColumnQueryOptions, QueryRawO
* This interface is available through sequelize.queryInterface. It should not be commonly used, but it's
* referenced anyway, so it can be used.
*/
export class QueryInterface {
export class AbstractQueryInterface extends AbstractQueryInterfaceTypeScript {
/**
* Returns the dialect-specific sql generator.
*
Expand All @@ -295,13 +296,6 @@ export class QueryInterface {

constructor(sequelize: Sequelize, queryGenerator: AbstractQueryGenerator);

/**
* Queries the schema (table list).
*
* @param schema The schema to query. Applies only to Postgres.
*/
createSchema(schema?: string, options?: QueryRawOptions): Promise<void>;

/**
* Drops the specified schema (table).
*
Expand All @@ -319,7 +313,7 @@ export class QueryInterface {
*
* @param options
*/
showAllSchemas(options?: QueryRawOptions): Promise<object>;
showAllSchemas(options?: QueryRawOptions): Promise<string[]>;

/**
* Return database version
Expand Down
21 changes: 3 additions & 18 deletions src/dialects/abstract/query-interface.js
Expand Up @@ -4,6 +4,7 @@ import { cloneDeep } from '../../utils/object';
import { noSchemaParameter, noSchemaDelimiterParameter } from '../../utils/deprecations';
import { assertNoReservedBind, combineBinds } from '../../utils/sql';
import { AbstractDataType } from './data-types';
import { AbstractQueryInterfaceTypeScript } from './query-interface-typescript';

const _ = require('lodash');

Expand All @@ -14,11 +15,9 @@ const { QueryTypes } = require('../../query-types');
/**
* The interface that Sequelize uses to talk to all databases
*/
// TODO: rename to AbstractQueryInterface
export class QueryInterface {
export class AbstractQueryInterface extends AbstractQueryInterfaceTypeScript {
constructor(sequelize, queryGenerator) {
this.sequelize = sequelize;
this.queryGenerator = queryGenerator;
super({ sequelize, queryGenerator });
}

/**
Expand Down Expand Up @@ -61,20 +60,6 @@ export class QueryInterface {
return await this.sequelize.queryRaw(sql, { ...options, type: QueryTypes.SELECT });
}

/**
* Create a schema
*
* @param {string} schema Schema name to create
* @param {object} [options] Query options
*
* @returns {Promise}
*/
async createSchema(schema, options) {
const sql = this.queryGenerator.createSchemaQuery(schema);

return await this.sequelize.queryRaw(sql, options);
}

/**
* Drop a schema
*
Expand Down
10 changes: 10 additions & 0 deletions src/dialects/abstract/query-interface.types.ts
@@ -0,0 +1,10 @@
import type { QueryRawOptions, Sequelize } from '../../sequelize';
import type { AbstractQueryGenerator, CreateSchemaQueryOptions } from './query-generator';

export interface QueryInterfaceOptions {
sequelize: Sequelize;
queryGenerator: AbstractQueryGenerator;
}

/** Options accepted by {@link AbstractQueryInterfaceTypeScript#createSchema} */
export interface CreateSchemaOptions extends CreateSchemaQueryOptions, QueryRawOptions {}
4 changes: 2 additions & 2 deletions src/dialects/db2/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { Db2QueryGenerator } from './query-generator.js';

export class Db2QueryInterface extends QueryInterface {
export class Db2QueryInterface extends AbstractQueryInterface {
queryGenerator: Db2QueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: Db2QueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/db2/query-interface.js
Expand Up @@ -6,13 +6,13 @@ import { assertNoReservedBind } from '../../utils/sql';

const _ = require('lodash');
const { Op } = require('../../operators');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');
const { QueryTypes } = require('../../query-types');

/**
* The interface that Sequelize uses to talk with Db2 database
*/
export class Db2QueryInterface extends QueryInterface {
export class Db2QueryInterface extends AbstractQueryInterface {
async getForeignKeyReferencesForTable(tableName, options) {
const queryOptions = {
...options,
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/ibmi/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { IBMiQueryGenerator } from './query-generator.js';

export class IBMiQueryInterface extends QueryInterface {
export class IBMiQueryInterface extends AbstractQueryInterface {
queryGenerator: IBMiQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: IBMiQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/ibmi/query-interface.js
@@ -1,7 +1,7 @@
'use strict';

const { Transaction } = require('../../transaction');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');

/**
Returns an object that enables the `ibmi` dialect to call underlying odbc
Expand All @@ -12,7 +12,7 @@ const { QueryInterface } = require('../abstract/query-interface');
@private
*/

export class IBMiQueryInterface extends QueryInterface {
export class IBMiQueryInterface extends AbstractQueryInterface {

startTransaction(transaction, options) {
if (!(transaction instanceof Transaction)) {
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/mssql/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { MsSqlQueryGenerator } from './query-generator.js';

export class MsSqlQueryInterface extends QueryInterface {
export class MsSqlQueryInterface extends AbstractQueryInterface {
queryGenerator: MsSqlQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: MsSqlQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/mssql/query-interface.js
Expand Up @@ -7,12 +7,12 @@ const _ = require('lodash');

const { QueryTypes } = require('../../query-types');
const { Op } = require('../../operators');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');

/**
* The interface that Sequelize uses to talk with MSSQL database
*/
export class MsSqlQueryInterface extends QueryInterface {
export class MsSqlQueryInterface extends AbstractQueryInterface {
/**
* A wrapper that fixes MSSQL's inability to cleanly remove columns from existing tables if they have a default constraint.
*
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/mysql/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { MySqlQueryGenerator } from './query-generator.js';

export class MySqlQueryInterface extends QueryInterface {
export class MySqlQueryInterface extends AbstractQueryInterface {
queryGenerator: MySqlQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: MySqlQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/mysql/query-interface.js
Expand Up @@ -3,13 +3,13 @@
import { assertNoReservedBind, combineBinds } from '../../utils/sql';

const sequelizeErrors = require('../../errors');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');
const { QueryTypes } = require('../../query-types');

/**
* The interface that Sequelize uses to talk with MySQL/MariaDB database
*/
export class MySqlQueryInterface extends QueryInterface {
export class MySqlQueryInterface extends AbstractQueryInterface {
/**
* A wrapper that fixes MySQL's inability to cleanly remove columns from existing tables if they have a foreign key constraint.
*
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/postgres/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { PostgresQueryGenerator } from './query-generator.js';

export class PostgresQueryInterface extends QueryInterface {
export class PostgresQueryInterface extends AbstractQueryInterface {
queryGenerator: PostgresQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: PostgresQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/postgres/query-interface.js
Expand Up @@ -5,12 +5,12 @@ import { camelizeObjectKeys } from '../../utils/object';

const DataTypes = require('../../data-types');
const { QueryTypes } = require('../../query-types');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');

/**
* The interface that Sequelize uses to talk with Postgres database
*/
export class PostgresQueryInterface extends QueryInterface {
export class PostgresQueryInterface extends AbstractQueryInterface {
/**
* Ensure enum and their values.
*
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/snowflake/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { SnowflakeQueryGenerator } from './query-generator.js';

export class SnowflakeQueryInterface extends QueryInterface {
export class SnowflakeQueryInterface extends AbstractQueryInterface {
queryGenerator: SnowflakeQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: SnowflakeQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/snowflake/query-interface.js
Expand Up @@ -3,13 +3,13 @@
import { assertNoReservedBind, combineBinds } from '../../utils/sql';

const sequelizeErrors = require('../../errors');
const { QueryInterface } = require('../abstract/query-interface');
const { AbstractQueryInterface } = require('../abstract/query-interface');
const { QueryTypes } = require('../../query-types');

/**
* The interface that Sequelize uses to talk with Snowflake database
*/
export class SnowflakeQueryInterface extends QueryInterface {
export class SnowflakeQueryInterface extends AbstractQueryInterface {
/**
* A wrapper that fixes Snowflake's inability to cleanly remove columns from existing tables if they have a foreign key
* constraint.
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/sqlite/query-interface.d.ts
@@ -1,8 +1,8 @@
import type { Sequelize } from '../../sequelize.js';
import { QueryInterface } from '../abstract/query-interface.js';
import { AbstractQueryInterface } from '../abstract/query-interface.js';
import type { SqliteQueryGenerator } from './query-generator.js';

export class SqliteQueryInterface extends QueryInterface {
export class SqliteQueryInterface extends AbstractQueryInterface {
queryGenerator: SqliteQueryGenerator;

constructor(sequelize: Sequelize, queryGenerator: SqliteQueryGenerator);
Expand Down
4 changes: 2 additions & 2 deletions src/dialects/sqlite/query-interface.js
Expand Up @@ -4,15 +4,15 @@ import { noSchemaParameter, noSchemaDelimiterParameter } from '../../utils/depre

const sequelizeErrors = require('../../errors');
const { QueryTypes } = require('../../query-types');
const { QueryInterface, QueryOptions, ColumnsDescription } = require('../abstract/query-interface');
const { AbstractQueryInterface, QueryOptions, ColumnsDescription } = require('../abstract/query-interface');
const { cloneDeep } = require('../../utils/object.js');
const _ = require('lodash');
const crypto = require('node:crypto');

/**
* The interface that Sequelize uses to talk with SQLite database
*/
export class SqliteQueryInterface extends QueryInterface {
export class SqliteQueryInterface extends AbstractQueryInterface {
/**
* A wrapper that fixes SQLite's inability to remove columns from existing tables.
* It will create a backup of the table, drop the table afterwards and create a
Expand Down
4 changes: 2 additions & 2 deletions src/model-typescript.ts
Expand Up @@ -27,7 +27,7 @@ import type {
UpsertOptions,
Sequelize,
AbstractQueryGenerator,
QueryInterface,
AbstractQueryInterface,
} from '.';

export interface ModelHooks<M extends Model = Model, TAttributes = any> {
Expand Down Expand Up @@ -145,7 +145,7 @@ const staticPrivateStates = new WeakMap<typeof ModelTypeScript, { sequelize?: Se
// DO NOT EXPORT THIS CLASS!
// This is a temporary class to progressively migrate the Sequelize class to TypeScript by slowly moving its functions here.
export class ModelTypeScript {
static get queryInterface(): QueryInterface {
static get queryInterface(): AbstractQueryInterface {
return this.sequelize.queryInterface;
}

Expand Down
9 changes: 5 additions & 4 deletions src/sequelize.d.ts
Expand Up @@ -2,7 +2,8 @@ import type { Options as RetryAsPromisedOptions } from 'retry-as-promised';
import type { AbstractDialect } from './dialects/abstract';
import type { AbstractConnectionManager } from './dialects/abstract/connection-manager';
import type { AbstractDataType, DataTypeClassOrInstance } from './dialects/abstract/data-types.js';
import type { QueryInterface, ColumnsDescription } from './dialects/abstract/query-interface';
import type { AbstractQueryInterface, ColumnsDescription } from './dialects/abstract/query-interface';
import type { CreateSchemaOptions } from './dialects/abstract/query-interface.types';
import type {
DestroyOptions,
DropOptions,
Expand Down Expand Up @@ -765,12 +766,12 @@ export class Sequelize extends SequelizeTypeScript {
/**
* Returns the dialect-dependant QueryInterface instance.
*/
getQueryInterface(): QueryInterface;
getQueryInterface(): AbstractQueryInterface;

/**
* The QueryInterface instance, dialect dependant.
*/
queryInterface: QueryInterface;
queryInterface: AbstractQueryInterface;

/**
* Define a new model, representing a table in the DB.
Expand Down Expand Up @@ -934,7 +935,7 @@ export class Sequelize extends SequelizeTypeScript {
* @param schema Name of the schema
* @param options Options supplied
*/
createSchema(schema: string, options?: Logging): Promise<unknown>;
createSchema(schema: string, options?: CreateSchemaOptions): Promise<void>;

/**
* Show all defined schemas
Expand Down

0 comments on commit a3d164f

Please sign in to comment.