Skip to content

Commit

Permalink
feat(cli): Add a --with-model arg to generate an example schema (#21195)
Browse files Browse the repository at this point in the history
Co-authored-by: Joël Galeran <Jolg42@users.noreply.github.com>
  • Loading branch information
Kayoshi-dev and Jolg42 committed Apr 26, 2024
1 parent d8c3ab1 commit 21e923a
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 17 deletions.
90 changes: 73 additions & 17 deletions packages/cli/src/Init.ts
Expand Up @@ -26,20 +26,22 @@ export const defaultSchema = (props?: {
generatorProvider?: string
previewFeatures?: string[]
output?: string
withModel?: boolean
}) => {
const {
datasourceProvider = 'postgresql',
generatorProvider = defaultGeneratorProvider,
previewFeatures = defaultPreviewFeatures,
output = defaultOutput,
withModel = false,
} = props || {}

const aboutAccelerate = `\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n`

const isProviderCompatibleWithAccelerate = datasourceProvider !== 'sqlite'

return `// This is your Prisma schema file,
let schema = `// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
${isProviderCompatibleWithAccelerate ? aboutAccelerate : ''}
generator client {
Expand All @@ -55,6 +57,40 @@ datasource db {
url = env("DATABASE_URL")
}
`

// We add a model to the schema file if the user passed the --with-model flag
if (withModel) {
const defaultAttributes = `email String @unique
name String?`

switch (datasourceProvider) {
case 'mongodb':
schema += `
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
${defaultAttributes}
}
`
break
case 'cockroachdb':
schema += `
model User {
id BigInt @id @default(sequence())
${defaultAttributes}
}
`
break
default:
schema += `
model User {
id Int @id @default(autoincrement())
${defaultAttributes}
}
`
}
}

return schema
}

export const defaultEnv = (
Expand All @@ -72,8 +108,8 @@ export const defaultEnv = (
return env
}

export const defaultPort = (provider: ConnectorType) => {
switch (provider) {
export const defaultPort = (datasourceProvider: ConnectorType) => {
switch (datasourceProvider) {
case 'mysql':
return 3306
case 'sqlserver':
Expand All @@ -89,8 +125,12 @@ export const defaultPort = (provider: ConnectorType) => {
return undefined
}

export const defaultURL = (provider: ConnectorType, port = defaultPort(provider), schema = 'public') => {
switch (provider) {
export const defaultURL = (
datasourceProvider: ConnectorType,
port = defaultPort(datasourceProvider),
schema = 'public',
) => {
switch (datasourceProvider) {
case 'postgresql':
return `postgresql://johndoe:randompassword@localhost:${port}/mydb?schema=${schema}`
case 'cockroachdb':
Expand Down Expand Up @@ -132,6 +172,7 @@ export class Init implements Command {
${bold('Usage')}
${dim('$')} prisma init [options]
${bold('Options')}
-h, --help Display this help message
Expand All @@ -141,6 +182,10 @@ export class Init implements Command {
--output Define Prisma Client generator output path to use.
--url Define a custom datasource url
${bold('Flags')}
--with-model Add example model to created schema file
${bold('Examples')}
Set up a new Prisma project with PostgreSQL (default)
Expand All @@ -160,6 +205,9 @@ export class Init implements Command {
Set up a new Prisma project and specify the url that will be used
${dim('$')} prisma init --url mysql://user:password@localhost:3306/mydb
Set up a new Prisma project with an example model
${dim('$')} prisma init --with-model
`)

// eslint-disable-next-line @typescript-eslint/require-await
Expand All @@ -172,6 +220,7 @@ export class Init implements Command {
'--generator-provider': String,
'--preview-feature': [String],
'--output': String,
'--with-model': Boolean,
})

if (isError(args) || args['--help']) {
Expand Down Expand Up @@ -219,22 +268,28 @@ export class Init implements Command {
process.exit(1)
}

const { provider, url } = await match(args)
const { datasourceProvider, url } = await match(args)
.with(
{
'--datasource-provider': P.when((provider): provider is string => Boolean(provider)),
'--datasource-provider': P.when((datasourceProvider): datasourceProvider is string =>
Boolean(datasourceProvider),
),
},
(input) => {
const providerLowercase = input['--datasource-provider'].toLowerCase()
if (!['postgresql', 'mysql', 'sqlserver', 'sqlite', 'mongodb', 'cockroachdb'].includes(providerLowercase)) {
const datasourceProviderLowercase = input['--datasource-provider'].toLowerCase()
if (
!['postgresql', 'mysql', 'sqlserver', 'sqlite', 'mongodb', 'cockroachdb'].includes(
datasourceProviderLowercase,
)
) {
throw new Error(
`Provider "${args['--datasource-provider']}" is invalid or not supported. Try again with "postgresql", "mysql", "sqlite", "sqlserver", "mongodb" or "cockroachdb".`,
)
}
const provider = providerLowercase as ConnectorType
const url = defaultURL(provider)
const datasourceProvider = datasourceProviderLowercase as ConnectorType
const url = defaultURL(datasourceProvider)
return Promise.resolve({
provider,
datasourceProvider,
url,
})
},
Expand All @@ -259,14 +314,14 @@ export class Init implements Command {
}
}

const provider = protocolToConnectorType(`${url.split(':')[0]}:`)
return { provider, url }
const datasourceProvider = protocolToConnectorType(`${url.split(':')[0]}:`)
return { datasourceProvider, url }
},
)
.otherwise(() => {
// Default to PostgreSQL
return Promise.resolve({
provider: 'postgresql' as ConnectorType,
datasourceProvider: 'postgresql' as ConnectorType,
url: undefined,
})
})
Expand All @@ -289,10 +344,11 @@ export class Init implements Command {
fs.writeFileSync(
path.join(prismaFolder, 'schema.prisma'),
defaultSchema({
datasourceProvider: provider,
datasourceProvider,
generatorProvider,
previewFeatures,
output,
withModel: args['--with-model'],
}),
)

Expand Down Expand Up @@ -331,7 +387,7 @@ export class Init implements Command {

const steps: string[] = []

if (provider === 'mongodb') {
if (datasourceProvider === 'mongodb') {
steps.push(`Define models in the schema.prisma file.`)
} else {
steps.push(
Expand Down
30 changes: 30 additions & 0 deletions packages/cli/src/__tests__/commands/Init.test.ts
Expand Up @@ -231,6 +231,36 @@ test('errors with invalid provider param', async () => {
await expect(result).rejects.toThrow()
})

test('works with --with-model param postgresql', async () => {
ctx.fixture('init')
const result = await ctx.cli('init', '--with-model')
expect(stripAnsi(result.stdout)).toMatchSnapshot()

const schema = fs.readFileSync(join(ctx.tmpDir, 'prisma', 'schema.prisma'), 'utf-8')
expect(schema).toMatch(defaultSchema({ withModel: true, datasourceProvider: 'postgresql' }))
expect(schema).toMatchSnapshot()
})

test('works with --with-model param mongodb', async () => {
ctx.fixture('init')
const result = await ctx.cli('init', '--with-model', '--datasource-provider', 'MongoDB')
expect(stripAnsi(result.stdout)).toMatchSnapshot()

const schema = fs.readFileSync(join(ctx.tmpDir, 'prisma', 'schema.prisma'), 'utf-8')
expect(schema).toMatch(defaultSchema({ withModel: true, datasourceProvider: 'mongodb' }))
expect(schema).toMatchSnapshot()
})

test('works with --with-model param cockroachdb', async () => {
ctx.fixture('init')
const result = await ctx.cli('init', '--with-model', '--datasource-provider', 'CockroachDB')
expect(stripAnsi(result.stdout)).toMatchSnapshot()

const schema = fs.readFileSync(join(ctx.tmpDir, 'prisma', 'schema.prisma'), 'utf-8')
expect(schema).toMatch(defaultSchema({ withModel: true, datasourceProvider: 'cockroachdb' }))
expect(schema).toMatchSnapshot()
})

test('works with generator param - `go run github.com/steebchen/prisma-client-go`', async () => {
ctx.fixture('init')
const result = await ctx.cli('init', '--generator-provider', 'go run github.com/steebchen/prisma-client-go')
Expand Down
136 changes: 136 additions & 0 deletions packages/cli/src/__tests__/commands/__snapshots__/Init.test.ts.snap
Expand Up @@ -135,6 +135,142 @@ datasource db {
"
`;

exports[`works with --with-model param cockroachdb 1`] = `
"
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Run prisma db pull to turn your database schema into a Prisma schema.
3. Run prisma generate to generate the Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
┌────────────────────────────────────────────────────────────────┐
│ Developing real-time features? │
│ Prisma Pulse lets you respond instantly to database changes. │
│ https://pris.ly/cli/pulse │
└────────────────────────────────────────────────────────────────┘
"
`;

exports[`works with --with-model param cockroachdb 2`] = `
"// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "cockroachdb"
url = env("DATABASE_URL")
}
model User {
id BigInt @id @default(sequence())
email String @unique
name String?
}
"
`;
exports[`works with --with-model param mongodb 1`] = `
"
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Define models in the schema.prisma file.
3. Run prisma generate to generate the Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
┌────────────────────────────────────────────────────────────────┐
│ Developing real-time features? │
│ Prisma Pulse lets you respond instantly to database changes. │
│ https://pris.ly/cli/pulse │
└────────────────────────────────────────────────────────────────┘
"
`;
exports[`works with --with-model param mongodb 2`] = `
"// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
}
"
`;
exports[`works with --with-model param postgresql 1`] = `
"
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
┌────────────────────────────────────────────────────────────────┐
│ Developing real-time features? │
│ Prisma Pulse lets you respond instantly to database changes. │
│ https://pris.ly/cli/pulse │
└────────────────────────────────────────────────────────────────┘
"
`;
exports[`works with --with-model param postgresql 2`] = `
"// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
"
`;
exports[`works with custom output 1`] = `
"
✔ Your Prisma schema was created at prisma/schema.prisma
Expand Down

0 comments on commit 21e923a

Please sign in to comment.