feat: refs #7562 deleteDeprecatedObjects #6

Merged
guillermo merged 7 commits from 7562-deleteDeprecatedObjects into master 2024-09-12 08:06:15 +00:00
4 changed files with 91 additions and 44 deletions
Showing only changes of commit 5ac41532d9 - Show all commits

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
.DS_Store
node_modules
db
myt.config.yml
juan marked this conversation as resolved Outdated
Outdated
Review

Porque se añaden al gitignore?

Porque se añaden al gitignore?

Porque si te lo montas para probarlo en el mismo proyecto, te puede subir sin querer los archivos

Porque si te lo montas para probarlo en el mismo proyecto, te puede subir sin querer los archivos
Outdated
Review

El proyecto debe probarse desde otro directorio, inicializado con myt init.

El proyecto debe probarse desde otro directorio, inicializado con `myt init`.

View File

@ -6,6 +6,11 @@ mockFunctions:
- mockTime
- mockUtcTime
sumViews: true
defaultDefiner: root@localhost
deprecMarkRegex: __$
deprecCommentRegex: ^@deprecated [0-9]{4}-[0-9]{2}-[0-9]{2}
deprecDateRegex: '[0-9]{4}-[0-9]{2}-[0-9]{2}'
deprecRetentionPeriod: 60 # Days
privileges:
userTable: global_priv
userWhere: >-

View File

