Skip to content

Commit

Permalink
auto|off|config.
Browse files Browse the repository at this point in the history
  • Loading branch information
igalklebanov committed Sep 14, 2024
1 parent 2a246c5 commit 4bd7345
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 41 deletions.
106 changes: 72 additions & 34 deletions src/commands/seed/make.mts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { join } from 'pathe'
import { CommonArgs } from '../../arguments/common.mjs'
import { ExtensionArg, assertExtension } from '../../arguments/extension.mjs'
import { getConfigOrFail } from '../../config/get-config.mjs'
import type { HasCWD } from '../../config/get-cwd.mjs'
import type {
DatabaseInterface,
DatabaseInterfaceConfig,
} from '../../config/kysely-ctl-config.mjs'
import { createSubcommand } from '../../utils/create-subcommand.mjs'
import {
getKyselyCodegenInstalledVersion,
getPrismaKyselyInstalledVersion,
} from '../../utils/version.mjs'
import { getKyselyCodegenInstalledVersion } from '../../utils/version.mjs'

const args = {
...CommonArgs,
Expand Down Expand Up @@ -58,50 +60,86 @@ const BaseMakeCommand = {

consola.debug('File path:', destinationFilePath)

const databaseInterfacePath =
seeds.databaseInterfacePath ||
((await getKyselyCodegenInstalledVersion(args))
? 'kysely-codegen'
: undefined)
const databaseInterfaceConfig = await resolveDatabaseInterfaceConfig(
args,
seeds.databaseInterface,
)
consola.debug('Database interface config:', databaseInterfaceConfig)

consola.debug('Database interface path:', databaseInterfacePath)
if (!databaseInterfaceConfig) {
consola.debug('using non-type-safe seed template')

if (!databaseInterfacePath) {
await copyFile(
join(__dirname, 'templates/seed-template.ts'),
destinationFilePath,
)
} else {
const templateFile = await readFile(
join(__dirname, 'templates/seed-type-safe-template.ts'),
{ encoding: 'utf8' },
)

consola.debug('templateFile', templateFile)
return printSuccess(destinationFilePath)
}

const [
databaseInterfaceFilePath,
databaseInterfaceName = databaseInterfaceFilePath ===
'kysely-codegen' || (await getPrismaKyselyInstalledVersion(args))
? 'DB'
: 'Database',
] = databaseInterfacePath.split('#')
consola.debug('using type-safe seed template')

consola.debug('Database interface file path: ', databaseInterfaceFilePath)
consola.debug('Database interface name: ', databaseInterfaceName)
const templateFile = await readFile(
join(__dirname, 'templates/seed-type-safe-template.ts'),
{ encoding: 'utf8' },
)
consola.debug('Template file:', templateFile)

const databaseInterfaceName = databaseInterfaceConfig.name || 'DB'

const populatedTemplateFile = templateFile
.replace(
/<import>/,
`import type ${
databaseInterfaceConfig.isDefaultExport
? databaseInterfaceName
: `{ ${databaseInterfaceName} }`
} from '${databaseInterfaceConfig.path}'`,
)
.replace(/<name>/, databaseInterfaceName)
consola.debug('Populated template file: ', populatedTemplateFile)

const populatedTemplateFile = templateFile
.replace(/<typename>/g, databaseInterfaceName)
.replace(/<path>/g, databaseInterfaceFilePath)
await writeFile(destinationFilePath, populatedTemplateFile)

consola.debug('Populated template file: ', populatedTemplateFile)
printSuccess(destinationFilePath)
},
} satisfies CommandDef<typeof args>

await writeFile(destinationFilePath, populatedTemplateFile)
function printSuccess(destinationFilePath: string): void {
consola.success(`Created seed file at ${destinationFilePath}`)
}

async function resolveDatabaseInterfaceConfig(
args: HasCWD,
databaseInterface: DatabaseInterface | undefined,
): Promise<DatabaseInterfaceConfig | null> {
if (databaseInterface === 'off') {
return null
}

if (typeof databaseInterface === 'object') {
return databaseInterface
}

if (await getKyselyCodegenInstalledVersion(args)) {
return {
isDefaultExport: false,
name: 'DB',
path: 'kysely-codegen',
}
}

consola.success(`Created seed file at ${destinationFilePath}`)
},
} satisfies CommandDef<typeof args>
// if (await getPrismaKyselyInstalledVersion(config)) {
// TODO: generates by default to ./prisma/generated/types.ts#DB
// but configurable at the kysely generator config level located in ./prisma/schema.prisma
// }

