Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cli): add
seed generate
command (#17262)
Co-authored-by: Alyx <zoe@ephys.dev>
- Loading branch information
Showing
13 changed files
with
262 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.yarn | ||
/packages/cli/migrations | ||
/packages/cli/seeds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ node_modules | |
oclif.lock | ||
oclif.manifest.json | ||
/migrations | ||
/seeds |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import fs from 'node:fs/promises'; | ||
import path from 'node:path'; | ||
import { SKELETONS_FOLDER } from '../_internal/skeletons.js'; | ||
import { getCurrentYYYYMMDDHHmms, slugify } from '../_internal/utils.js'; | ||
|
||
export const SUPPORTED_SEED_FORMATS = ['sql', 'typescript', 'cjs', 'esm'] as const; | ||
export type SupportedSeedFormat = (typeof SUPPORTED_SEED_FORMATS)[number]; | ||
|
||
const FORMAT_EXTENSIONS: Record<SupportedSeedFormat, string> = { | ||
sql: 'sql', | ||
typescript: 'ts', | ||
cjs: 'cjs', | ||
esm: 'mjs', | ||
}; | ||
|
||
export interface GenerateSeedOptions { | ||
format: SupportedSeedFormat; | ||
seedName: string; | ||
seedFolder: string; | ||
} | ||
|
||
export async function generateSeed(options: GenerateSeedOptions): Promise<string> { | ||
const { format, seedName, seedFolder } = options; | ||
|
||
const seedFilename = `${getCurrentYYYYMMDDHHmms()}-${slugify(seedName)}`; | ||
const seedPath = path.join(seedFolder, seedFilename); | ||
|
||
if (format === 'sql') { | ||
await fs.mkdir(seedPath, { recursive: true }); | ||
await Promise.all([ | ||
fs.writeFile(path.join(seedPath, 'up.sql'), ''), | ||
fs.writeFile(path.join(seedPath, 'down.sql'), ''), | ||
]); | ||
|
||
return seedPath; | ||
} | ||
|
||
await fs.mkdir(seedFolder, { recursive: true }); | ||
|
||
const extension = FORMAT_EXTENSIONS[format]; | ||
const targetPath = `${seedPath}.${extension}`; | ||
const sourcePath = path.join(SKELETONS_FOLDER, `seed.${extension}`); | ||
|
||
await fs.copyFile(sourcePath, targetPath); | ||
|
||
return targetPath; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { expect, test } from '@oclif/test'; | ||
import { fileUrlToDirname } from '@sequelize/utils/node'; | ||
import fs from 'node:fs/promises'; | ||
import path from 'node:path'; | ||
import { pathToFileURL } from 'node:url'; | ||
|
||
const __dirname = fileUrlToDirname(import.meta.url); | ||
const packageRoot = path.join(__dirname, '..', '..', '..'); | ||
|
||
function oclifTest() { | ||
return test.loadConfig({ | ||
root: packageRoot, | ||
}); | ||
} | ||
|
||
describe('seed:generate', () => { | ||
oclifTest() | ||
.stdout() | ||
.command(['seed:generate', '--format=sql', '--name=test-seed', '--json']) | ||
.it('generates an SQL seed', async ctx => { | ||
const asJson = JSON.parse(ctx.stdout); | ||
|
||
expect(Object.keys(asJson)).to.deep.eq(['path']); | ||
expect(pathToFileURL(asJson.path).pathname).to.match(/seeds\/[\d\-t]{19}-test-seed/); | ||
expect(await fs.readdir(asJson.path)).to.have.members(['up.sql', 'down.sql']); | ||
}); | ||
|
||
oclifTest() | ||
.stdout() | ||
.command(['seed:generate', '--format=typescript', '--name=test-seed', '--json']) | ||
.it('generates a TypeScript seed', async ctx => { | ||
const asJson = JSON.parse(ctx.stdout); | ||
|
||
expect(Object.keys(asJson)).to.deep.eq(['path']); | ||
expect(pathToFileURL(asJson.path).pathname).to.match(/seeds\/[\d\-t]{19}-test-seed\.ts/); | ||
await fs.access(asJson.path); | ||
}); | ||
|
||
oclifTest() | ||
.stdout() | ||
.command(['seed:generate', '--format=cjs', '--name=test-seed', '--json']) | ||
.it('generates a CJS seed', async ctx => { | ||
const asJson = JSON.parse(ctx.stdout); | ||
|
||
expect(Object.keys(asJson)).to.deep.eq(['path']); | ||
expect(pathToFileURL(asJson.path).pathname).to.match(/seeds\/[\d\-t]{19}-test-seed\.cjs/); | ||
await fs.access(asJson.path); | ||
}); | ||
|
||
oclifTest() | ||
.stdout() | ||
.command(['seed:generate', '--format=esm', '--name=test-seed', '--json']) | ||
.it('generates an ESM seed', async ctx => { | ||
const asJson = JSON.parse(ctx.stdout); | ||
|
||
expect(Object.keys(asJson)).to.deep.eq(['path']); | ||
expect(pathToFileURL(asJson.path).pathname).to.match(/seeds\/[\d\-t]{19}-test-seed\.mjs/); | ||
await fs.access(asJson.path); | ||
}); | ||
|
||
oclifTest() | ||
.stdout() | ||
.command(['seed:generate', '--format=sql', '--no-interactive', '--json']) | ||
.it('supports not specifying a name', async ctx => { | ||
const asJson = JSON.parse(ctx.stdout); | ||
|
||
expect(Object.keys(asJson)).to.deep.eq(['path']); | ||
expect(pathToFileURL(asJson.path).pathname).to.match(/seeds\/[\d\-t]{19}-unnamed/); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Flags } from '@oclif/core'; | ||
import chalk from 'chalk'; | ||
import { config } from '../../_internal/config.js'; | ||
import { SequelizeCommand } from '../../_internal/sequelize-command.js'; | ||
import type { SupportedSeedFormat } from '../../api/generate-seed.js'; | ||
import { SUPPORTED_SEED_FORMATS, generateSeed } from '../../api/generate-seed.js'; | ||
|
||
export class GenerateSeed extends SequelizeCommand<(typeof GenerateSeed)['flags']> { | ||
static enableJsonFlag = true; | ||
|
||
static flags = { | ||
format: Flags.string({ | ||
options: SUPPORTED_SEED_FORMATS, | ||
summary: 'The format of the seed file to generate', | ||
required: true, | ||
}), | ||
name: Flags.string({ | ||
summary: 'A short name for the seed file', | ||
default: 'unnamed', | ||
}), | ||
}; | ||
|
||
static summary = 'Generates a new seed file'; | ||
|
||
static examples = [ | ||
`<%= config.bin %> <%= command.id %>`, | ||
`<%= config.bin %> <%= command.id %> --format=sql`, | ||
`<%= config.bin %> <%= command.id %> --name="users table test data"`, | ||
]; | ||
|
||
async run(): Promise<{ path: string }> { | ||
const { format, name: seedName } = this.flags; | ||
const { seedFolder } = config; | ||
|
||
const seedPath = await generateSeed({ | ||
format: format as SupportedSeedFormat, | ||
seedName, | ||
seedFolder, | ||
}); | ||
|
||
if (format === 'sql') { | ||
this.log(`SQL seed files generated in ${chalk.green(seedPath)}`); | ||
} else { | ||
this.log(`Seed file generated at ${chalk.green(seedPath)}`); | ||
} | ||
|
||
// JSON output | ||
return { path: seedPath }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
'use strict'; | ||
|
||
module.exports = { | ||
/** @type {import('@sequelize/cli').SeedFunction} */ | ||
async up(queryInterface, sequelize) { | ||
/** | ||
* Add seed commands here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkInsert('People', [{ | ||
* name: 'John Doe', | ||
* isBetaMember: false | ||
* }], {}); | ||
*/ | ||
}, | ||
|
||
/** @type {import('@sequelize/cli').SeedFunction} */ | ||
async down(queryInterface, sequelize) { | ||
/** | ||
* Add commands to revert seed here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkDelete('People', null, {}); | ||
*/ | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** @type {import('@sequelize/cli').SeedFunction} */ | ||
export async function up(queryInterface, sequelize) { | ||
/** | ||
* Add seed commands here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkInsert('People', [{ | ||
* name: 'John Doe', | ||
* isBetaMember: false | ||
* }], {}); | ||
*/ | ||
} | ||
|
||
/** @type {import('@sequelize/cli').SeedFunction} */ | ||
export async function down(queryInterface, sequelize) { | ||
/** | ||
* Add commands to revert seed here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkDelete('People', null, {}); | ||
*/ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { AbstractQueryInterface, Sequelize } from '@sequelize/core'; | ||
|
||
export async function up( | ||
queryInterface: AbstractQueryInterface, | ||
sequelize: Sequelize, | ||
): Promise<void> { | ||
/** | ||
* Add seed commands here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkInsert('People', [{ | ||
* name: 'John Doe', | ||
* isBetaMember: false | ||
* }], {}); | ||
*/ | ||
} | ||
|
||
export async function down( | ||
queryInterface: AbstractQueryInterface, | ||
sequelize: Sequelize, | ||
): Promise<void> { | ||
/** | ||
* Add commands to revert seed here. | ||
* | ||
* Example: | ||
* await queryInterface.bulkDelete('People', null, {}); | ||
*/ | ||
} |