@ -43,7 +43,7 @@ class Create extends Command {
const params = {
schema,
name,
definer: 'root@localhost'
definer: opts.defaultDefiner
};
switch (opts.type) {

View File

@ -1,6 +1,7 @@
const Myt = require('./myt');
const Command = require('./lib/command');
const fs = require('fs-extra');
const SqlString = require('sqlstring');
/**
* Creates a new version.
@ -18,7 +19,7 @@ class Version extends Command {
static opts = {
alias: {
name: 'n',
guillermo marked this conversation as resolved
Review

Los alias solo tienen que tener una letra y hacer referencia a una palabra inglesa, ej: -p

Los alias solo tienen que tener una letra y hacer referencia a una palabra inglesa, ej: `-p`
deprecate: 'kk'
deprecate: 'p'
},
string: [
'name'
@ -128,11 +129,14 @@ class Version extends Command {
);
await fs.mkdir(newVersionDir);
if (opts.deprecate) {
this.emit('deprecate');
await deprecate(conn, opts, newVersionDir);
}
else
guillermo marked this conversation as resolved
Review

else y } deben estar en la misma linea: } else

`else` y `}` deben estar en la misma linea: `} else`
await fs.writeFile(
`${newVersionDir}/00-firstScript.sql`,
opts.deprecate
? (this.emit('deprecate'), await deprecate(conn))
: '-- Place your SQL code here\n'
'-- Place your SQL code here\n'
);
this.emit('versionCreated', versionFolder);
@ -147,67 +151,103 @@ class Version extends Command {
}
}
async function deprecate(conn) {
const [[config]] = await conn.query(`
SELECT dateRegex,
deprecatedMarkRegex,
VN_CURDATE() - INTERVAL daysKeepDeprecatedObjects DAY dated
FROM config
`);
async function deprecate(conn, opts, newVersionDir) {
const now = new Date();
const minDeprecDate = new Date(now.getTime() - opts.deprecRetentionPeriod * 24 * 60 * 60 * 1000);
guillermo marked this conversation as resolved Outdated
Outdated
Review

Usar el fichero de configuración de Myt para estos parámetros

Usar el fichero de configuración de Myt para estos parámetros
const deprecMarkRegex = opts.deprecMarkRegex;
const deprecCommentRegex = opts.deprecCommentRegex;
const deprecDateRegex = opts.deprecDateRegex;
const filePath = `${newVersionDir}/00-deprecate.sql`;
if (!config || Object.values(config).some(value => value == null || value === ''))
throw new Error('missing configuration variables');
const [sql] = await conn.query(`
WITH variables AS (
SELECT ? markRegex, ? dateRegex, ? dated
)
SELECT CONCAT('ALTER TABLE ', c.TABLE_SCHEMA, '.', c.TABLE_NAME, ' DROP PRIMARY KEY;') "sql"
// Generate the drops of the primary keys
const [primaryKeys] = await conn.query(`
SELECT c.TABLE_SCHEMA 'schema', c.TABLE_NAME 'table'
FROM information_schema.COLUMNS c
LEFT JOIN information_schema.VIEWS v ON v.TABLE_SCHEMA = c.TABLE_SCHEMA
AND v.TABLE_NAME = c.TABLE_NAME
JOIN information_schema.STATISTICS s ON s.TABLE_SCHEMA = c.TABLE_SCHEMA
AND s.TABLE_NAME = c.TABLE_NAME
AND s.COLUMN_NAME = c.COLUMN_NAME
JOIN variables var
WHERE c.COLUMN_NAME REGEXP var.markRegex COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, var.dateRegex COLLATE utf8mb4_unicode_ci) < var.dated
WHERE c.COLUMN_NAME REGEXP ? COLLATE utf8mb4_unicode_ci
AND c.COLUMN_COMMENT REGEXP ? COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, ? COLLATE utf8mb4_unicode_ci) < ?
AND v.TABLE_NAME IS NULL
AND s.INDEX_NAME = 'PRIMARY'
UNION
SELECT CONCAT('ALTER TABLE ', c.TABLE_SCHEMA, '.', c.TABLE_NAME, ' DROP FOREIGN KEY ', kcu.CONSTRAINT_NAME, ';')
`, [deprecMarkRegex, deprecCommentRegex, deprecDateRegex, minDeprecDate]);
primaryKeys.map(async row => {
await fs.appendFile(
filePath,
'ALTER TABLE ' + SqlString.escapeId(row.schema, true) + '.' +
SqlString.escapeId(row.table, true) + ' DROP PRIMARY KEY;\n'
);
});
// Generate the drops of the foreign keys
const [foreignKeys] = await conn.query(`
SELECT c.TABLE_SCHEMA 'schema', c.TABLE_NAME 'table', kcu.CONSTRAINT_NAME 'constraint'
FROM information_schema.COLUMNS c
LEFT JOIN information_schema.VIEWS v ON v.TABLE_SCHEMA = c.TABLE_SCHEMA
AND v.TABLE_NAME = c.TABLE_NAME
JOIN information_schema.KEY_COLUMN_USAGE kcu ON kcu.TABLE_SCHEMA = c.TABLE_SCHEMA
AND kcu.TABLE_NAME = c.TABLE_NAME
AND kcu.COLUMN_NAME = c.COLUMN_NAME
JOIN variables var
WHERE c.COLUMN_NAME REGEXP var.markRegex COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, var.dateRegex COLLATE utf8mb4_unicode_ci) < var.dated
WHERE c.COLUMN_NAME REGEXP ? COLLATE utf8mb4_unicode_ci
AND c.COLUMN_COMMENT REGEXP ? COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, ? COLLATE utf8mb4_unicode_ci) < ?
AND v.TABLE_NAME IS NULL
AND kcu.REFERENCED_COLUMN_NAME IS NOT NULL
UNION
SELECT CONCAT('ALTER TABLE ', c.TABLE_SCHEMA, '.', c.TABLE_NAME, ' DROP COLUMN ', c.COLUMN_NAME, ';')
`, [deprecMarkRegex, deprecCommentRegex, deprecDateRegex, minDeprecDate]);
foreignKeys.map(async row => {
await fs.appendFile(
filePath,
'ALTER TABLE ' + SqlString.escapeId(row.schema, true) + '.' +
SqlString.escapeId(row.table, true) + ' DROP FOREIGN KEY ' +
SqlString.escapeId(row.constraint, true) + ';\n'
);
guillermo marked this conversation as resolved Outdated
Outdated
Review
  • Generar el SQL con Javascript en lugar de usar CONCATs SQL
  • Escapar identificadores (nombres de esquemas, tablas, columnas...)
  • Hacer comprobación estricta del patron @deprecated YYYY-MM-DD
- Generar el SQL con Javascript en lugar de usar CONCATs SQL - Escapar identificadores (nombres de esquemas, tablas, columnas...) - Hacer comprobación **estricta** del patron `@deprecated YYYY-MM-DD`
});
// Generate the drops of the columns
const [columns] = await conn.query(`
SELECT c.TABLE_SCHEMA 'schema', c.TABLE_NAME 'table', c.COLUMN_NAME 'column'
FROM information_schema.COLUMNS c
LEFT JOIN information_schema.VIEWS v ON v.TABLE_SCHEMA = c.TABLE_SCHEMA
AND v.TABLE_NAME = c.TABLE_NAME
LEFT JOIN information_schema.KEY_COLUMN_USAGE kcu ON kcu.TABLE_SCHEMA = c.TABLE_SCHEMA
AND kcu.TABLE_NAME = c.TABLE_NAME
AND kcu.COLUMN_NAME = c.COLUMN_NAME
JOIN variables var
WHERE c.COLUMN_NAME REGEXP var.markRegex COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, var.dateRegex COLLATE utf8mb4_unicode_ci) < var.dated
WHERE c.COLUMN_NAME REGEXP ? COLLATE utf8mb4_unicode_ci
AND c.COLUMN_COMMENT REGEXP ? COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(c.COLUMN_COMMENT, ? COLLATE utf8mb4_unicode_ci) <?
AND v.TABLE_NAME IS NULL
UNION
SELECT CONCAT('DROP TABLE ', t.TABLE_SCHEMA, '.', t.TABLE_NAME, ';')
FROM information_schema.TABLES t
JOIN variables var
WHERE t.TABLE_NAME REGEXP var.markRegex COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(t.TABLE_COMMENT, var.dateRegex COLLATE utf8mb4_unicode_ci) < var.dated
`, [config.deprecatedMarkRegex, config.dateRegex, config.dated]);
`, [deprecMarkRegex, deprecCommentRegex, deprecDateRegex, minDeprecDate]);
return sql.map(row => row.sql).join('\n');
columns.map(async row => {
await fs.appendFile(
filePath,
'ALTER TABLE ' + SqlString.escapeId(row.schema, true) + '.' +
SqlString.escapeId(row.table, true) + ' DROP COLUMN ' +
SqlString.escapeId(row.column, true) + ';\n'
);
});
// Generate the drops of the tables
const [tables] = await conn.query(`
SELECT TABLE_SCHEMA 'schema', TABLE_NAME 'table'
FROM information_schema.TABLES
WHERE TABLE_NAME REGEXP ? COLLATE utf8mb4_unicode_ci
AND TABLE_COMMENT REGEXP ? COLLATE utf8mb4_unicode_ci
AND REGEXP_SUBSTR(TABLE_COMMENT, ? COLLATE utf8mb4_unicode_ci) < ?
`, [deprecMarkRegex, deprecCommentRegex, deprecDateRegex, minDeprecDate]);
tables.map(async row => {
await fs.appendFile(
filePath,
'DROP TABLE ' + SqlString.escapeId(row.schema, true) + '.' +
SqlString.escapeId(row.table, true) + ';\n'
);
});
}
function randomName() {