Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions drizzle-kit/src/cli/commands/up-mssql.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import chalk from 'chalk';
import { writeFileSync } from 'fs';
import { upToV2 } from 'src/dialects/mssql/versions';
import { upToV4 } from 'src/dialects/mssql/versions';
import { prepareOutFolder, validateWithReport } from '../../utils/utils-node';

export const upMssqlHandler = (out: string) => {
Expand All @@ -15,7 +15,7 @@ export const upMssqlHandler = (out: string) => {
.forEach((it) => {
const path = it.path;

const { snapshot } = upToV2(it.raw);
const { snapshot } = upToV4(it.raw);

console.log(`[${chalk.green('✓')}] ${path}`);

Expand Down
79 changes: 70 additions & 9 deletions drizzle-kit/src/dialects/mssql/convertor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,25 +215,79 @@ const recreateIdentityColumn = convertor('recreate_identity_column', (st) => {
});

const createIndex = convertor('create_index', (st) => {
const { name, table, columns, isUnique, where, schema } = st.index;
const indexPart = isUnique ? 'UNIQUE INDEX' : 'INDEX';
const { name, table, columns, include, isUnique, where, schema, clustered, with: withConfig, fulltext } = st.index;
const key = schema !== 'dbo' ? `[${schema}].[${table}]` : `[${table}]`;
const columnList = columns.map((it) => {
const column = it.isExpression ? it.value : `[${it.value}]`;
return it.asc === false ? `${column} DESC` : column;
}).join(',');

if (st.index.kind === 'fulltext') {
if (!fulltext?.keyIndex) {
throw new Error(`Full-text index "${name}" is missing a key index`);
}

const withOptions = [
fulltext.changeTracking ? `CHANGE_TRACKING = ${fulltext.changeTracking.toUpperCase()}` : undefined,
fulltext.stoplist
? `STOPLIST = ${
fulltext.stoplist === 'system' || fulltext.stoplist === 'off'
? fulltext.stoplist.toUpperCase()
: `[${fulltext.stoplist}]`
}`
: undefined,
].filter((it) => it !== undefined);
const withClause = withOptions.length > 0 ? ` WITH (${withOptions.join(', ')})` : '';
const catalogClause = fulltext.catalog ? ` ON [${fulltext.catalog}]` : '';

return `CREATE FULLTEXT INDEX ON ${key} (${columnList}) KEY INDEX [${fulltext.keyIndex}]${catalogClause}${withClause};`;
}

const uniqueString = `${
columns.map((it) => {
return it.isExpression ? it.value : `[${it.value}]`;
})
}`;
if (st.index.kind === 'columnstore') {
const withOptions = [
withConfig?.online === null || withConfig?.online === undefined
? undefined
: `ONLINE = ${withConfig.online ? 'ON' : 'OFF'}`,
].filter((it) => it !== undefined);
const withClause = withOptions.length > 0 ? ` WITH (${withOptions.join(', ')})` : '';
const indexPart = `${clustered === true ? 'CLUSTERED ' : 'NONCLUSTERED '}COLUMNSTORE INDEX`;
const columnsClause = clustered === true
? columnList ? ` ORDER (${columnList})` : ''
: ` (${columnList})`;

return `CREATE ${indexPart} [${name}] ON ${key}${columnsClause}${where ? ` WHERE ${where}` : ''}${withClause};`;
}

const indexPart = `${isUnique ? 'UNIQUE ' : ''}${
clustered === true ? 'CLUSTERED ' : clustered === false ? 'NONCLUSTERED ' : ''
}INDEX`;

const includeClause = include.length > 0
? ` INCLUDE (${include.map((it) => it.isExpression ? it.value : `[${it.value}]`).join(',')})`
: '';

const whereClause = where ? ` WHERE ${where}` : '';
const withOptions = [
withConfig?.fillFactor === null || withConfig?.fillFactor === undefined
? undefined
: `FILLFACTOR = ${withConfig.fillFactor}`,
withConfig?.online === null || withConfig?.online === undefined
? undefined
: `ONLINE = ${withConfig.online ? 'ON' : 'OFF'}`,
].filter((it) => it !== undefined);
const withClause = withOptions.length > 0 ? ` WITH (${withOptions.join(', ')})` : '';

const key = schema !== 'dbo' ? `[${schema}].[${table}]` : `[${table}]`;
return `CREATE ${indexPart} [${name}] ON ${key} (${uniqueString})${whereClause};`;
return `CREATE ${indexPart} [${name}] ON ${key} (${columnList})${includeClause}${whereClause}${withClause};`;
});

const dropIndex = convertor('drop_index', (st) => {
const { schema, name, table } = st.index;

const key = schema !== 'dbo' ? `[${schema}].[${table}]` : `[${table}]`;
if (st.index.kind === 'fulltext') {
return `DROP FULLTEXT INDEX ON ${key};`;
}

return `DROP INDEX [${name}] ON ${key};`;
});

Expand Down Expand Up @@ -295,6 +349,13 @@ const renameIndex = convertor('rename_index', (st) => {
const { name: nameFrom, schema: schemaFrom, table: tableFrom } = st.from;
const { name: nameTo } = st.to;

if (st.from.kind === 'fulltext' || st.to.kind === 'fulltext') {
return [
dropIndex.convert({ index: st.from }) as string,
createIndex.convert({ index: st.to }) as string,
];
}

const key = schemaFrom !== 'dbo' ? `${schemaFrom}.${tableFrom}.${nameFrom}` : `${tableFrom}.${nameFrom}`;
return `EXEC sp_rename '${key}', [${nameTo}], 'INDEX';`;
});
Expand Down
187 changes: 186 additions & 1 deletion drizzle-kit/src/dialects/mssql/ddl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,173 @@ export const createDDLV1 = () => {
table: 'required',
columns: 'string[]', // does not supported indexing expressions
isUnique: 'boolean',
clustered: 'boolean?',
where: 'string?',
},
uniques: {
schema: 'required',
table: 'required',
nameExplicit: 'boolean',
columns: 'string[]',
},
checks: {
schema: 'required',
table: 'required',
value: 'string',
},
defaults: {
schema: 'required',
table: 'required',
column: 'string',
// this field will be required for name preserving
nameExplicit: 'boolean',
default: 'string?',
},
views: {
schema: 'required',
definition: 'string',
encryption: 'boolean?',
schemaBinding: 'boolean?',
viewMetadata: 'boolean?',
checkOption: 'boolean?',
},
});
};

export const createDDLV2 = () => {
return create({
schemas: {},
tables: { schema: 'required' },
columns: {
schema: 'required',
table: 'required',
type: 'string',
notNull: 'boolean',
generated: {
type: ['persisted', 'virtual'],
as: 'string',
},
identity: {
increment: 'number',
seed: 'number',
},
},
pks: {
schema: 'required',
table: 'required',
nameExplicit: 'boolean',
columns: 'string[]',
},
fks: {
schema: 'required',
table: 'required',
columns: 'string[]',
nameExplicit: 'boolean',
schemaTo: 'string',
tableTo: 'string',
columnsTo: 'string[]',
onUpdate: ['NO ACTION', 'CASCADE', 'SET NULL', 'SET DEFAULT'],
onDelete: ['NO ACTION', 'CASCADE', 'SET NULL', 'SET DEFAULT'],
},
indexes: {
schema: 'required',
table: 'required',
columns: [
{
value: 'string',
isExpression: 'boolean',
},
],
isUnique: 'boolean',
clustered: 'boolean?',
where: 'string?',
},
uniques: {
schema: 'required',
table: 'required',
nameExplicit: 'boolean',
columns: 'string[]',
},
checks: {
schema: 'required',
table: 'required',
value: 'string',
},
defaults: {
schema: 'required',
table: 'required',
column: 'string',
nameExplicit: 'boolean',
default: 'string?',
},
views: {
schema: 'required',
definition: 'string',
encryption: 'boolean?',
schemaBinding: 'boolean?',
viewMetadata: 'boolean?',
checkOption: 'boolean?',
},
});
};

export const createDDLV3 = () => {
return create({
schemas: {},
tables: { schema: 'required' },
columns: {
schema: 'required',
table: 'required',
type: 'string',
notNull: 'boolean',
generated: {
type: ['persisted', 'virtual'],
as: 'string',
},
identity: {
increment: 'number',
seed: 'number',
},
},
pks: {
schema: 'required',
table: 'required',
nameExplicit: 'boolean',
columns: 'string[]',
},
fks: {
schema: 'required',
table: 'required',
columns: 'string[]',
nameExplicit: 'boolean',
schemaTo: 'string',
tableTo: 'string',
columnsTo: 'string[]',
onUpdate: ['NO ACTION', 'CASCADE', 'SET NULL', 'SET DEFAULT'],
onDelete: ['NO ACTION', 'CASCADE', 'SET NULL', 'SET DEFAULT'],
},
indexes: {
schema: 'required',
table: 'required',
columns: [
{
value: 'string',
isExpression: 'boolean',
asc: 'boolean',
},
],
include: [
{
value: 'string',
isExpression: 'boolean',
},
],
isUnique: 'boolean',
clustered: 'boolean?',
with: {
fillFactor: 'number?',
online: 'boolean?',
},
where: 'string?',
},
uniques: {
Expand Down Expand Up @@ -112,14 +279,32 @@ export const createDDL = () => {
indexes: {
schema: 'required',
table: 'required',
// TODO add asc/desc: asc and desc feature exists in mssql
kind: ['btree', 'fulltext', 'columnstore'],
columns: [
{
value: 'string',
isExpression: 'boolean',
asc: 'boolean',
},
],
include: [
{
value: 'string',
isExpression: 'boolean',
},
],
isUnique: 'boolean',
clustered: 'boolean?',
with: {
fillFactor: 'number?',
online: 'boolean?',
},
fulltext: {
keyIndex: 'string?',
catalog: 'string?',
changeTracking: ['auto', 'manual', 'off', null],
stoplist: 'string?',
},
where: 'string?',
},
uniques: {
Expand Down
Loading