utils.ts•5.86 kB
import { getCommandWithExecutor, isError, link } from '@prisma/internals'
import { bold, green } from 'kleur/colors'
import { getOptionalParameter } from './cli/parameters'
import { credentialsFile } from './credentials'
export const platformParameters = {
  global: {
    // TODO Remove this from global once we have a way for parents to strip out flags upon parsing.
    '--token': String,
    '--json': Boolean,
  },
  workspace: {
    '--token': String,
    '--workspace': String,
    '--json': Boolean,
    '-w': '--workspace',
  },
  project: {
    '--token': String,
    '--project': String,
    '-p': '--project',
  },
  environment: {
    '--token': String,
    '--environment': String,
    '-e': '--environment',
  },
  serviceToken: {
    '--token': String,
    '--serviceToken': String,
    '-s': '--serviceToken',
  },
  apikey: {
    '--token': String,
    '--apikey': String,
  },
} as const
export const ErrorPlatformUnauthorized = new Error(
  `No platform credentials found. Run ${green(getCommandWithExecutor('prisma platform auth login --early-access'))} first. Alternatively you can provide a token via the \`--token\` or \`-t\` parameters, or set the 'PRISMA_TOKEN' environment variable with a token.`, // prettier-ignore
)
export const getTokenOrThrow = async <$Args extends Record<string, unknown>>(args: $Args) => {
  const token = getOptionalParameter(args, ['--token', '-t'], 'PRISMA_TOKEN') as string
  if (token) return token
  const credentials = await credentialsFile.load()
  if (isError(credentials)) throw credentials
  if (!credentials) throw ErrorPlatformUnauthorized
  return credentials.token
}
const accelerateConnectionStringUrl = 'prisma://accelerate.prisma-data.net'
/**
 *
 * Output related utils
 *
 */
export const generateConnectionString = (apiKey: string) => {
  const url = new URL(accelerateConnectionStringUrl)
  url.searchParams.set('api_key', apiKey)
  return bold(url.href)
}
export const poll = async <F extends () => Promise<R>, R>(
  fn: F,
  until: (res: R) => boolean,
  waitMs: number,
  timeoutMs: number,
  message?: string,
) => {
  const endTime = new Date().getMilliseconds() + timeoutMs
  const wait = () =>
    new Promise((resolve) => {
      setTimeout(resolve, waitMs)
    })
  let result = await fn()
  while (!until(result)) {
    const waitTime = new Date().getMilliseconds() + waitMs
    if (waitTime > endTime) {
      throw new Error(`polling timed out after ${timeoutMs}ms`)
    }
    if (message) console.log(message)
    result = await wait().then(fn)
  }
  if (isError(result)) throw result
  return result
}
export const printPpgInitOutput = ({
  databaseUrl,
  workspaceId,
  projectId,
  environmentId,
  isExistingPrismaProject = false,
}: {
  databaseUrl: string
  workspaceId: string
  projectId: string
  environmentId: string
  isExistingPrismaProject?: boolean
}) => {
  /**
   * Happy path: fresh Prisma project, files have been created for the user
   */
  const newPrismaProjectOutput = `
We created an initial ${green('schema.prisma')} file and a ${green('.env')} file with your ${green(
    'DATABASE_URL',
  )} environment variable already set.
${bold('--- Next steps ---')}
Go to ${link('https://pris.ly/ppg-init')} for detailed instructions.
${bold('1. Define your database schema')}
Open the ${green('schema.prisma')} file and define your first models. Check the docs if you need inspiration: ${link(
    'https://pris.ly/ppg-init',
  )}.
${bold('2. Apply migrations')}
Run the following command to create and apply a migration:
${green('npx prisma migrate dev --name init')}
${bold(`3. Manage your data`)}
View and edit your data locally by running this command:
${green('npx prisma studio')}
...or online in Console:
${link(`https://console.prisma.io/${workspaceId}/${projectId}/${environmentId}/studio`)}
${bold(`4. Send queries from your app`)}
To access your database from a JavaScript/TypeScript app, you need to use Prisma ORM. Go here for step-by-step instructions: ${link(
    'https://pris.ly/ppg-init',
  )}
  `
  /**
   * Init was ran against an existing Prisma project.
   * If ./schema.prisma, prisma folder, or ./prisma/schema.prisma, or DATABASE_URL in .env exists,
   * then show DATABASE_URL to the user and do not write to file system.
   */
  const existingPrismaProjectOutput = `
We found an existing ${green('schema.prisma')} file in your current project directory.
${bold('--- Database URL ---')}
Connect Prisma ORM to your Prisma Postgres database with this URL:
${green(databaseUrl)}
${bold('--- Next steps ---')}
Go to ${link('https://pris.ly/ppg-init')} for detailed instructions.
${bold('1. Install and use the Prisma Accelerate extension')}
Prisma Postgres requires the Prisma Accelerate extension for querying. If you haven't already installed it, install it in your project:
${green('npm install @prisma/extension-accelerate')}
...and add it to your Prisma Client instance:
${green('import { withAccelerate } from "@prisma/extension-accelerate"')}
${green('const prisma = new PrismaClient().$extends(withAccelerate())')}
${bold('2. Apply migrations')}
Run the following command to create and apply a migration:
${green('npx prisma migrate dev')}
${bold(`3. Manage your data`)}
View and edit your data locally by running this command:
${green('npx prisma studio')}
...or online in Console:
${link(`https://console.prisma.io/${workspaceId}/${projectId}/${environmentId}/studio`)}
${bold(`4. Send queries from your app`)}
If you already have an existing app with Prisma ORM, you can now run it and it will send queries against your newly created Prisma Postgres instance.
${bold(`5. Learn more`)}
For more info, visit the Prisma Postgres docs: ${link('https://pris.ly/ppg-docs')}
`
  return isExistingPrismaProject // prettier-ignore
    ? existingPrismaProjectOutput
    : newPrismaProjectOutput
}