Skip to content

Commit

Permalink
added introspect for mysql views
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrSherman committed Sep 25, 2024
1 parent c0d0181 commit c7f100f
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 59 deletions.
2 changes: 2 additions & 0 deletions drizzle-kit/src/cli/commands/introspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { IntrospectProgress } from '../views';
import {
columnsResolver,
enumsResolver,
mySqlViewsResolver,
schemasResolver,
sequencesResolver,
tablesResolver,
Expand Down Expand Up @@ -212,6 +213,7 @@ export const introspectMysql = async (
squashMysqlScheme(schema),
tablesResolver,
columnsResolver,
mySqlViewsResolver,
dryMySql,
schema,
);
Expand Down
59 changes: 59 additions & 0 deletions drizzle-kit/src/introspect-mysql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,31 @@ export const schemaToTypeScript = (
{ mysql: [] as string[] },
);

Object.values(schema.views).forEach((it) => {
imports.mysql.push('mysqlView');

Object.values(it.columns).forEach(() => {
const columnImports = Object.values(it.columns)
.map((col) => {
let patched: string = (importsPatch[col.type] || col.type).replace('[]', '');
patched = patched === 'double precision' ? 'doublePrecision' : patched;
patched = patched.startsWith('varchar(') ? 'varchar' : patched;
patched = patched.startsWith('char(') ? 'char' : patched;
patched = patched.startsWith('numeric(') ? 'numeric' : patched;
patched = patched.startsWith('time(') ? 'time' : patched;
patched = patched.startsWith('timestamp(') ? 'timestamp' : patched;
patched = patched.startsWith('vector(') ? 'vector' : patched;
patched = patched.startsWith('geometry(') ? 'geometry' : patched;
return patched;
})
.filter((type) => {
return mysqlImportsList.has(type);
});

imports.mysql.push(...columnImports);
});
});

const tableStatements = Object.values(schema.tables).map((table) => {
const func = 'mysqlTable';
let statement = '';
Expand Down Expand Up @@ -243,6 +268,38 @@ export const schemaToTypeScript = (
return statement;
});

const viewsStatements = Object.values(schema.views).map((view) => {
const { columns, name, algorithm, definer, definition, sqlSecurity, withCheckOption } = view;
const func = 'mysqlView';
let statement = '';

if (imports.mysql.includes(withCasing(name))) {
statement = `// Table name is in conflict with ${
withCasing(
view.name,
)
} import.\n// Please change to any other name, that is not in imports list\n`;
}
statement += `export const ${withCasing(name)} = ${func}("${name}", {\n`;
statement += createTableColumns(
Object.values(columns),
[],
withCasing,
casing,
name,
schema,
);
statement += '})';

statement += algorithm ? `.algorithm("${algorithm}")` : '';
statement += definer ? `.definer("${definer}")` : '';
statement += sqlSecurity ? `.sqlSecurity("${sqlSecurity}")` : '';
statement += withCheckOption ? `.withCheckOption("${withCheckOption}")` : '';
statement += `.as(sql\`${definition?.replaceAll('`', '\\`')}\`);`;

return statement;
});

const uniqueMySqlImports = [
'mysqlTable',
'mysqlSchema',
Expand All @@ -257,6 +314,8 @@ export const schemaToTypeScript = (

let decalrations = '';
decalrations += tableStatements.join('\n\n');
decalrations += '\n';
decalrations += viewsStatements.join('\n\n');

const file = importsTs + decalrations;

Expand Down
36 changes: 18 additions & 18 deletions drizzle-kit/src/jsonDiffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,26 +296,26 @@ export function applyJsonDiff(json1, json2) {

const alteredMeta = view.meta;

return {
name: json2.views[nameWithSchema].name,
schema: json2.views[nameWithSchema].schema,
// pg
deletedWithOption: deletedWithOption,
addedWithOption: addedWithOption,
alteredWith: {
return Object.fromEntries(
Object.entries({
name: json2.views[nameWithSchema].name,
schema: json2.views[nameWithSchema].schema,
// pg
deletedWithOption: deletedWithOption,
addedWithOption: addedWithOption,
deletedWith: Object.keys(deletedWith).length ? deletedWith : undefined,
addedWith: Object.keys(addedWith).length ? addedWith : undefined,
alterWith: Object.keys(alterWith).length ? alterWith : undefined,
},
alteredSchema,
alteredExisting,
alteredTablespace,
alteredUsing,
// mysql
alteredMeta,
// common
alteredDefinition,
};
alteredWith: Object.keys(alterWith).length ? alterWith : undefined,
alteredSchema,
alteredExisting,
alteredTablespace,
alteredUsing,
// mysql
alteredMeta,
// common
alteredDefinition,
}).filter(([_, value]) => value !== undefined),
);
},
);

Expand Down
2 changes: 1 addition & 1 deletion drizzle-kit/src/jsonStatements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2672,5 +2672,5 @@ export const preparePgAlterViewAlterUsingJson = (
export const prepareMySqlAlterView = (
view: Omit<MySqlView, 'isExisting'>,
): JsonAlterMySqlViewStatement => {
return view as JsonAlterMySqlViewStatement;
return { type: 'alter_mysql_view', ...view };
};
35 changes: 34 additions & 1 deletion drizzle-kit/src/serializer/mysqlSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,39 @@ export const fromDatabase = async (
}
}

const views = await db.query(
`select * from INFORMATION_SCHEMA.VIEWS WHERE table_schema = '${inputSchema}';`,
);

const resultViews: Record<string, View> = {};

for await (const view of views) {
const viewName = view['TABLE_NAME'];
const definition = view['VIEW_DEFINITION'];

const withCheckOption = view['CHECK_OPTION'] === 'NONE' ? undefined : view['CHECK_OPTION'].toLowerCase();
const definer = view['DEFINER'].split('@').map((it: string) => `'${it}'`).join('@');
const sqlSecurity = view['SECURITY_TYPE'].toLowerCase();

const [createSqlStatement] = await db.query(`SHOW CREATE VIEW \`${viewName}\`;`);
const algorithmMatch = createSqlStatement['Create View'].match(/ALGORITHM=([^ ]+)/);
const algorithm = algorithmMatch ? algorithmMatch[1].toLowerCase() : undefined;

const columns = result[viewName].columns;
delete result[viewName];

resultViews[viewName] = {
columns: columns,
isExisting: false,
name: viewName,
definer,
algorithm,
definition,
sqlSecurity,
withCheckOption,
};
}

if (progressCallback) {
progressCallback('indexes', indexesCount, 'done');
// progressCallback("enums", 0, "fetching");
Expand All @@ -842,7 +875,7 @@ export const fromDatabase = async (
version: '5',
dialect: 'mysql',
tables: result,
views: {},
views: resultViews,
_meta: {
tables: {},
columns: {},
Expand Down
2 changes: 1 addition & 1 deletion drizzle-kit/src/serializer/pgSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ const matViewWithOption = object({
userCatalogTable: boolean().optional(),
}).strict();

export const mergedViewWithOption = viewWithOption.merge(matViewWithOption);
export const mergedViewWithOption = viewWithOption.merge(matViewWithOption).strict();

export const view = object({
name: string(),
Expand Down
72 changes: 34 additions & 38 deletions drizzle-kit/src/snapshotsDiffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,9 @@ export const alteredPgViewSchema = alteredViewCommon.merge(
schema: string(),
deletedWithOption: mergedViewWithOption.optional(),
addedWithOption: mergedViewWithOption.optional(),
alteredWith: object({
addedWith: mergedViewWithOption.optional(),
deletedWith: mergedViewWithOption.optional(),
alterWith: mergedViewWithOption.optional(),
}).strict(),
addedWith: mergedViewWithOption.optional(),
deletedWith: mergedViewWithOption.optional(),
alterWith: mergedViewWithOption.optional(),
alteredSchema: object({
__old: string(),
__new: string(),
Expand Down Expand Up @@ -1285,39 +1283,37 @@ export const applyPgSnapshotsDiff = async (
);
}

if (alteredView.alteredWith) {
if (alteredView.alteredWith.addedWith) {
alterViews.push(
preparePgAlterViewAddWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.alteredWith.addedWith,
),
);
}
if (alteredView.addedWith) {
alterViews.push(
preparePgAlterViewAddWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.addedWith,
),
);
}

if (alteredView.alteredWith.deletedWith) {
alterViews.push(
preparePgAlterViewDropWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.alteredWith.deletedWith,
),
);
}
if (alteredView.deletedWith) {
alterViews.push(
preparePgAlterViewDropWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.deletedWith,
),
);
}

if (alteredView.alteredWith.alterWith) {
alterViews.push(
preparePgAlterViewAddWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.alteredWith.alterWith,
),
);
}
if (alteredView.alterWith) {
alterViews.push(
preparePgAlterViewAddWithOptionJson(
alteredView.name,
alteredView.schema,
materialized,
alteredView.alterWith,
),
);
}

if (alteredView.alteredTablespace) {
Expand Down Expand Up @@ -1643,7 +1639,7 @@ export const applyMysqlSnapshotsDiff = async (
},
);

const diffResult = applyJsonDiff(columnsPatchedSnap1, json2);
const diffResult = applyJsonDiff(viewsPatchedSnap1, json2);

const typedResult: DiffResultMysql = diffResultSchemeMysql.parse(diffResult);

Expand Down Expand Up @@ -1931,7 +1927,7 @@ export const applyMysqlSnapshotsDiff = async (
}

if (alteredView.alteredMeta) {
const view = { ...json2['views'][alteredView.name], isExisting: undefined };
const view = { ...curFull['views'][alteredView.name], isExisting: undefined };
alterViews.push(
prepareMySqlAlterView(view),
);
Expand Down
23 changes: 23 additions & 0 deletions drizzle-kit/src/sqlgenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
JsonAlterColumnSetPrimaryKeyStatement,
JsonAlterColumnTypeStatement,
JsonAlterCompositePK,
JsonAlterMySqlViewStatement,
JsonAlterReferenceStatement,
JsonAlterSequenceStatement,
JsonAlterTableRemoveFromSchema,
Expand Down Expand Up @@ -491,6 +492,27 @@ class MySqlDropViewConvertor extends Convertor {
}
}

class MySqlAlterViewConvertor extends Convertor {
can(statement: JsonStatement, dialect: Dialect): boolean {
return statement.type === 'alter_mysql_view' && dialect === 'mysql';
}

convert(st: JsonAlterMySqlViewStatement) {
const { name, algorithm, definer, definition, sqlSecurity, withCheckOption } = st;

let statement = `ALTER `;
statement += algorithm ? `ALGORITHM = ${algorithm}\n` : '';
statement += definer ? `DEFINER = ${definer}\n` : '';
statement += sqlSecurity ? `SQL SECURITY ${sqlSecurity}\n` : '';
statement += `VIEW \`${name}\` AS ${definition}`;
statement += withCheckOption ? `\nWITH ${withCheckOption} CHECK OPTION` : '';

statement += ';';

return statement;
}
}

class PgRenameViewConvertor extends Convertor {
can(statement: JsonStatement, dialect: Dialect): boolean {
return statement.type === 'rename_view' && dialect === 'postgresql';
Expand Down Expand Up @@ -2711,6 +2733,7 @@ convertors.push(new PgAlterViewAlterUsingConvertor());
convertors.push(new MySqlCreateViewConvertor());
convertors.push(new MySqlDropViewConvertor());
convertors.push(new MySqlRenameViewConvertor());
convertors.push(new MySqlAlterViewConvertor());

convertors.push(new CreateTypeEnumConvertor());

Expand Down

0 comments on commit c7f100f

Please sign in to comment.