From f2391f23750c276a40732b199d7efe96d5bc9ba0 Mon Sep 17 00:00:00 2001 From: Alberto Schiabel Date: Mon, 25 Apr 2022 09:25:08 +0200 Subject: [PATCH] feat(db pull): add spinner in CLI when introspecting (#12897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joël Galeran --- packages/migrate/src/__tests__/DbPull.test.ts | 330 ++++++++++++------ .../__snapshots__/DbPull.test.ts.snap | 2 +- packages/migrate/src/commands/DbPull.ts | 13 +- packages/sdk/package.json | 1 + packages/sdk/src/index.ts | 3 +- packages/sdk/src/utils/jestContext.ts | 66 +++- packages/sdk/src/utils/spinner.ts | 59 ++++ pnpm-lock.yaml | 198 ++++++++++- 8 files changed, 527 insertions(+), 145 deletions(-) create mode 100644 packages/sdk/src/utils/spinner.ts diff --git a/packages/migrate/src/__tests__/DbPull.test.ts b/packages/migrate/src/__tests__/DbPull.test.ts index 8cba09795fbc..a75eccf2f5a8 100644 --- a/packages/migrate/src/__tests__/DbPull.test.ts +++ b/packages/migrate/src/__tests__/DbPull.test.ts @@ -1,4 +1,4 @@ -import { jestConsoleContext, jestContext } from '@prisma/sdk' +import { jestConsoleContext, jestContext, jestProcessContext } from '@prisma/sdk' import path from 'path' import { DbPull } from '../commands/DbPull' @@ -15,7 +15,7 @@ if (isMacOrWindowsCI) { const describeIf = (condition: boolean) => (condition ? describe : describe.skip) const testIf = (condition: boolean) => (condition ? test : test.skip) -const ctx = jestContext.new().add(jestConsoleContext()).assemble() +const ctx = jestContext.new().add(jestConsoleContext()).add(jestProcessContext()).assemble() describe('common/sqlite', () => { test('basic introspection', async () => { @@ -26,6 +26,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --force', async () => { @@ -36,6 +38,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) // TODO: Windows: fails with @@ -50,6 +54,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('basic introspection with invalid --url', async () => { @@ -60,6 +66,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should succeed when schema and db do match', async () => { @@ -70,14 +78,19 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from schema.prisma Datasource "db": SQLite database "dev.db" at "file:dev.db" - - Introspecting based on datasource defined in schema.prisma … - + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in schema.prisma + ✔ Introspected 3 models and wrote them into schema.prisma in XXXms Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) // TODO: Windows: fails with @@ -92,14 +105,19 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from schema.prisma Datasource "db": SQLite database "dev.db" at "file:dev.db" - - Introspecting … - + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting + ✔ Introspected 3 models and wrote them into schema.prisma in XXXms Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('basic introspection with invalid --url - empty host', async () => { @@ -112,6 +130,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should succeed and keep changes to valid schema and output warnings', async () => { @@ -123,9 +143,13 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/reintrospection.prisma Datasource "db": SQLite database "dev.db" at "file:dev.db" - - Introspecting based on datasource defined in prisma/reintrospection.prisma … - + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/reintrospection.prisma + ✔ Introspected 3 models and wrote them into prisma/reintrospection.prisma in XXXms *** WARNING *** @@ -136,8 +160,9 @@ describe('common/sqlite', () => { - Model "AwesomeUser" Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.fs.read('prisma/reintrospection.prisma')).toMatchInlineSnapshot(` generator client { @@ -193,14 +218,16 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // These models were enriched with \`@@map\` information taken from the previous Prisma schema. - // - Model "AwesomeNewPost" - // - Model "AwesomeProfile" - // - Model "AwesomeUser" - // - `) + // *** WARNING *** + // + // These models were enriched with \`@@map\` information taken from the previous Prisma schema. + // - Model "AwesomeNewPost" + // - Model "AwesomeProfile" + // - Model "AwesomeUser" + // + `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.fs.read('prisma/reintrospection.prisma')).toStrictEqual(originalSchema) }) @@ -213,14 +240,19 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" - - Introspecting based on datasource defined in prisma/schema.prisma … - + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/schema.prisma + ✔ Introspected 3 models and wrote them into prisma/schema.prisma in XXXms Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should fail when db is missing', async () => { @@ -228,26 +260,33 @@ describe('common/sqlite', () => { const result = DbPull.new().parse([]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - P4001 The introspected database was empty: + P4001 The introspected database was empty: - prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. + prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. - To fix this, you have two options: + To fix this, you have two options: - - manually create a table in your database. - - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). + - manually create a table in your database. + - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). - Then you can run prisma db pull again. + Then you can run prisma db pull again. - `) + `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" - - Introspecting based on datasource defined in prisma/schema.prisma … `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/schema.prisma + + ✖ Introspecting based on datasource defined in prisma/schema.prisma + + `) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should fail when db is empty', async () => { @@ -256,26 +295,33 @@ describe('common/sqlite', () => { const result = DbPull.new().parse([]) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` - P4001 The introspected database was empty: + P4001 The introspected database was empty: - prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. + prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. - To fix this, you have two options: + To fix this, you have two options: - - manually create a table in your database. - - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). + - manually create a table in your database. + - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). - Then you can run prisma db pull again. + Then you can run prisma db pull again. - `) + `) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" at "file:dev.db" - - Introspecting based on datasource defined in prisma/schema.prisma … `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/schema.prisma + + ✖ Introspecting based on datasource defined in prisma/schema.prisma + + `) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should fail when Prisma schema is missing', async () => { @@ -288,6 +334,8 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should fail when schema is invalid', async () => { @@ -306,10 +354,17 @@ describe('common/sqlite', () => { Prisma schema loaded from prisma/invalid.prisma Datasource "db": SQLite database "dev.db" at "file:dev.db" - Introspecting based on datasource defined in prisma/invalid.prisma … - `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/invalid.prisma + + ✖ Introspecting based on datasource defined in prisma/invalid.prisma + + `) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) it('should succeed when schema is invalid and using --force', async () => { @@ -322,14 +377,19 @@ describe('common/sqlite', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/invalid.prisma Datasource "db": SQLite database "dev.db" at "file:dev.db" + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Introspecting based on datasource defined in prisma/invalid.prisma … + + - Introspecting based on datasource defined in prisma/invalid.prisma ✔ Introspected 3 models and wrote them into prisma/invalid.prisma in XXXms Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.fs.read('prisma/invalid.prisma')).toMatchSnapshot() }) @@ -367,6 +427,8 @@ describe('postgresql', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('basic introspection --url', async () => { @@ -376,11 +438,13 @@ describe('postgresql', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection should load .env file with --print', async () => { ctx.fixture('schema-only-postgresql') - expect.assertions(5) + expect.assertions(7) try { await DbPull.new().parse(['--print', '--schema=./prisma/using-dotenv.prisma']) @@ -392,11 +456,13 @@ describe('postgresql', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection should load .env file without --print', async () => { ctx.fixture('schema-only-postgresql') - expect.assertions(5) + expect.assertions(7) try { await DbPull.new().parse(['--schema=./prisma/using-dotenv.prisma']) @@ -411,10 +477,17 @@ describe('postgresql', () => { Environment variables loaded from prisma/.env Datasource "my_db": PostgreSQL database "mydb", schema "public" at "fromdotenvdoesnotexist:5432" - Introspecting based on datasource defined in prisma/using-dotenv.prisma … - `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + + + - Introspecting based on datasource defined in prisma/using-dotenv.prisma + + ✖ Introspecting based on datasource defined in prisma/using-dotenv.prisma + + `) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) }) @@ -450,6 +523,8 @@ describe('mysql', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) // TODO: snapshot fails on CI for macOS and Windows because the connection @@ -462,6 +537,8 @@ describe('mysql', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) }) @@ -501,6 +578,8 @@ describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('basic introspection --url', async () => { @@ -510,6 +589,8 @@ describeIf(!process.env.TEST_SKIP_MSSQL)('SQL Server', () => { expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchSnapshot() expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) }) @@ -531,21 +612,26 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/no-model.prisma Datasource "my_db" + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Introspecting based on datasource defined in prisma/no-model.prisma … - ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/no-model.prisma in XXXms - - *** WARNING *** + - Introspecting based on datasource defined in prisma/no-model.prisma - The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - - Model "users", field: "numberOrString1", chosen data type: "Json" - - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/no-model.prisma in XXXms + + *** WARNING *** + + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + - Model "users", field: "numberOrString1", chosen data type: "Json" + - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" - Run prisma generate to generate Prisma Client. - `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + Run prisma generate to generate Prisma Client. + + `) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --force (existing models)', async () => { @@ -557,21 +643,26 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db" + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Introspecting based on datasource defined in prisma/schema.prisma … + + - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms *** WARNING *** - + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - Model "users", field: "numberOrString1", chosen data type: "Json" - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --print (no existing models)', async () => { @@ -620,14 +711,16 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - // - Model "users", field: "numberOrString1", chosen data type: "Json" - // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" - // - `) + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + // + `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --print --composite-type-depth=0 (no existing models)', async () => { @@ -661,12 +754,14 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - // - Model "users", field: "numberOrString1", chosen data type: "Json" - // - `) + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // + `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --print --composite-type-depth=1 (no existing models)', async () => { @@ -708,13 +803,15 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - // - Model "users", field: "numberOrString1", chosen data type: "Json" - // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - // - `) + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // + `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --force --composite-type-depth=-1 (existing models)', async () => { @@ -726,21 +823,26 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db" + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + - Introspecting based on datasource defined in prisma/schema.prisma … + - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms *** WARNING *** - + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - Model "users", field: "numberOrString1", chosen data type: "Json" - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection --print --composite-type-depth=-1 (no existing models)', async () => { @@ -789,14 +891,16 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` - // *** WARNING *** - // - // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - // - Model "users", field: "numberOrString1", chosen data type: "Json" - // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" - // - `) + // *** WARNING *** + // + // The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. + // - Model "users", field: "numberOrString1", chosen data type: "Json" + // - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" + // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" + // + `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) // describeIf is making eslint not happy about the names @@ -817,6 +921,8 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { // - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" // `) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) // In this case it should not error and the line `Datasource "x"` not be printed @@ -827,23 +933,28 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { await expect(result).resolves.toMatchInlineSnapshot(``) expect(ctx.mocked['console.log'].mock.calls.join('\n')).toMatchInlineSnapshot(``) expect(ctx.mocked['console.info'].mock.calls.join('\n')).not.toContain(`Datasource `) - expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Prisma schema loaded from schema.prisma + expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot( + `Prisma schema loaded from schema.prisma`, + ) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` - Introspecting … + + - Introspecting ✔ Introspected 1 model and 2 embedded documents and wrote them into schema.prisma in XXXms *** WARNING *** - + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - Model "users", field: "numberOrString1", chosen data type: "Json" - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('introspection with --force', async () => { @@ -855,21 +966,26 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { expect(ctx.mocked['console.info'].mock.calls.join('\n')).toMatchInlineSnapshot(` Prisma schema loaded from prisma/schema.prisma Datasource "my_db" + `) + expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(` + - Introspecting based on datasource defined in prisma/schema.prisma … + - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 1 model and 2 embedded documents and wrote them into prisma/schema.prisma in XXXms *** WARNING *** - + The following fields had data stored in multiple types. Either use Json or normalize data to the wanted type. - Model "users", field: "numberOrString1", chosen data type: "Json" - Type "UsersHobbies", field: "numberOrString2", chosen data type: "Json" - Type "UsersHobbiesObjects", field: "numberOrString3", chosen data type: "Json" Run prisma generate to generate Prisma Client. + `) - expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) test('re-introspection should error (not supported) (existing models)', async () => { @@ -887,5 +1003,7 @@ describeIf(process.platform !== 'win32' && !isMacOrWindowsCI)('MongoDB', () => { Datasource "my_db" `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stdout.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) + expect(ctx.mocked['process.stderr.write'].mock.calls.join('\n')).toMatchInlineSnapshot(``) }) }) diff --git a/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap b/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap index 09263efefd02..49985aef6650 100644 --- a/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap +++ b/packages/migrate/src/__tests__/__snapshots__/DbPull.test.ts.snap @@ -236,7 +236,7 @@ model AwesomeProfile { // introspectionSchemaVersion: NonPrisma, `; -exports[`common/sqlite should succeed when schema is invalid and using --force 5`] = ` +exports[`common/sqlite should succeed when schema is invalid and using --force 7`] = ` generator client { provider = "prisma-client-js" output = "../generated/client" diff --git a/packages/migrate/src/commands/DbPull.ts b/packages/migrate/src/commands/DbPull.ts index 19b9f5fe111b..8201fd02431b 100644 --- a/packages/migrate/src/commands/DbPull.ts +++ b/packages/migrate/src/commands/DbPull.ts @@ -1,6 +1,7 @@ import type { Command, IntrospectionSchemaVersion, IntrospectionWarnings } from '@prisma/sdk' import { arg, + createSpinner, drawBox, format, formatms, @@ -92,12 +93,7 @@ Set composite types introspection depth to 2 levels '--clean': Boolean, }) - const log = (...messages): void => { - if (!args['--print']) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - console.info(...messages) - } - } + const spinnerFactory = createSpinner(!args['--print']) if (args instanceof Error) { return this.help(args.message) @@ -196,7 +192,7 @@ Some information will be lost (relations, comments, mapped fields, @ignore...), !args['--url'] && schemaPath ? ` based on datasource defined in ${chalk.underline(path.relative(process.cwd(), schemaPath))}` : '' - log(`\nIntrospecting${basedOn} …`) + const introspectionSpinner = spinnerFactory(`Introspecting${basedOn}`) const before = Date.now() let introspectionSchema = '' @@ -209,6 +205,7 @@ Some information will be lost (relations, comments, mapped fields, @ignore...), introspectionWarnings = introspectionResult.warnings introspectionSchemaVersion = introspectionResult.version } catch (e: any) { + introspectionSpinner.failure() if (e.code === 'P4001') { if (introspectionSchema.trim() === '') { throw new Error(`\n${chalk.red.bold('P4001 ')}${chalk.red('The introspected database was empty:')} ${ @@ -305,7 +302,7 @@ Learn more about the upgrade process in the docs:\n${link('https://pris.ly/d/upg }) : '' - log(`\n✔ Introspected ${modelsAndTypesCountMessage} into ${chalk.underline( + introspectionSpinner.success(`Introspected ${modelsAndTypesCountMessage} into ${chalk.underline( path.relative(process.cwd(), schemaPath), )} in ${chalk.bold(formatms(Date.now() - before))}${prisma1UpgradeMessageBox} ${chalk.keyword('orange')(introspectionWarningsMessage)} diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 7d3d5e58ca9c..f6dc0302dddf 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -70,6 +70,7 @@ "new-github-issue-url": "0.2.1", "node-fetch": "2.6.7", "open": "7", + "ora": "5.4.1", "p-map": "4.0.0", "prompts": "2.4.2", "read-pkg-up": "7.0.1", diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index 0453b85ec6fd..2bafb4509e21 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -55,7 +55,7 @@ export { getEnvPaths } from './utils/getEnvPaths' export { handlePanic } from './utils/handlePanic' export { isCi } from './utils/isCi' export { isCurrentBinInstalledGlobally } from './utils/isCurrentBinInstalledGlobally' -export { jestConsoleContext, jestContext } from './utils/jestContext' +export { jestConsoleContext, jestContext, jestProcessContext } from './utils/jestContext' export { keyBy } from './utils/keyBy' export { link } from './utils/link' export { load } from './utils/load' @@ -67,6 +67,7 @@ export { parseBinaryTargetsEnvValue, parseEnvValue } from './utils/parseEnvValue export { pick } from './utils/pick' export { platformRegex } from './utils/platformRegex' export { printConfigWarnings } from './utils/printConfigWarnings' +export { createSpinner } from './utils/spinner' export type { Position } from './utils/trimBlocksFromSchema' export { trimBlocksFromSchema, trimNewLine } from './utils/trimBlocksFromSchema' export { tryLoadEnvs } from './utils/tryLoadEnvs' diff --git a/packages/sdk/src/utils/jestContext.ts b/packages/sdk/src/utils/jestContext.ts index b1174c5e487e..f8be0b72a74e 100644 --- a/packages/sdk/src/utils/jestContext.ts +++ b/packages/sdk/src/utils/jestContext.ts @@ -82,19 +82,19 @@ type ContextContributorFactory = Settings extends : (settings: Settings) => ContextContributor /** - * A function that provides additonal test context. + * A function that provides additional test context. */ -type ContextContributor = (ctx: Context) => NewContext +type ContextContributor = (ctx: Context) => Context & NewContext /** * Main context builder API that permits recursively building up context. */ + function factory(ctx: Context) { return { add(contextContributor: ContextContributor) { - contextContributor(ctx) - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - return factory(ctx as any) + const newCtx = contextContributor(ctx) + return factory(newCtx) }, assemble(): Context { return ctx @@ -105,18 +105,19 @@ function factory(ctx: Context) { /** * Test context contributor. Mocks console.error with a Jest spy before each test. */ -export const jestConsoleContext: ContextContributorFactory< - {}, - BaseContext, - { - mocked: { - 'console.error': jest.SpyInstance - 'console.log': jest.SpyInstance - 'console.info': jest.SpyInstance - 'console.warn': jest.SpyInstance - } + +type ConsoleContext = { + mocked: { + 'console.error': jest.SpyInstance + 'console.log': jest.SpyInstance + 'console.info': jest.SpyInstance + 'console.warn': jest.SpyInstance } -> = () => (ctx) => { +} + +export const jestConsoleContext: ContextContributorFactory<{}, BaseContext, ConsoleContext> = () => (c) => { + const ctx = c as BaseContext & ConsoleContext + beforeEach(() => { ctx.mocked['console.error'] = jest.spyOn(console, 'error').mockImplementation(() => {}) ctx.mocked['console.log'] = jest.spyOn(console, 'log').mockImplementation(() => {}) @@ -131,5 +132,36 @@ export const jestConsoleContext: ContextContributorFactory< ctx.mocked['console.warn'].mockRestore() }) - return null as any + return ctx +} + +/** + * Test context contributor. Mocks process.std(out|err).write with a Jest spy before each test. + */ + +type ProcessContext = { + mocked: { + 'process.stderr.write': jest.SpyInstance + 'process.stdout.write': jest.SpyInstance + } +} + +export const jestProcessContext: ContextContributorFactory<{}, BaseContext, ProcessContext> = () => (c) => { + const ctx = c as BaseContext & ProcessContext + + beforeEach(() => { + ctx.mocked['process.stderr.write'] = jest + .spyOn(process.stderr, 'write') + .mockImplementation((message: string | Uint8Array) => true) + ctx.mocked['process.stdout.write'] = jest + .spyOn(process.stdout, 'write') + .mockImplementation((message: string | Uint8Array) => true) + }) + + afterEach(() => { + ctx.mocked['process.stderr.write'].mockRestore() + ctx.mocked['process.stdout.write'].mockRestore() + }) + + return ctx } diff --git a/packages/sdk/src/utils/spinner.ts b/packages/sdk/src/utils/spinner.ts new file mode 100644 index 000000000000..db8b01c60233 --- /dev/null +++ b/packages/sdk/src/utils/spinner.ts @@ -0,0 +1,59 @@ +import type { Options as OraOptions } from 'ora' +import ora from 'ora' + +const defaultOraOptions: OraOptions = { + spinner: 'dots', + color: 'cyan', + indent: 0, + stream: process.stdout, +} + +/** + * Methods available to a spinner instance that has already started. + */ +export interface SpinnerStarted { + success(text?: string): void + failure(text?: string): void +} + +/** + * Closure that starts a spinner if `enableOutput` is true, and returns a `SpinnerStarted` instance. + * Note: the spinner will only be enabled if the stream is being run inside a TTY context (not spawned or piped) and/or not in a CI environment. + * @param enableOutput Whether to enable or disable any output. Useful e.g. for "--print" flags in commands. + * @param oraOptions Additional options to pass to `ora` for customizing the spinner. + * @returns + */ +export function createSpinner(enableOutput = true, oraOptions: Partial = {}) { + const actualOptions = { ...defaultOraOptions, ...oraOptions } + + return (text: string): SpinnerStarted => { + if (!enableOutput) { + return { + success: () => {}, + failure: () => {}, + } + } + + actualOptions.stream?.write('\n') + const spinner = ora(actualOptions) + spinner.start(text) + + return { + /** + * Stop the spinner, change it to a green ✔ and persist the current text, or text if provided. + * @param textSuccess Will persist text if provided. + */ + success: (textSuccess) => { + spinner.succeed(textSuccess) + }, + + /** + * Stop the spinner, change it to a red ✖ and persist the current text, or text if provided. + * @param textFailure Will persist text if provided. + */ + failure: (textFailure) => { + spinner.fail(textFailure) + }, + } + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4979eca3cea7..87b98aff0227 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -170,7 +170,7 @@ importers: '@prisma/migrate': link:../migrate '@prisma/sdk': link:../sdk '@prisma/studio': 0.459.0 - '@prisma/studio-server': 0.459.0_839d6f5e1e290969a8d17594ebaffe12 + '@prisma/studio-server': 0.459.0 '@swc/core': 1.2.141 '@swc/jest': 0.2.17_@swc+core@1.2.141 '@types/debug': 4.1.7 @@ -190,7 +190,7 @@ importers: get-port: 5.1.1 global-dirs: 3.0.0 is-installed-globally: 0.4.0 - jest: 27.5.1_ts-node@10.4.0 + jest: 27.5.1 jest-junit: 13.0.0 line-replace: 2.0.1 log-update: 4.0.0 @@ -610,6 +610,7 @@ importers: new-github-issue-url: 0.2.1 node-fetch: 2.6.7 open: '7' + ora: 5.4.1 p-map: 4.0.0 prompts: 2.4.2 read-pkg-up: 7.0.1 @@ -655,6 +656,7 @@ importers: new-github-issue-url: 0.2.1 node-fetch: 2.6.7 open: 7.4.2 + ora: 5.4.1 p-map: 4.0.0 prompts: 2.4.2 read-pkg-up: 7.0.1 @@ -1271,6 +1273,51 @@ packages: slash: 3.0.0 dev: true + /@jest/core/27.5.1: + resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 27.5.1 + '@jest/reporters': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/node': 17.0.23 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.8.1 + exit: 0.1.2 + graceful-fs: 4.2.9 + jest-changed-files: 27.5.1 + jest-config: 27.5.1 + jest-haste-map: 27.5.1 + jest-message-util: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-resolve-dependencies: 27.5.1 + jest-runner: 27.5.1 + jest-runtime: 27.5.1 + jest-snapshot: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + jest-watcher: 27.5.1 + micromatch: 4.0.5 + rimraf: 3.0.2 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + /@jest/core/27.5.1_ts-node@10.4.0: resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -1592,38 +1639,34 @@ packages: buffer: 6.0.3 dev: true - /@prisma/studio-pcw/0.459.0_839d6f5e1e290969a8d17594ebaffe12: + /@prisma/studio-pcw/0.459.0: resolution: {integrity: sha512-V3bvY8XXtRq4dRxtAci3+MAHee0joQU1kVmtjT2RIbFXonnOSo3jkqRMLV2OpNx96oysS5h1u3K86a/EavG2bw==} engines: {node: '>= 12'} peerDependencies: '@prisma/client': '*' '@prisma/sdk': '*' dependencies: - '@prisma/client': link:packages/client - '@prisma/sdk': link:packages/sdk debug: 4.3.3 lodash: 4.17.21 transitivePeerDependencies: - supports-color dev: true - /@prisma/studio-server/0.459.0_839d6f5e1e290969a8d17594ebaffe12: + /@prisma/studio-server/0.459.0: resolution: {integrity: sha512-oKGELhEKUdezw1tCHiVzL0dH1WBNpfCvtfghV9SENHterM7Ugb2U8AlNSoKvIiyrOiLgkTG4VYl442o1QjDBnw==} engines: {node: '>= 12'} peerDependencies: '@prisma/sdk': '*' dependencies: - '@prisma/sdk': link:packages/sdk '@prisma/studio': 0.459.0 '@prisma/studio-common': 0.459.0 - '@prisma/studio-pcw': 0.459.0_839d6f5e1e290969a8d17594ebaffe12 + '@prisma/studio-pcw': 0.459.0 checkpoint-client: 1.1.20 cors: 2.8.5 debug: 4.3.3 express: 4.17.2 untildify: 4.0.0 transitivePeerDependencies: - - '@prisma/client' - supports-color dev: true @@ -2967,6 +3010,11 @@ packages: dependencies: restore-cursor: 3.1.0 + /cli-spinners/2.6.1: + resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} + engines: {node: '>=6'} + dev: false + /cli-truncate/2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} @@ -2990,6 +3038,11 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone/1.0.4: + resolution: {integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4=} + engines: {node: '>=0.8'} + dev: false + /co/4.6.0: resolution: {integrity: sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -3259,6 +3312,12 @@ packages: engines: {node: '>=0.10.0'} dev: true + /defaults/1.0.3: + resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=} + dependencies: + clone: 1.0.4 + dev: false + /define-lazy-prop/2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -5000,6 +5059,11 @@ packages: is-path-inside: 3.0.3 dev: true + /is-interactive/1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: false + /is-negative-zero/2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -5098,7 +5162,6 @@ packages: /is-unicode-supported/0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - dev: true /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} @@ -5205,6 +5268,36 @@ packages: - supports-color dev: true + /jest-cli/27.5.1: + resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 27.5.1 + '@jest/test-result': 27.5.1 + '@jest/types': 27.5.1 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.9 + import-local: 3.1.0 + jest-config: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + prompts: 2.4.2 + yargs: 16.2.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + /jest-cli/27.5.1_ts-node@10.4.0: resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5235,6 +5328,46 @@ packages: - utf-8-validate dev: true + /jest-config/27.5.1: + resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + ts-node: '>=9.0.0' + peerDependenciesMeta: + ts-node: + optional: true + dependencies: + '@babel/core': 7.17.8 + '@jest/test-sequencer': 27.5.1 + '@jest/types': 27.5.1 + babel-jest: 27.5.1_@babel+core@7.17.8 + chalk: 4.1.2 + ci-info: 3.3.0 + deepmerge: 4.2.2 + glob: 7.2.0 + graceful-fs: 4.2.9 + jest-circus: 27.5.1 + jest-environment-jsdom: 27.5.1 + jest-environment-node: 27.5.1 + jest-get-type: 27.5.1 + jest-jasmine2: 27.5.1 + jest-regex-util: 27.5.1 + jest-resolve: 27.5.1 + jest-runner: 27.5.1 + jest-util: 27.5.1 + jest-validate: 27.5.1 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 27.5.1 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + dev: true + /jest-config/27.5.1_ts-node@10.4.0: resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5268,7 +5401,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.4.0_a16cbeb8e0fa356850b3b86d32b2cb91 + ts-node: 10.4.0_6971bcbb08a723855b7f8db1d8bb7314 transitivePeerDependencies: - bufferutil - canvas @@ -5635,6 +5768,27 @@ packages: supports-color: 8.1.1 dev: true + /jest/27.5.1: + resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 27.5.1 + import-local: 3.1.0 + jest-cli: 27.5.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + /jest/27.5.1_ts-node@10.4.0: resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -6029,7 +6183,6 @@ packages: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - dev: true /log-update/4.0.0: resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} @@ -6556,6 +6709,21 @@ packages: word-wrap: 1.2.3 dev: true + /ora/5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: false + /os-homedir/1.0.2: resolution: {integrity: sha1-/7xJiDNuDoM94MFox+8VISGqf7M=} engines: {node: '>=0.10.0'} @@ -8284,6 +8452,12 @@ packages: makeerror: 1.0.12 dev: true + /wcwidth/1.0.1: + resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=} + dependencies: + defaults: 1.0.3 + dev: false + /webidl-conversions/3.0.1: resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}