@simonbackx/simple-database 1.36.5 → 1.36.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -106,7 +106,8 @@ var Migration = class Migration {
|
|
|
106
106
|
if (file.includes(".test.")) return;
|
|
107
107
|
if (file.endsWith(".d.ts")) return;
|
|
108
108
|
if (!file.endsWith(".ts") && !file.endsWith(".js")) return;
|
|
109
|
-
|
|
109
|
+
const imported = await import(file);
|
|
110
|
+
migration = imported.default?.default ?? imported.default;
|
|
110
111
|
}
|
|
111
112
|
return migration;
|
|
112
113
|
}
|
|
@@ -105,7 +105,8 @@ var Migration = class Migration {
|
|
|
105
105
|
if (file.includes(".test.")) return;
|
|
106
106
|
if (file.endsWith(".d.ts")) return;
|
|
107
107
|
if (!file.endsWith(".ts") && !file.endsWith(".js")) return;
|
|
108
|
-
|
|
108
|
+
const imported = await import(file);
|
|
109
|
+
migration = imported.default?.default ?? imported.default;
|
|
109
110
|
}
|
|
110
111
|
return migration;
|
|
111
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Migration.mjs","names":["fs","MigrationModel"],"sources":["../../../src/classes/Migration.ts"],"sourcesContent":["import { promises as fs } from 'fs';\n\nimport { logger, StyledText } from '@simonbackx/simple-logging';\nimport { Migration as MigrationModel } from '../models/Migration.js';\nimport { Database } from './Database.js';\n\nexport async function fileExists(file: string): Promise<boolean> {\n try {\n await fs.access(file);\n return true;\n }\n catch (e) {\n return false;\n }\n}\n\nasync function getProjectRoot() {\n let path = __dirname;\n for (let index = 0; index < 5; index++) {\n if (await fileExists(path + '/migrations')) {\n return path;\n }\n path += '/..';\n }\n throw new Error('Could not find migrations root');\n}\n\ntype MigrationFunction = () => Promise<void>;\n\nasync function directoryExists(filePath: string): Promise<boolean> {\n try {\n return (await fs.stat(filePath)).isDirectory();\n }\n catch (err) {\n return false;\n }\n}\n\nexport class Migration {\n up: MigrationFunction;\n down: MigrationFunction | undefined;\n\n constructor(up: MigrationFunction, down?: MigrationFunction) {\n this.up = up;\n this.down = down;\n }\n\n /***\n * Given a folder, loop all the folders in that folder and run the migrations in the 'migrations' folder\n */\n static async runAll(folder: string): Promise<boolean> {\n const dirname = __dirname;\n\n // Get the current working directory by removing shared part of folder and dirname\n const shared = dirname.split('/').filter((part, index) => part === folder.split('/')[index]).join('/');\n const cwd = folder.replace(shared, '');\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('Running all... ').addClass('migration', 'runAll'),\n new StyledText(cwd).addClass('migration', 'folder').addStyle('dim'),\n );\n\n process.env.DB_MULTIPLE_STATEMENTS = 'true';\n\n // First check if we have migrations table\n const projectRoot = await getProjectRoot();\n const setupMigration = await this.getMigration(projectRoot + '/migrations/000000000-setup-migrations.sql');\n if (!setupMigration) {\n throw new Error('Setup migration missing');\n }\n await setupMigration.up();\n await MigrationModel.markAsExecuted('000000000-setup-migrations.sql');\n\n const parts = folder.split('/');\n const firstPart = parts.shift();\n if (firstPart === undefined) {\n throw new Error('Invalid folder path');\n }\n let folderQueue: string[] = [firstPart];\n const migrations: [string, string][] = [];\n\n for (const part of parts) {\n if (part === '*') {\n const newQueue: string[] = [];\n for (folder of folderQueue) {\n // Read all directories\n const recursiveFolders = (await fs.readdir(folder, { withFileTypes: true })).filter(dirent => dirent.isDirectory()).map(dirent => folder + '/' + dirent.name);\n newQueue.push(...recursiveFolders);\n }\n folderQueue = newQueue;\n }\n else {\n folderQueue = folderQueue.map(folder => folder + '/' + part);\n }\n }\n\n for (const p of folderQueue) {\n if (await directoryExists(p)) {\n const folderFiles = await fs.readdir(p);\n\n for (const file of folderFiles) {\n const full = p + '/' + file;\n const name = file;\n if (!(await MigrationModel.isExecuted(name))) {\n migrations.push([name, full]);\n }\n }\n }\n }\n\n // Make sure we run the migrations in order\n migrations.sort((a, b) => {\n // It is expected to return a negative value if first argument is less than second argument, zero if they're equal and a positive value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n });\n\n for (const [name, file] of migrations) {\n // Check if SQL or TypeScript\n const migration = await this.getMigration(file);\n if (!migration) {\n continue;\n }\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('Running ').addClass('migration', 'start'),\n new StyledText(name).addClass('migration', 'start', 'name'),\n );\n\n try {\n await logger.setContext({\n prefixes: [new StyledText('[Migration]').addClass('migration', 'prefix'), ' '],\n tags: ['migration'],\n }, async () => {\n await migration.up();\n await MigrationModel.markAsExecuted(name);\n });\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✓').addClass('migration', 'success', 'tag'),\n ' ',\n new StyledText('Migration ' + name + ' ran successfully').addClass('migration', 'success', 'text'),\n );\n }\n catch (e) {\n // Logger.errorWithContext({textColor: ['dim', 'red'], prefix: ' FAILED ', addSpace: true, prefixColor: ['bgRed']}, \"Migration \" + name + \" failed\", e)\n logger.error(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✗').addClass('migration', 'failed', 'tag'),\n ' ',\n new StyledText('Migration ' + name + ' failed').addClass('migration', 'failed', 'text'),\n ' ',\n new StyledText(e).addClass('migration', 'failed', 'error'),\n );\n return false;\n }\n }\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✨').addClass('migration', 'success', 'tag', 'all'),\n ' ',\n new StyledText('All migrations done').addClass('migration', 'success', 'text', 'all'),\n );\n return true;\n }\n\n static async getMigration(file: string): Promise<Migration | undefined> {\n let migration: Migration;\n if (file.endsWith('.sql')) {\n if (file.endsWith('.down.sql')) {\n // Ignore. This will contain the downgrade implementation.\n return;\n }\n const sqlStatement = await fs.readFile(file, { encoding: 'utf-8' });\n\n migration = new Migration(async () => {\n await Database.statement(sqlStatement);\n });\n }\n else {\n if (file.includes('.test.')) {\n return;\n }\n if (file.endsWith('.d.ts')) {\n return;\n }\n if (!file.endsWith('.ts') && !file.endsWith('.js')) {\n return;\n }\n\n const imported = await import(file);\n migration = imported.default;\n }\n return migration;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Migration.mjs","names":["fs","MigrationModel"],"sources":["../../../src/classes/Migration.ts"],"sourcesContent":["import { promises as fs } from 'fs';\n\nimport { logger, StyledText } from '@simonbackx/simple-logging';\nimport { Migration as MigrationModel } from '../models/Migration.js';\nimport { Database } from './Database.js';\n\nexport async function fileExists(file: string): Promise<boolean> {\n try {\n await fs.access(file);\n return true;\n }\n catch (e) {\n return false;\n }\n}\n\nasync function getProjectRoot() {\n let path = __dirname;\n for (let index = 0; index < 5; index++) {\n if (await fileExists(path + '/migrations')) {\n return path;\n }\n path += '/..';\n }\n throw new Error('Could not find migrations root');\n}\n\ntype MigrationFunction = () => Promise<void>;\n\nasync function directoryExists(filePath: string): Promise<boolean> {\n try {\n return (await fs.stat(filePath)).isDirectory();\n }\n catch (err) {\n return false;\n }\n}\n\nexport class Migration {\n up: MigrationFunction;\n down: MigrationFunction | undefined;\n\n constructor(up: MigrationFunction, down?: MigrationFunction) {\n this.up = up;\n this.down = down;\n }\n\n /***\n * Given a folder, loop all the folders in that folder and run the migrations in the 'migrations' folder\n */\n static async runAll(folder: string): Promise<boolean> {\n const dirname = __dirname;\n\n // Get the current working directory by removing shared part of folder and dirname\n const shared = dirname.split('/').filter((part, index) => part === folder.split('/')[index]).join('/');\n const cwd = folder.replace(shared, '');\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('Running all... ').addClass('migration', 'runAll'),\n new StyledText(cwd).addClass('migration', 'folder').addStyle('dim'),\n );\n\n process.env.DB_MULTIPLE_STATEMENTS = 'true';\n\n // First check if we have migrations table\n const projectRoot = await getProjectRoot();\n const setupMigration = await this.getMigration(projectRoot + '/migrations/000000000-setup-migrations.sql');\n if (!setupMigration) {\n throw new Error('Setup migration missing');\n }\n await setupMigration.up();\n await MigrationModel.markAsExecuted('000000000-setup-migrations.sql');\n\n const parts = folder.split('/');\n const firstPart = parts.shift();\n if (firstPart === undefined) {\n throw new Error('Invalid folder path');\n }\n let folderQueue: string[] = [firstPart];\n const migrations: [string, string][] = [];\n\n for (const part of parts) {\n if (part === '*') {\n const newQueue: string[] = [];\n for (folder of folderQueue) {\n // Read all directories\n const recursiveFolders = (await fs.readdir(folder, { withFileTypes: true })).filter(dirent => dirent.isDirectory()).map(dirent => folder + '/' + dirent.name);\n newQueue.push(...recursiveFolders);\n }\n folderQueue = newQueue;\n }\n else {\n folderQueue = folderQueue.map(folder => folder + '/' + part);\n }\n }\n\n for (const p of folderQueue) {\n if (await directoryExists(p)) {\n const folderFiles = await fs.readdir(p);\n\n for (const file of folderFiles) {\n const full = p + '/' + file;\n const name = file;\n if (!(await MigrationModel.isExecuted(name))) {\n migrations.push([name, full]);\n }\n }\n }\n }\n\n // Make sure we run the migrations in order\n migrations.sort((a, b) => {\n // It is expected to return a negative value if first argument is less than second argument, zero if they're equal and a positive value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n });\n\n for (const [name, file] of migrations) {\n // Check if SQL or TypeScript\n const migration = await this.getMigration(file);\n if (!migration) {\n continue;\n }\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('Running ').addClass('migration', 'start'),\n new StyledText(name).addClass('migration', 'start', 'name'),\n );\n\n try {\n await logger.setContext({\n prefixes: [new StyledText('[Migration]').addClass('migration', 'prefix'), ' '],\n tags: ['migration'],\n }, async () => {\n await migration.up();\n await MigrationModel.markAsExecuted(name);\n });\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✓').addClass('migration', 'success', 'tag'),\n ' ',\n new StyledText('Migration ' + name + ' ran successfully').addClass('migration', 'success', 'text'),\n );\n }\n catch (e) {\n // Logger.errorWithContext({textColor: ['dim', 'red'], prefix: ' FAILED ', addSpace: true, prefixColor: ['bgRed']}, \"Migration \" + name + \" failed\", e)\n logger.error(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✗').addClass('migration', 'failed', 'tag'),\n ' ',\n new StyledText('Migration ' + name + ' failed').addClass('migration', 'failed', 'text'),\n ' ',\n new StyledText(e).addClass('migration', 'failed', 'error'),\n );\n return false;\n }\n }\n\n logger.log(\n new StyledText('[Migration]').addClass('migration', 'prefix').addTag('migration'),\n ' ',\n new StyledText('✨').addClass('migration', 'success', 'tag', 'all'),\n ' ',\n new StyledText('All migrations done').addClass('migration', 'success', 'text', 'all'),\n );\n return true;\n }\n\n static async getMigration(file: string): Promise<Migration | undefined> {\n let migration: Migration;\n if (file.endsWith('.sql')) {\n if (file.endsWith('.down.sql')) {\n // Ignore. This will contain the downgrade implementation.\n return;\n }\n const sqlStatement = await fs.readFile(file, { encoding: 'utf-8' });\n\n migration = new Migration(async () => {\n await Database.statement(sqlStatement);\n });\n }\n else {\n if (file.includes('.test.')) {\n return;\n }\n if (file.endsWith('.d.ts')) {\n return;\n }\n if (!file.endsWith('.ts') && !file.endsWith('.js')) {\n return;\n }\n\n const imported = await import(file);\n migration = imported.default?.default ?? imported.default;\n }\n return migration;\n }\n}\n"],"mappings":"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"}
|