Skip to content

Commit

Permalink
fix: type renameTableQuery, removeConstraintQuery, versionQuery (#15813)
Browse files Browse the repository at this point in the history
  • Loading branch information
WikiRik committed Apr 2, 2023
1 parent 70486fc commit 8928c6d
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 155 deletions.
9 changes: 7 additions & 2 deletions packages/core/src/dialects/abstract/query-generator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class AbstractQueryGenerator extends AbstractQueryGeneratorTypeScript {
): string;

removeColumnQuery(
table: TableName,
table: TableNameOrModel,
attributeName: string,
options?: RemoveColumnQueryOptions,
): string;
Expand Down Expand Up @@ -179,7 +179,8 @@ export class AbstractQueryGenerator extends AbstractQueryGeneratorTypeScript {
// TODO: throw when using invalid options when migrating to TS
options?: CreateTableQueryOptions
): string;
dropTableQuery(tableName: TableName, options?: DropTableQueryOptions): string;
dropTableQuery(tableName: TableNameOrModel, options?: DropTableQueryOptions): string;
renameTableQuery(before: TableNameOrModel, after: TableNameOrModel): string;

createSchemaQuery(schemaName: string, options?: CreateSchemaQueryOptions): string;
dropSchemaQuery(schemaName: string): string | QueryWithBindParams;
Expand All @@ -192,6 +193,10 @@ export class AbstractQueryGenerator extends AbstractQueryGeneratorTypeScript {

dropForeignKeyQuery(tableName: TableNameOrModel, foreignKey: string): string;

removeConstraintQuery(tableName: TableNameOrModel, constraintName: string): string;

versionQuery(): string;

/**
* Creates a function that can be used to collect bind parameters.
*
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/dialects/abstract/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Col } from '../../expression-builders/col.js';
import { Literal } from '../../expression-builders/literal.js';
import { conformIndex } from '../../model-internals';
import { and } from '../../sequelize';
import { rejectInvalidOptions, canTreatArrayAsAnd, isColString } from '../../utils/check';
import { rejectInvalidOptions } from '../../utils/check';
import {
mapFinderOptions,
removeNullishValuesFromHash,
Expand Down Expand Up @@ -872,7 +872,7 @@ export class AbstractQueryGenerator extends AbstractQueryGeneratorTypeScript {
'ALTER TABLE',
this.quoteTable(tableName),
'DROP CONSTRAINT',
this.quoteIdentifiers(constraintName),
this.quoteIdentifier(constraintName),
]);
}

Expand Down
22 changes: 0 additions & 22 deletions packages/core/src/dialects/db2/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,35 +809,13 @@ export class Db2QueryGenerator extends Db2QueryGeneratorTypeScript {
return this._getForeignKeysQuerySQL(sql);
}

getPrimaryKeyConstraintQuery(table, attributeName) {
const tableName = wrapSingleQuote(table.tableName || table);

return [
'SELECT TABNAME AS "tableName",',
'COLNAME AS "columnName",',
'CONSTNAME AS "constraintName"',
'FROM SYSCAT.KEYCOLUSE WHERE CONSTNAME LIKE \'PK_%\'',
`AND COLNAME = ${wrapSingleQuote(attributeName)}`,
`AND TABNAME = ${tableName};`,
].join(' ');
}

dropForeignKeyQuery(tableName, foreignKey) {
return _.template('ALTER TABLE <%= table %> DROP FOREIGN KEY <%= key %>;', this._templateSettings)({
table: this.quoteTable(tableName),
key: this.quoteIdentifier(foreignKey),
});
}

dropConstraintQuery(tableName, constraintName) {
const sql = 'ALTER TABLE <%= table %> DROP CONSTRAINT <%= constraint %>;';

return _.template(sql, this._templateSettings)({
table: this.quoteTable(tableName),
constraint: this.quoteIdentifier(constraintName),
});
}

setAutocommitQuery() {
return '';
}
Expand Down
6 changes: 2 additions & 4 deletions packages/core/src/dialects/postgres/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ import {
DROP_TABLE_QUERY_SUPPORTABLE_OPTIONS,
} from '../abstract/query-generator';

const util = require('node:util');
const DataTypes = require('../../data-types');
const { PostgresQueryGeneratorTypeScript } = require('./query-generator-typescript');
const semver = require('semver');
const _ = require('lodash');

/**
Expand Down Expand Up @@ -187,7 +185,7 @@ export class PostgresQueryGenerator extends PostgresQueryGeneratorTypeScript {
const dataType = attribute.type || attribute;
const definition = this.dataTypeMapping(table, key, dbDataType);
const quotedKey = this.quoteIdentifier(key);
const quotedTable = this.quoteTable(this.extractTableDetails(table));
const quotedTable = this.quoteTable(table);
const ifNotExists = options.ifNotExists ? ' IF NOT EXISTS' : '';

let query = `ALTER TABLE ${quotedTable} ADD COLUMN ${ifNotExists} ${quotedKey} ${definition};`;
Expand All @@ -204,7 +202,7 @@ export class PostgresQueryGenerator extends PostgresQueryGeneratorTypeScript {
removeColumnQuery(tableName, attributeName, options) {
options = options || {};

const quotedTableName = this.quoteTable(this.extractTableDetails(tableName));
const quotedTableName = this.quoteTable(tableName);
const quotedAttributeName = this.quoteIdentifier(attributeName);
const ifExists = options.ifExists ? ' IF EXISTS' : '';

Expand Down
7 changes: 2 additions & 5 deletions packages/core/src/dialects/snowflake/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ const _ = require('lodash');
const { SnowflakeQueryGeneratorTypeScript } = require('./query-generator-typescript');
const { Op } = require('../../operators');

const JSON_FUNCTION_REGEX = /^\s*((?:[a-z]+_){0,2}jsonb?(?:_[a-z]+){0,2})\([^)]*\)/i;
const JSON_OPERATOR_REGEX = /^\s*(->>?|@>|<@|\?[&|]?|\|{2}|#-)/i;
const TOKEN_CAPTURE_REGEX = /^\s*((?:(["'`])(?:(?!\2).|\2{2})*\2)|[\s\w]+|[()+,.;-])/i;
const FOREIGN_KEY_FIELDS = [
'CONSTRAINT_NAME as constraint_name',
'CONSTRAINT_NAME as constraintName',
Expand Down Expand Up @@ -197,10 +194,10 @@ export class SnowflakeQueryGenerator extends SnowflakeQueryGeneratorTypeScript {
]);
}

showTablesQuery(database, options) {
showTablesQuery(database) {
return joinSQLFragments([
'SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = \'BASE TABLE\'',
database ? `AND TABLE_SCHEMA = ${this.escape(database, options)}` : 'AND TABLE_SCHEMA NOT IN ( \'INFORMATION_SCHEMA\', \'PERFORMANCE_SCHEMA\', \'SYS\')',
database ? `AND TABLE_SCHEMA = ${this.escape(database)}` : 'AND TABLE_SCHEMA NOT IN ( \'INFORMATION_SCHEMA\', \'PERFORMANCE_SCHEMA\', \'SYS\')',
';',
]);
}
Expand Down
18 changes: 9 additions & 9 deletions packages/core/src/dialects/sqlite/query-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ export class SqliteQueryGenerator extends SqliteQueryGeneratorTypeScript {
return `SELECT sql FROM sqlite_master WHERE tbl_name='${tableName}';`;
}

// TODO: this should not implement `removeColumnQuery` but a new sqlite specific function possibly called `replaceTableQuery`
removeColumnQuery(tableName, attributes, options) {
if (options) {
rejectInvalidOptions(
Expand All @@ -304,15 +305,14 @@ export class SqliteQueryGenerator extends SqliteQueryGeneratorTypeScript {

attributes = this.attributesToSQL(attributes);

let backupTableName;
if (typeof tableName === 'object') {
backupTableName = {
tableName: `${tableName.tableName}_backup`,
schema: tableName.schema,
};
} else {
backupTableName = `${tableName}_backup`;
}
const table = this.extractTableDetails(tableName);

// TODO: this is unsafe, this table could already exist
const backupTableName = {
tableName: `${table.tableName}_backup`,
schema: table.schema,
delimiter: table.delimiter,
};

const quotedTableName = this.quoteTable(tableName);
const quotedBackupTableName = this.quoteTable(backupTableName);
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/types/sequelize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ class Model1 extends Model {}

class Model2 extends Model {}

const myModel: ModelStatic<Model1> = sequelize.models.asd;
myModel.hasOne(Model2);
myModel.findAll();
const MyModel: ModelStatic<Model1> = sequelize.models.asd;
MyModel.hasOne(Model2);
MyModel.findAll();

async function test() {
const [results, meta]: [unknown[], unknown] = await sequelize.query('SELECT * FROM `user`', { type: QueryTypes.RAW });
Expand Down
19 changes: 0 additions & 19 deletions packages/core/test/unit/dialects/mssql/query-generator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const expectsql = Support.expectsql;
const current = Support.sequelize;
const { DataTypes, Op, TableHints } = require('@sequelize/core');
const { MsSqlQueryGenerator: QueryGenerator } = require('@sequelize/core/_non-semver-use-at-your-own-risk_/dialects/mssql/query-generator.js');
const { _validateIncludedElements } = require('@sequelize/core/_non-semver-use-at-your-own-risk_/model-internals.js');

if (current.dialect.name === 'mssql') {
describe('[MSSQL Specific] QueryGenerator', () => {
Expand Down Expand Up @@ -138,18 +137,6 @@ if (current.dialect.name === 'mssql') {
});
});

it('versionQuery', function () {
expectsql(this.queryGenerator.versionQuery(), {
mssql: 'DECLARE @ms_ver NVARCHAR(20); SET @ms_ver = REVERSE(CONVERT(NVARCHAR(20), SERVERPROPERTY(\'ProductVersion\'))); SELECT REVERSE(SUBSTRING(@ms_ver, CHARINDEX(\'.\', @ms_ver)+1, 20)) AS \'version\'',
});
});

it('renameTableQuery', function () {
expectsql(this.queryGenerator.renameTableQuery('oldTableName', 'newTableName'), {
mssql: 'EXEC sp_rename [oldTableName], [newTableName];',
});
});

it('showTablesQuery', function () {
expectsql(this.queryGenerator.showTablesQuery(), {
mssql: 'SELECT TABLE_NAME, TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = \'BASE TABLE\';',
Expand All @@ -172,12 +159,6 @@ if (current.dialect.name === 'mssql') {
});
});

it('removeColumnQuery', function () {
expectsql(this.queryGenerator.removeColumnQuery('myTable', 'myColumn'), {
mssql: 'ALTER TABLE [myTable] DROP COLUMN [myColumn];',
});
});

it('getForeignKeysQuery', function () {
expectsql(this.queryGenerator.getForeignKeysQuery('myTable'), {
mssql: 'SELECT constraint_name = OBJ.NAME, constraintName = OBJ.NAME, constraintSchema = SCHEMA_NAME(OBJ.SCHEMA_ID), tableName = TB.NAME, tableSchema = SCHEMA_NAME(TB.SCHEMA_ID), columnName = COL.NAME, referencedTableSchema = SCHEMA_NAME(RTB.SCHEMA_ID), referencedTableName = RTB.NAME, referencedColumnName = RCOL.NAME FROM sys.foreign_key_columns FKC INNER JOIN sys.objects OBJ ON OBJ.OBJECT_ID = FKC.CONSTRAINT_OBJECT_ID INNER JOIN sys.tables TB ON TB.OBJECT_ID = FKC.PARENT_OBJECT_ID INNER JOIN sys.columns COL ON COL.COLUMN_ID = PARENT_COLUMN_ID AND COL.OBJECT_ID = TB.OBJECT_ID INNER JOIN sys.tables RTB ON RTB.OBJECT_ID = FKC.REFERENCED_OBJECT_ID INNER JOIN sys.columns RCOL ON RCOL.COLUMN_ID = REFERENCED_COLUMN_ID AND RCOL.OBJECT_ID = RTB.OBJECT_ID WHERE TB.NAME =\'myTable\'',
Expand Down
12 changes: 0 additions & 12 deletions packages/core/test/unit/dialects/sqlite/query-generator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const chai = require('chai');

const expect = chai.expect;
const Support = require('../../../support');
const { Op } = require('@sequelize/core');

const dialect = Support.getTestDialect();
const _ = require('lodash');
Expand Down Expand Up @@ -364,17 +363,6 @@ if (dialect === 'sqlite') {
+ 'DROP TABLE `myTable_backup`;',
},
],
removeColumnQuery: [
{
title: 'Properly quotes column names',
arguments: ['myTable', { commit: 'VARCHAR(255)', bar: 'VARCHAR(255)' }],
expectation:
'CREATE TABLE IF NOT EXISTS `myTable_backup` (`commit` VARCHAR(255), `bar` VARCHAR(255));'
+ 'INSERT INTO `myTable_backup` SELECT `commit`, `bar` FROM `myTable`;'
+ 'DROP TABLE `myTable`;'
+ 'ALTER TABLE `myTable_backup` RENAME TO `myTable`;',
},
],
getForeignKeysQuery: [
{
title: 'Property quotes table names',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ describe('QueryGenerator#describeTableQuery', () => {
});

it('produces a query to describe a table from a model', () => {
const MyModel = sequelize.define('myModel', {});
const MyModel = sequelize.define('MyModel', {});

expectsql(() => queryGenerator.describeTableQuery(MyModel), {
default: 'SHOW FULL COLUMNS FROM [myModels];',
default: 'SHOW FULL COLUMNS FROM [MyModels];',
postgres: `SELECT
pk.constraint_type as "Constraint",
c.column_name as "Field",
Expand All @@ -104,7 +104,7 @@ describe('QueryGenerator#describeTableQuery', () => {
ON pk.table_schema=c.table_schema
AND pk.table_name=c.table_name
AND pk.column_name=c.column_name
WHERE c.table_name = 'myModels' AND c.table_schema = 'public'`,
WHERE c.table_name = 'MyModels' AND c.table_schema = 'public'`,
mssql: `SELECT
c.COLUMN_NAME AS 'Name',
c.DATA_TYPE AS 'Type',
Expand Down Expand Up @@ -133,14 +133,14 @@ describe('QueryGenerator#describeTableQuery', () => {
LEFT JOIN sys.extended_properties prop ON prop.major_id = sc.object_id
AND prop.minor_id = sc.column_id
AND prop.name = 'MS_Description'
WHERE t.TABLE_NAME = N'myModels' AND t.TABLE_SCHEMA = N'dbo'`,
sqlite: 'PRAGMA TABLE_INFO(`myModels`);',
WHERE t.TABLE_NAME = N'MyModels' AND t.TABLE_SCHEMA = N'dbo'`,
sqlite: 'PRAGMA TABLE_INFO(`MyModels`);',
db2: `SELECT NAME AS "Name", TBNAME AS "Table", TBCREATOR AS "Schema",
TRIM(COLTYPE) AS "Type", LENGTH AS "Length", SCALE AS "Scale",
NULLS AS "IsNull", DEFAULT AS "Default", COLNO AS "Colno",
IDENTITY AS "IsIdentity", KEYSEQ AS "KeySeq", REMARKS AS "Comment"
FROM SYSIBM.SYSCOLUMNS
WHERE TBNAME = 'myModels' AND TBCREATOR = USER;`,
WHERE TBNAME = 'MyModels' AND TBCREATOR = USER;`,
ibmi: `SELECT
QSYS2.SYSCOLUMNS.*,
QSYS2.SYSCST.CONSTRAINT_NAME,
Expand All @@ -153,7 +153,7 @@ describe('QueryGenerator#describeTableQuery', () => {
LEFT JOIN QSYS2.SYSCST
ON QSYS2.SYSCSTCOL.CONSTRAINT_NAME = QSYS2.SYSCST.CONSTRAINT_NAME
WHERE QSYS2.SYSCOLUMNS.TABLE_SCHEMA = CURRENT SCHEMA
AND QSYS2.SYSCOLUMNS.TABLE_NAME = 'myModels'`,
AND QSYS2.SYSCOLUMNS.TABLE_NAME = 'MyModels'`,
});
});

Expand Down Expand Up @@ -382,7 +382,7 @@ describe('QueryGenerator#describeTableQuery', () => {
});
});

it('produces a query to describe a table with schema and custom schemaDelimiter argument', () => {
it('produces a query to describe a table with schema and custom delimiter argument', () => {
// This test is only relevant for dialects that do not support schemas
if (dialect.supports.schemas) {
return;
Expand Down
31 changes: 22 additions & 9 deletions packages/core/test/unit/query-generator/drop-table-query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,45 @@ const dialect = sequelize.dialect;
describe('QueryGenerator#dropTableQuery', () => {
const queryGenerator = sequelize.getQueryInterface().queryGenerator;

it('produces a DROP TABLE query', () => {
it('produces a query that drops a table', () => {
expectsql(() => queryGenerator.dropTableQuery('myTable'), {
default: `DROP TABLE IF EXISTS [myTable];`,
mssql: `IF OBJECT_ID('[myTable]', 'U') IS NOT NULL DROP TABLE [myTable];`,
});
});

it('produces a DROP TABLE query with cascade', () => {
it('produces a query that drops a table with cascade', () => {
expectsql(() => queryGenerator.dropTableQuery('myTable', { cascade: true }), {
default: buildInvalidOptionReceivedError('dropTableQuery', dialectName, ['cascade']),
postgres: `DROP TABLE IF EXISTS "myTable" CASCADE;`,
});
});

it('produces a DROP TABLE query with schema', () => {
it('produces a query that drops a table from a model', () => {
const MyModel = sequelize.define('MyModel', {});

expectsql(() => queryGenerator.dropTableQuery(MyModel), {
default: `DROP TABLE IF EXISTS [MyModels];`,
mssql: `IF OBJECT_ID('[MyModels]', 'U') IS NOT NULL DROP TABLE [MyModels];`,
});
});

it('produces a query that drops a table with schema', () => {
expectsql(() => queryGenerator.dropTableQuery({ tableName: 'myTable', schema: 'mySchema' }), {
default: `DROP TABLE IF EXISTS [mySchema].[myTable];`,
mssql: `IF OBJECT_ID('[mySchema].[myTable]', 'U') IS NOT NULL DROP TABLE [mySchema].[myTable];`,
sqlite: 'DROP TABLE IF EXISTS `mySchema.myTable`;',
});
});

it('produces a DROP TABLE query with default schema', () => {
it('produces a query that drops a table with default schema', () => {
expectsql(() => queryGenerator.dropTableQuery({ tableName: 'myTable', schema: dialect.getDefaultSchema() }), {
default: `DROP TABLE IF EXISTS [myTable];`,
mssql: `IF OBJECT_ID('[myTable]', 'U') IS NOT NULL DROP TABLE [myTable];`,
});
});

it('produces a DROP TABLE query from a table and globally set schema', () => {
it('produces a query that drops a table from a table and globally set schema', () => {
const sequelizeSchema = createSequelizeInstance({ schema: 'mySchema' });
const queryGeneratorSchema = sequelizeSchema.getQueryInterface().queryGenerator;

Expand All @@ -47,10 +56,14 @@ describe('QueryGenerator#dropTableQuery', () => {
});
});

it('produces a DROP TABLE query with schema and cascade', () => {
expectsql(() => queryGenerator.dropTableQuery({ tableName: 'myTable', schema: 'mySchema' }, { cascade: true }), {
default: buildInvalidOptionReceivedError('dropTableQuery', dialectName, ['cascade']),
postgres: `DROP TABLE IF EXISTS "mySchema"."myTable" CASCADE;`,
it('produces a query that drops a table with schema and custom delimiter argument', () => {
// This test is only relevant for dialects that do not support schemas
if (dialect.supports.schemas) {
return;
}

expectsql(() => queryGenerator.dropTableQuery({ tableName: 'myTable', schema: 'mySchema', delimiter: 'custom' }), {
sqlite: 'DROP TABLE IF EXISTS `mySchemacustommyTable`;',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ describe('QueryGenerator#listSchemasQuery', () => {

it('produces a query used to list schemas in supported dialects', () => {
expectsql(() => queryGenerator.listSchemasQuery(), {
default: 'DROP SCHEMA IF EXISTS [myDatabase];',
mariadb: `SELECT SCHEMA_NAME as schema_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('MYSQL', 'INFORMATION_SCHEMA', 'PERFORMANCE_SCHEMA', 'mysql', 'information_schema', 'performance_schema');`,
mysql: `SELECT SCHEMA_NAME as schema_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('MYSQL', 'INFORMATION_SCHEMA', 'PERFORMANCE_SCHEMA', 'SYS', 'mysql', 'information_schema', 'performance_schema', 'sys');`,
mssql: `SELECT "name" as "schema_name" FROM sys.schemas as s WHERE "s"."name" NOT IN (N'INFORMATION_SCHEMA', N'dbo', N'guest', N'sys', N'archive') AND "s"."name" NOT LIKE 'db_%'`,
Expand Down

0 comments on commit 8928c6d

Please sign in to comment.