Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(client, cli): implement --data-proxy [DPGA, 1] #13561

Merged
merged 12 commits into from Jun 7, 2022
Merged
9 changes: 5 additions & 4 deletions helpers/compile/build.ts
Expand Up @@ -167,7 +167,7 @@ const watch =
const restartWatcher = createWatcher(['./src/**/*'], config)

// triggers quick rebuild on file change
const onChange = debounce(async () => {
const fastRebuild = debounce(async () => {
const timeBefore = Date.now()

// we handle possible rebuild exceptions
Expand All @@ -183,7 +183,7 @@ const watch =
}, 10)

// triggers a full rebuild on added file
const onAdd = debounce(async () => {
const fullRebuild = debounce(async () => {
void changeWatcher.close() // stop all

// only one watcher will do this task
Expand All @@ -193,8 +193,9 @@ const watch =
}
}, 10)

changeWatcher.on('change', onChange)
restartWatcher.once('add', onAdd)
changeWatcher.on('change', fastRebuild)
restartWatcher.once('add', fullRebuild)
restartWatcher.once('unlink', fullRebuild)
millsp marked this conversation as resolved.
Show resolved Hide resolved

return undefined
}
Expand Down
12 changes: 6 additions & 6 deletions helpers/compile/plugins/fill-plugin/fillPlugin.ts
Expand Up @@ -191,14 +191,14 @@ const fillPlugin = (
process: {
inject: path.join(__dirname, 'fillers', 'process.ts'),
},
global: {
define: '{}',
},
globalThis: {
define: '{}',
},

// not needed
// global: {
// define: '{}',
// },
// globalThis: {
// define: '{}',
// },
// console: { },
// __dirname: { },
// __filename: { },
Expand Down
3 changes: 3 additions & 0 deletions helpers/compile/plugins/fill-plugin/fillers/function.ts
@@ -0,0 +1,3 @@
export const fn = () => {}

fn.prototype = fn
5 changes: 4 additions & 1 deletion packages/cli/src/Doctor.ts
@@ -1,9 +1,10 @@
import type { DMMF } from '@prisma/generator-helper'
import { getSchemaPathAndPrint } from '@prisma/migrate'
import type { Command } from '@prisma/sdk'
import {
arg,
canConnectToDatabase,
checkUnsupportedDataProxy,
Command,
format,
getConfig,
getDMMF,
Expand Down Expand Up @@ -64,6 +65,8 @@ ${chalk.bold('Examples')}
return this.help(args.message)
}

await checkUnsupportedDataProxy('doctor', args, true)

if (args['--help']) {
return this.help()
}
Expand Down
10 changes: 7 additions & 3 deletions packages/cli/src/Generate.ts
Expand Up @@ -48,9 +48,10 @@ ${chalk.bold('Usage')}

${chalk.bold('Options')}

-h, --help Display this help message
--schema Custom path to your Prisma schema
--watch Watch the Prisma schema and rerun after a change
-h, --help Display this help message
--schema Custom path to your Prisma schema
--data-proxy Enable the Data Proxy in the Prisma Client
millsp marked this conversation as resolved.
Show resolved Hide resolved
--watch Watch the Prisma schema and rerun after a change

${chalk.bold('Examples')}

Expand Down Expand Up @@ -101,6 +102,7 @@ ${chalk.bold('Examples')}
'-h': '--help',
'--watch': Boolean,
'--schema': String,
'--data-proxy': Boolean,
// Only used for checkpoint information
'--postinstall': String,
'--telemetry-information': String,
Expand Down Expand Up @@ -136,6 +138,7 @@ ${chalk.bold('Examples')}
printDownloadProgress: !watchMode,
version: enginesVersion,
cliVersion: pkg.version,
dataProxy: !!args['--data-proxy'],
})

if (!generators || generators.length === 0) {
Expand Down Expand Up @@ -258,6 +261,7 @@ Please run \`${getCommandWithExecutor('prisma generate')}\` to see the errors.`)
printDownloadProgress: !watchMode,
version: enginesVersion,
cliVersion: pkg.version,
dataProxy: !!args['--data-proxy'],
})