// if (await getKanelKyselyInstalledVersion(config)) {
// TODO: generates by default to
// }

return null
}

export const MakeCommand = createSubcommand('make', BaseMakeCommand)
export const LegacyMakeCommand = createSubcommand('seed:make', BaseMakeCommand)
45 changes: 40 additions & 5 deletions src/config/kysely-ctl-config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ type MigratorlessMigrationsConfig = MigrationsBaseConfig &
}
)

type SeederfulSeedsConfig = Pick<SeedsBaseConfig, 'getSeedPrefix'> & {
type SeederfulSeedsConfig = Pick<
SeedsBaseConfig,
'databaseInterface' | 'getSeedPrefix'
> & {
allowJS?: never
provider?: never
seeder: Seeder
Expand Down Expand Up @@ -187,12 +190,44 @@ export type MigrationsBaseConfig = Omit<MigratorProps, 'db' | 'provider'> & {

export type SeedsBaseConfig = Omit<SeederProps, 'db' | 'provider'> & {
/**
* `Database` interface relative-to-seed-folder path, e.g. `kysely-codegen`, `../path/to/database#MyDatabaseTypeName`.
* Generate type-safe seed files that rely on an existing database interface.
*
* Default is `'auto'`.
*
* When `'auto'`:
*
* Default is `kysely-codegen` if it is installed, otherwise `Kysely<any>`.
* - When `kysely-codegen` is installed, it will use `import type { DB } from 'kysely-codegen'`.
* - **SOON** When `prisma-kysely` is installed, it will try to find the right path and use `import type { DB } from 'path/to/types'`.
* - **SOON** When `kanel-kysely` is installed, it will try to find the right path and use `import type Database from 'path/to/Database'`.
* - Otherwise, it will fallback to `Kysely<any>`.
*
* If `prisma-kysely` is installed, you can leave out the `#MyDatabaseTypeName` part, it will default to `<path>#DB`.
* When `'off'`, it will fallback to `Kysely<any>`.
*
* When a config object is passed, it will use the specified database interface path and name.
*/
databaseInterfacePath?: string
databaseInterface?: 'auto' | 'off' | DatabaseInterfaceConfig
getSeedPrefix?(): string | Promise<string>
}

export type DatabaseInterface = 'auto' | 'off' | DatabaseInterfaceConfig

export interface DatabaseInterfaceConfig {
/**
* Whether the database interface is the default export.
*
* Default is `false`.
*/
isDefaultExport?: boolean

/**
* Name of the database interface.
*
* Default is `'DB'`.
*/
name?: string

/**
* Path to the database interface, relative to the seed folder.
*/
path: string
}
4 changes: 2 additions & 2 deletions src/templates/seed-type-safe-template.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { <typename> } from '<path>'
import type { Kysely } from 'kysely'
<import>

export async function seed(db: Kysely<<typename>>): Promise<void> {
export async function seed(db: Kysely<<name>>): Promise<void> {
// seed code goes here...
// note: this function is mandatory. you must implement this function.
}
6 changes: 6 additions & 0 deletions src/utils/version.mts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export async function getPrismaKyselyInstalledVersion(
return await getInstalledVersionFromConsumerPackageJSON(args, 'prisma-kysely')
}

export async function getKanelKyselyInstalledVersion(
args: HasCWD,
): Promise<string | null> {
return await getInstalledVersionFromConsumerPackageJSON(args, 'kanel-kysely')
}

async function getInstalledVersionFromConsumerPackageJSON(
args: HasCWD,
name: string,
Expand Down

0 comments on commit 4bd7345

Please sign in to comment.