Skip to content

Commit 1bf9344

Browse files
[mysql]: suggestions
1 parent 84871b1 commit 1bf9344

File tree

1 file changed

+146
-198
lines changed

1 file changed

+146
-198
lines changed

drizzle-kit/src/cli/commands/push-mysql.ts

Lines changed: 146 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -94,202 +94,150 @@ export const handle = async (
9494
}
9595
};
9696

97-
// TODO: check
98-
// export const filterStatements = (
99-
// statements: JsonStatement[],
100-
// currentSchema: TypeOf<typeof mysqlSchema>,
101-
// prevSchema: TypeOf<typeof mysqlSchema>,
102-
// ) => {
103-
// return statements.filter((statement) => {
104-
// if (statement.type === 'alter_table_alter_column_set_type') {
105-
// // Don't need to handle it on migrations step and introspection
106-
// // but for both it should be skipped
107-
// if (
108-
// statement.oldDataType.startsWith('tinyint')
109-
// && statement.newDataType.startsWith('boolean')
110-
// ) {
111-
// return false;
112-
// }
113-
114-
// if (
115-
// statement.oldDataType.startsWith('bigint unsigned')
116-
// && statement.newDataType.startsWith('serial')
117-
// ) {
118-
// return false;
119-
// }
120-
121-
// if (
122-
// statement.oldDataType.startsWith('serial')
123-
// && statement.newDataType.startsWith('bigint unsigned')
124-
// ) {
125-
// return false;
126-
// }
127-
// } else if (statement.type === 'alter_table_alter_column_set_default') {
128-
// if (
129-
// statement.newDefaultValue === false
130-
// && statement.oldDefaultValue === 0
131-
// && statement.newDataType === 'boolean'
132-
// ) {
133-
// return false;
134-
// }
135-
// if (
136-
// statement.newDefaultValue === true
137-
// && statement.oldDefaultValue === 1
138-
// && statement.newDataType === 'boolean'
139-
// ) {
140-
// return false;
141-
// }
142-
// } else if (statement.type === 'delete_unique_constraint') {
143-
// const unsquashed = MySqlSquasher.unsquashUnique(statement.data);
144-
// // only if constraint was removed from a serial column, than treat it as removed
145-
// // const serialStatement = statements.find(
146-
// // (it) => it.type === "alter_table_alter_column_set_type"
147-
// // ) as JsonAlterColumnTypeStatement;
148-
// // if (
149-
// // serialStatement?.oldDataType.startsWith("bigint unsigned") &&
150-
// // serialStatement?.newDataType.startsWith("serial") &&
151-
// // serialStatement.columnName ===
152-
// // MySqlSquasher.unsquashUnique(statement.data).columns[0]
153-
// // ) {
154-
// // return false;
155-
// // }
156-
// // Check if uniqueindex was only on this column, that is serial
157-
158-
// // if now serial and was not serial and was unique index
159-
// if (
160-
// unsquashed.columns.length === 1
161-
// && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]]
162-
// .type === 'serial'
163-
// && prevSchema.tables[statement.tableName].columns[unsquashed.columns[0]]
164-
// .type === 'serial'
165-
// && currentSchema.tables[statement.tableName].columns[unsquashed.columns[0]]
166-
// .name === unsquashed.columns[0]
167-
// ) {
168-
// return false;
169-
// }
170-
// } else if (statement.type === 'alter_table_alter_column_drop_notnull') {
171-
// // only if constraint was removed from a serial column, than treat it as removed
172-
// const serialStatement = statements.find(
173-
// (it) => it.type === 'alter_table_alter_column_set_type',
174-
// ) as JsonAlterColumnTypeStatement;
175-
// if (
176-
// serialStatement?.oldDataType.startsWith('bigint unsigned')
177-
// && serialStatement?.newDataType.startsWith('serial')
178-
// && serialStatement.columnName === statement.columnName
179-
// && serialStatement.tableName === statement.tableName
180-
// ) {
181-
// return false;
182-
// }
183-
// if (statement.newDataType === 'serial' && !statement.columnNotNull) {
184-
// return false;
185-
// }
186-
// if (statement.columnAutoIncrement) {
187-
// return false;
188-
// }
189-
// }
190-
191-
// return true;
192-
// });
193-
// };
194-
195-
export const suggestions = async (_db: DB, _statements: JsonStatement[]) => {
196-
return [] as { hint: string; statement?: string | undefined }[];
197-
198-
// TODO: update and implement
199-
200-
// Potential improvement:
201-
// ON UPDATE NOW() has an FSP (fractional seconds precision)
202-
// It cannot be added if it differs from the column TIMESTAMP FSP
203-
// Warn the user if it differs
204-
// Possibly add warn for generate command
205-
// @AlexSherman added this
206-
207-
// for (const statement of statements) {
208-
// if (statement.type === 'drop_table') {
209-
// const res = await db.query(`select 1 from \`${statement.table}\` limit 1`);
210-
// if (res.length > 0) {
211-
// hints.push(`· You're about to delete non-empty ${chalk.underline(statement.table)} table`);
212-
// }
213-
// } else if (statement.type === 'drop_column') {
214-
// const res = await db.query(
215-
// `select 1 from \`${statement.column.table}\` limit 1`,
216-
// );
217-
// if (res.length > 0) {
218-
// hints.push(
219-
// `· You're about to delete ${
220-
// chalk.underline(
221-
// statement.column.name,
222-
// )
223-
// } column in a non-empty ${statement.column.table} table with`,
224-
// );
225-
// }
226-
// } else if (statement.type === 'alter_column') {
227-
// // alter column set type
228-
// // alter column set not null
229-
// `· You're about to set not-null constraint to ${
230-
// chalk.underline(statement.columnName)
231-
// } column without default, which contains ${count} items`;
232-
// `· You're about to remove default value from ${
233-
// chalk.underline(statement.columnName)
234-
// } not-null column with ${count} items`;
235-
236-
// // if drop pk and json2 has autoincrement in table -> exit process with error
237-
// `${
238-
// withStyle.errorWarning(
239-
// `You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`,
240-
// )
241-
// }`;
242-
// `· You're about to change ${
243-
// chalk.underline(statement.tableName)
244-
// } primary key. This statements may fail and you table may left without primary key`;
245-
246-
// // if drop pk and json2 has autoincrement in table -> exit process with error
247-
// `· You have removed the primary key from a ${statement.tableName} table without removing the auto-increment property from this table. As the database error states: 'there can be only one auto column, and it must be defined as a key. Make sure to remove autoincrement from ${statement.tableName} table`;
248-
// `· You're about to add not-null ${
249-
// chalk.underline(statement.column.name)
250-
// } column without default value, which contains ${count} items`;
251-
252-
// const res = await db.query(
253-
// `select count(*) as count from \`${statement.tableName}\``,
254-
// );
255-
// const count = Number(res[0].count);
256-
// if (count > 0) {
257-
// `· You're about to change ${
258-
// chalk.underline(
259-
// statement.columnName,
260-
// )
261-
// } column type from ${
262-
// chalk.underline(
263-
// statement.oldDataType,
264-
// )
265-
// } to ${chalk.underline(statement.newDataType)} with ${count} items`;
266-
// }
267-
// } else if (statement.type === 'create_index' && statement.index.unique) {
268-
// const res = await db.query(
269-
// `select 1 from \`${statement.index.table}\` limit 1`,
270-
// );
271-
// const count = Number(res[0].count);
272-
// if (count > 0) {
273-
// console.log(
274-
// `· You're about to add ${
275-
// chalk.underline(
276-
// statement.index.name,
277-
// )
278-
// } unique constraint to the table, which contains ${count} items. If this statement fails, you will receive an error from the database. Do you want to truncate ${
279-
// chalk.underline(
280-
// statement.index.table,
281-
// )
282-
// } table?\n`,
283-
// );
284-
// const { status, data } = await render(
285-
// new Select([
286-
// 'No, add the constraint without truncating the table',
287-
// `Yes, truncate the table`,
288-
// ]),
289-
// );
290-
// }
291-
// }
292-
// }
293-
294-
// return { hints, truncates };
97+
const identifier = ({ table, column }: { table?: string; column?: string }) => {
98+
return [table, column].filter(Boolean).map((t) => `\`${t}\``).join('.');
99+
};
100+
export const suggestions = async (db: DB, jsonStatements: JsonStatement[]) => {
101+
const grouped: { hint: string; statement?: string }[] = [];
102+
103+
const filtered = jsonStatements.filter((it) => {
104+
if (it.type === 'alter_column' && it.diff.generated) return false;
105+
106+
return true;
107+
});
108+
109+
for (const statement of filtered) {
110+
if (statement.type === 'drop_table') {
111+
const res = await db.query(`select 1 from ${identifier({ table: statement.table })} limit 1`);
112+
113+
if (res.length > 0) {
114+
grouped.push({ hint: `· You're about to delete non-empty ${chalk.underline(statement.table)} table` });
115+
}
116+
continue;
117+
}
118+
119+
if (statement.type === 'drop_column') {
120+
const column = statement.column;
121+
const res = await db.query(`select 1 from ${identifier({ table: column.table })} limit 1`);
122+
if (res.length === 0) continue;
123+
124+
grouped.push({
125+
hint: `· You're about to delete non-empty ${chalk.underline(column.name)} column in ${
126+
chalk.underline(column.table)
127+
} table`,
128+
});
129+
continue;
130+
}
131+
132+
// drop pk
133+
if (statement.type === 'drop_pk') {
134+
const table = statement.pk.table;
135+
const id = identifier({ table });
136+
const res = await db.query(
137+
`select 1 from ${id} limit 1`,
138+
);
139+
140+
if (res.length === 0) continue;
141+
142+
const hint = `· You're about to drop ${
143+
chalk.underline(table)
144+
} primary key, this statements may fail and your table may loose primary key`;
145+
146+
grouped.push({ hint });
147+
continue;
148+
}
149+
150+
if (
151+
statement.type === 'add_column' && statement.column.notNull && statement.column.default === null
152+
&& !statement.column.generated
153+
) {
154+
const column = statement.column;
155+
const id = identifier({ table: column.table });
156+
const res = await db.query(`select 1 from ${id} limit 1`);
157+
158+
if (res.length === 0) continue;
159+
const hint = `· You're about to add not-null ${
160+
chalk.underline(statement.column.name)
161+
} column without default value to a non-empty ${chalk.underline(statement.column.table)} table`;
162+
163+
grouped.push({ hint });
164+
continue;
165+
}
166+
167+
if (statement.type === 'alter_column') {
168+
const tableName = identifier({ table: statement.column.table });
169+
const columnName = identifier({ column: statement.column.name });
170+
171+
// add not null without default or generated
172+
if (
173+
statement.diff.notNull && statement.diff.notNull.to && statement.column.default === null
174+
&& !statement.column.generated
175+
) {
176+
const columnRes = await db.query(`select ${columnName} from ${tableName} WHERE ${columnName} IS NULL limit 1`);
177+
178+
if (columnRes.length > 0) {
179+
const hint = `· You're about to add not-null to a non-empty ${
180+
chalk.underline(columnName)
181+
} column without default value in ${chalk.underline(statement.column.table)} table`;
182+
183+
grouped.push({ hint });
184+
}
185+
}
186+
187+
// Do not think that dropping default in not empty column could somehow break something
188+
// author: @AlexSherman
189+
190+
// if (
191+
// statement.diff.default && statement.diff.default.to === null && statement.column.notNull
192+
// && !statement.column.generated
193+
// ) {
194+
// const column = statement.column;
195+
// const tableName = identifier({ table: column.table });
196+
// const columnName = identifier({ column: column.name });
197+
// const res = await db.query(`select ${columnName} from ${tableName} WHERE ${columnName} IS NULL limit 1`);
198+
199+
// if (res.length > 0) {
200+
// const hint =
201+
// `· You're about to drop default from ${columnName} column with not null in a non-empty ${tableName} table`;
202+
203+
// grouped.push({ hint });
204+
// }
205+
// }
206+
207+
if (statement.diff.type) {
208+
const hint = `· You're about to change ${
209+
chalk.underline(
210+
columnName,
211+
)
212+
} column type in ${tableName} from ${
213+
chalk.underline(
214+
statement.diff.type.from,
215+
)
216+
} to ${chalk.underline(statement.diff.type.to)}`;
217+
218+
grouped.push({ hint });
219+
}
220+
221+
continue;
222+
}
223+
224+
if (statement.type === 'create_index') {
225+
if (!statement.index.isUnique) continue;
226+
227+
const unique = statement.index;
228+
const id = identifier({ table: unique.table });
229+
230+
const res = await db.query(`select 1 from ${id} limit 1`);
231+
if (res.length === 0) continue;
232+
233+
grouped.push({
234+
hint: `· You're about to add ${chalk.underline(unique.name)} unique index to a non-empty ${
235+
chalk.underline(unique.table)
236+
} table which may fail`,
237+
});
238+
continue;
239+
}
240+
}
241+
242+
return grouped;
295243
};

0 commit comments

Comments
 (0)