if (!generatorsWatch || generatorsWatch.length === 0) {
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/Init.ts
@@ -1,8 +1,9 @@
import type { ConnectorType } from '@prisma/generator-helper'
import type { Command } from '@prisma/sdk'
import {
arg,
canConnectToDatabase,
checkUnsupportedDataProxy,
Command,
format,
getCommandWithExecutor,
HelpError,
Expand Down Expand Up @@ -134,6 +135,8 @@ export class Init implements Command {
return this.help()
}

await checkUnsupportedDataProxy('init', args, false)

/**
* Validation
*/
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/Studio.ts
@@ -1,7 +1,6 @@
import { enginesVersion } from '@prisma/engines'
import { getSchemaPathAndPrint } from '@prisma/migrate'
import type { Command } from '@prisma/sdk'
import { arg, format, HelpError, isError, loadEnvFile } from '@prisma/sdk'
import { arg, checkUnsupportedDataProxy, Command, format, HelpError, isError, loadEnvFile } from '@prisma/sdk'
import { StudioServer } from '@prisma/studio-server'
import chalk from 'chalk'
import getPort from 'get-port'
Expand Down Expand Up @@ -75,6 +74,8 @@ ${chalk.bold('Examples')}
return this.help(args.message)
}

await checkUnsupportedDataProxy('studio', args, true)

if (args['--help']) {
return this.help()
}
Expand Down
1 change: 1 addition & 0 deletions packages/client/edge.d.ts
@@ -0,0 +1 @@
export * from '.prisma/client'
3 changes: 3 additions & 0 deletions packages/client/edge.js
@@ -0,0 +1,3 @@
module.exports = {
...require('.prisma/client/edge'),
}
1 change: 0 additions & 1 deletion packages/client/fixtures/dataproxy/prisma/schema.prisma
Expand Up @@ -5,7 +5,6 @@ datasource db {

generator client {
provider = "prisma-client-js"
engineType = "dataproxy"
}

model Post {
Expand Down
27 changes: 18 additions & 9 deletions packages/client/helpers/build.ts
Expand Up @@ -5,14 +5,17 @@ import type { BuildOptions } from '../../../helpers/compile/build'
import { build } from '../../../helpers/compile/build'
import { fillPlugin } from '../../../helpers/compile/plugins/fill-plugin/fillPlugin'

const fillPluginPath = path.join('..', '..', 'helpers', 'compile', 'plugins', 'fill-plugin')
const functionPolyfillPath = path.join(fillPluginPath, 'fillers', 'function.ts')

// we define the config for runtime
const runtimeBuildConfig: BuildOptions = {
const nodeRuntimeBuildConfig: BuildOptions = {
name: 'runtime',
entryPoints: ['src/runtime/index.ts'],
outfile: 'runtime/index',
bundle: true,
define: {
'globalThis.NOT_PRISMA_DATA_PROXY': 'true',
NODE_CLIENT: 'true',
// that fixes an issue with lz-string umd builds
'define.amd': 'false',
},
Expand All @@ -27,22 +30,29 @@ const browserBuildConfig: BuildOptions = {
bundle: true,
}

// we define the config for proxy
const proxyBuildConfig: BuildOptions = {
name: 'proxy',
// we define the config for edge
const edgeRuntimeBuildConfig: BuildOptions = {
name: 'edge',
entryPoints: ['src/runtime/index.ts'],
outfile: 'runtime/proxy',
outfile: 'runtime/edge',
bundle: true,
minify: true,
legalComments: 'none',
define: {
// that helps us to tree-shake unused things out
'globalThis.NOT_PRISMA_DATA_PROXY': 'false',
NODE_CLIENT: 'false',
// that fixes an issue with lz-string umd builds
'define.amd': 'false',
},
plugins: [
fillPlugin({
// we remove eval and Function for vercel
eval: { define: 'undefined' },
Function: {
define: 'fn',
inject: functionPolyfillPath,
},

// TODO no tree shaking on wrapper pkgs
'@prisma/get-platform': { contents: '' },
// removes un-needed code out of `chalk`
Expand Down Expand Up @@ -115,10 +125,9 @@ function bundleTypeDefinitions(filename: string, outfile: string) {
}
}

void build([generatorBuildConfig, runtimeBuildConfig, browserBuildConfig, proxyBuildConfig]).then(() => {
void build([generatorBuildConfig, nodeRuntimeBuildConfig, browserBuildConfig, edgeRuntimeBuildConfig]).then(() => {
if (process.env.DEV !== 'true') {
bundleTypeDefinitions('declaration/client/src/runtime/index', 'runtime/index')
bundleTypeDefinitions('declaration/client/src/runtime/index', 'runtime/proxy')
bundleTypeDefinitions('declaration/client/src/runtime/index-browser', 'runtime/index-browser')
}
})
6 changes: 6 additions & 0 deletions packages/client/jest.config.js
@@ -1,5 +1,11 @@
module.exports = {
preset: 'ts-jest',
globals: {
'ts-jest': {
tsconfig: 'tsconfig.json',
isolatedModules: true,
},
},
testEnvironment: 'node',
collectCoverage: process.env.CI ? true : false,
coverageReporters: ['clover'],
Expand Down
2 changes: 2 additions & 0 deletions packages/client/package.json
Expand Up @@ -57,6 +57,8 @@
"runtime",
"scripts",
"generator-build",
"edge.js",
"edge.d.ts",
"index.js",
"index.d.ts",
"index-browser.js"
Expand Down
12 changes: 12 additions & 0 deletions packages/client/scripts/default-edge.js
@@ -0,0 +1,12 @@
class PrismaClient {
constructor() {
throw new Error(
`@prisma/client/edge did not initialize yet. Please run "prisma generate --data-proxy" and try to import it again.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues`,
)
}
}

module.exports = {
PrismaClient,
}
43 changes: 29 additions & 14 deletions packages/client/scripts/postinstall.js
Expand Up @@ -67,10 +67,7 @@ async function main() {
// in the postinstall hook
}

// initializes the ./node_modules/.prisma/client folder with the default index(-browser).js/index.d.ts,
// which define a `PrismaClient` class stub that throws an error if instantiated before the `prisma generate`
// command is successfully executed.
await ensureEmptyDotPrisma()
await createDefaultGeneratedThrowFiles()

// TODO: consider using the `which` package
const localPath = getLocalPackagePath()
Expand Down Expand Up @@ -197,23 +194,41 @@ function run(cmd, params, cwd = process.cwd()) {
})
}

async function ensureEmptyDotPrisma() {
/**
* Copies our default "throw" files into the default generation folder. These
* files are dummy and informative because they just throw an error to let the
* user know that they have forgotten to run `prisma generate` or that they
* don't have a a schema file yet. We only add these files at the default
* location `node_modules/.prisma/client`.
*/
async function createDefaultGeneratedThrowFiles() {
try {
const dotPrismaClientDir = path.join(__dirname, '../../../.prisma/client')
const defaultNodeIndexPath = path.join(dotPrismaClientDir, 'index.js')
const defaultNodeIndexDtsPath = path.join(dotPrismaClientDir, 'index.d.ts')
const defaultBrowserIndexPath = path.join(dotPrismaClientDir, 'index-browser.js')
const defaultEdgeIndexPath = path.join(dotPrismaClientDir, 'edge.js')
const defaultEdgeIndexDtsPath = path.join(dotPrismaClientDir, 'edge.d.ts')
await makeDir(dotPrismaClientDir)
const defaultIndexJsPath = path.join(dotPrismaClientDir, 'index.js')
const defaultIndexBrowserJSPath = path.join(dotPrismaClientDir, 'index-browser.js')
const defaultIndexDTSPath = path.join(dotPrismaClientDir, 'index.d.ts')

if (!fs.existsSync(defaultIndexJsPath)) {
await copyFile(path.join(__dirname, 'default-index.js'), defaultIndexJsPath)
if (!fs.existsSync(defaultNodeIndexPath)) {
await copyFile(path.join(__dirname, 'default-index.js'), defaultNodeIndexPath)
}

if (!fs.existsSync(defaultBrowserIndexPath)) {
await copyFile(path.join(__dirname, 'default-index-browser.js'), defaultBrowserIndexPath)
}
if (!fs.existsSync(defaultIndexBrowserJSPath)) {
await copyFile(path.join(__dirname, 'default-index-browser.js'), defaultIndexBrowserJSPath)

if (!fs.existsSync(defaultNodeIndexDtsPath)) {
await copyFile(path.join(__dirname, 'default-index.d.ts'), defaultNodeIndexDtsPath)
}

if (!fs.existsSync(defaultEdgeIndexPath)) {
await copyFile(path.join(__dirname, 'default-edge.js'), defaultEdgeIndexPath)
}

if (!fs.existsSync(defaultIndexDTSPath)) {
await copyFile(path.join(__dirname, 'default-index.d.ts'), defaultIndexDTSPath)
if (!fs.existsSync(defaultEdgeIndexDtsPath)) {
await copyFile(path.join(__dirname, 'default-index.d.ts'), defaultEdgeIndexDtsPath)
}
} catch (e) {
console.error(e)
Expand Down
14 changes: 8 additions & 6 deletions packages/client/src/__tests__/buildNFTAnnotations.test.ts
Expand Up @@ -11,7 +11,7 @@ function normalizePaths(snapshot: string): string {

describe('library', () => {
it('generates annotations for a schema and a single engine', () => {
const annotations = buildNFTAnnotations(ClientEngineType.Library, ['debian-openssl-1.1.x'], 'out')
const annotations = buildNFTAnnotations(false, ClientEngineType.Library, ['debian-openssl-1.1.x'], 'out')

expect(normalizePaths(annotations)).toMatchInlineSnapshot(`

Expand All @@ -24,6 +24,7 @@ describe('library', () => {

it('generates annotations for a schema and multiple engines', () => {
const annotations = buildNFTAnnotations(
false,
millsp marked this conversation as resolved.
Show resolved Hide resolved
ClientEngineType.Library,
['debian-openssl-1.1.x', 'darwin', 'windows'],
'out',
Expand All @@ -47,7 +48,7 @@ describe('library', () => {

describe('binary', () => {
it('generates annotations for a schema and a single engine', () => {
const annotations = buildNFTAnnotations(ClientEngineType.Binary, ['debian-openssl-1.1.x'], 'out')
const annotations = buildNFTAnnotations(false, ClientEngineType.Binary, ['debian-openssl-1.1.x'], 'out')

expect(normalizePaths(annotations)).toMatchInlineSnapshot(`

Expand All @@ -60,6 +61,7 @@ describe('binary', () => {

it('generates annotations for a schema and multiple engines', () => {
const annotations = buildNFTAnnotations(
false,
ClientEngineType.Binary,
['debian-openssl-1.1.x', 'darwin', 'windows'],
'out',
Expand All @@ -84,16 +86,15 @@ describe('binary', () => {
describe('dataproxy', () => {
it('generates no annotations', () => {
const annotations = buildNFTAnnotations(
ClientEngineType.DataProxy,
true,
millsp marked this conversation as resolved.
Show resolved Hide resolved
ClientEngineType.Library,
['debian-openssl-1.1.x', 'darwin', 'windows'],
'out',
)

// TODO: when using .toMatchInlineSnapshot(), this fails after updating snapshots.
// Probably an issue with the snapshot serializer?
expect(normalizePaths(annotations)).toBe(`

`)
expect(normalizePaths(annotations)).toBe(``)
})
})

Expand All @@ -106,6 +107,7 @@ describe('special cases', () => {
process.env.NETLIFY = 'true'

const annotations = buildNFTAnnotations(
false,
ClientEngineType.Library,
['debian-openssl-1.1.x', 'darwin', 'windows'],
'out',
Expand Down