Skip to content

Commit

Permalink
feat: settings system for runtime & gentime (#42)
Browse files Browse the repository at this point in the history
Co-authored-by: eemmiillyy <emily.morgan@code.berlin>
  • Loading branch information
jasonkuhrt and eemmiillyy authored May 18, 2021
1 parent 4a82c91 commit ef76e45
Show file tree
Hide file tree
Showing 42 changed files with 545 additions and 374 deletions.
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
],
"overrides": [],
"rules": {
// They are great actually
"@typescript-eslint/no-namespace": "off",
// TypeScript makes these safe & effective
"no-case-declarations": "off",
// Same approach used by TypeScript noUnusedLocals
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,5 @@ dist
# Facades
scalars.d.ts
scalars.js
plugin.js
plugin.d.ts
generator.d.ts
generator.js
117 changes: 108 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ Official Prisma plugin for Nexus.
- [Project 1:n Relation](#project-1n-relation)
- [Example: Tests](#example-tests-1)
- [Example: Full 1:n](#example-full-1n)
- [Prisma ID field to GraphQL ID scalar type mapping](#prisma-id-field-to-graphql-id-scalar-type-mapping)
- [Prisma Schema docs re-used for GraphQL schema doc](#prisma-schema-docs-re-used-for-graphql-schema-doc)
- [Prisma Schema docs re-used for JSDoc](#prisma-schema-docs-re-used-for-jsdoc)
- [Runtime Settings](#runtime-settings)
- [Reference](#reference)
- [Generator Settings](#generator-settings)
- [Usage](#usage-1)
- [Reference](#reference-1)
- [Prisma String @id fields project as GraphQL ID fields](#prisma-string-id-fields-project-as-graphql-id-fields)
- [Prisma Schema Docs Propagation](#prisma-schema-docs-propagation)
- [As GraphQL schema doc](#as-graphql-schema-doc)
- [As JSDoc](#as-jsdoc)
- [Refined DX](#refined-dx)
- [Recipes](#recipes)
- [Project relation with custom resolver logic](#project-relation-with-custom-resolver-logic)
Expand Down Expand Up @@ -120,7 +126,7 @@ export const schema = makeSchema({

## Features

> **Note**: ⛑ The following use abbreviated examples that skip a complete setup of passing Nexus type definition to Nexus' `makeSchema`. If you are new to Nexus, Consider reading the [official Nexus tutorial](https://nxs.li/tutorial) before jumping into Nexus Prisma.
> **Note**: ⛑ The following use abbreviated examples that skip a complete setup of passing Nexus type definition to Nexus' `makeSchema`. If you are new to Nexus, consider reading the [official Nexus tutorial](https://nxs.li/tutorial) before jumping into Nexus Prisma.
### Type-safe Generated Library Code

Expand Down Expand Up @@ -547,9 +553,100 @@ query {
}
```

### Prisma ID field to GraphQL ID scalar type mapping
### Runtime Settings

All `@id` fields in your Prisma Schema get projected as `ID` types, not `String` types.
#### Reference

##### `prismaClientContextField: string`

- **@summary** The name of the GraphQL context field to get an instance of Prisma Client from.
- **@remarks** The instance of Prisma Client found here is accessed in the default resolvers for relational fields.
- **@default** `"prisma"`
- **@example**

```ts
// src/main.ts

import { PrismaClient } from '@prisma/client'
import { ApolloServer } from 'apollo-server'
import { makeSchema } from 'nexus'
import { User, Post, $settings } from 'nexus-prisma'

new ApolloServer({
schema: makeSchema({
types: [],
}),
context() {
return {
db: new PrismaClient(), // <-- You put Prisma client on the "db" context property
}
},
})

$settings({
prismaClientContextField = 'db', // <-- Tell Nexus Prisma
})
```

### Generator Settings

You are able to control certain aspects of the Nexus Prisma code generation.

#### Usage

1. Create a configuration file named any of:

```
nexusPrisma.ts / nexus-prisma.ts / nexus_prisma.ts
```

In one of the following directories:

1. **Project Root**The directory containing your project's package.json. Example:

```
├── nexus-prisma.ts
└── package.json
```

2. **Primsa Directory**The directory containing your Prisma schema. Example:

```
├── prisma/nexus-prisma.ts
└── package.json
```

2. Import the settings singleton and make your desired changes. Example:

```ts
import { settings } from 'nexus-prisma/generator'
settings({
projectIdIntToGraphQL: 'ID',
})
```

#### Reference

##### `projectIdIntToGraphQL: 'ID' | 'Int'`

- **`@summary`** Map Prisma model fields of type `Int` with attribute `@id` to `ID` or `Int`.
- **`@default`** `Int`

##### `docPropagation.JSDoc: boolean`

- **`@summary`** Should Prisma Schema docs propagate as JSdoc?
- **`@default`** `true`

##### `docPropagation.GraphQLDocs: boolean`

- **`@summary`** Should Prisma Schema docs propagate as GraphQL docs?
- **`@remarks`** When this is disabled it will force `.description` property to be `undefined`. This is for convenience, allowing you to avoid post-generation data manipulation or consumption contortions.
- **`@default`** `true`

### Prisma String @id fields project as GraphQL ID fields

All `String` fields with `@id` attribute in your Prisma Schema get projected as GraphQL `ID` types rather than `String` types.

```prisma
model User {
Expand All @@ -576,7 +673,9 @@ type User {
}
```

### Prisma Schema docs re-used for GraphQL schema doc
### Prisma Schema Docs Propagation

#### As GraphQL schema doc

```prisma
/// A user.
Expand Down Expand Up @@ -614,7 +713,7 @@ type User {
}
```

### Prisma Schema docs re-used for JSDoc
#### As JSDoc

```prisma
/// A user.
Expand Down Expand Up @@ -676,7 +775,7 @@ Nexus Prisma generates default GraphQL resolvers for your model _relation fields
resolve(...args) {
// Your custom before-logic here
const result = await User.posts.resolve(...args)
// Your custom afer-logic here
// Your custom after-logic here
return result
},
})
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const config: InitialOptionsTsJest = {
testPathIgnorePatterns: process.env.CI ? [] : ['.*e2e.*'],
globals: {
'ts-jest': {
diagnostics: Boolean(process.env.CI),
diagnostics: Boolean(process.env.CI) ? { ignoreCodes: [7006, 7031] } : false,
babelConfig: false,
tsconfig: '<rootDir>/tests/tsconfig.json',
},
Expand Down
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"plugin.js",
"plugin.d.ts",
"scalars.js",
"scalars.d.ts"
"scalars.d.ts",
"settings.d.ts",
"settings.js",
"generator.d.ts",
"generator.js"
],
"bin": {
"nexus-prisma": "./dist/cli/nexus-prisma.js",
Expand All @@ -24,7 +28,7 @@
"lint:check": "eslint . --ext .ts,.tsx --max-warnings 0",
"dev": "tsc --build --watch",
"dev:ts": "yarn dev",
"dev:yalc": "nodemon --exec 'yalc push --no-scripts' --watch 'dist/**/*'",
"dev:yalc": "nodemon --delay 1.5 --exec 'yalc push --no-scripts' --watch 'dist/**/*'",
"build:module-facades": "ts-node scripts/build-module-facades",
"build": "yarn clean && yarn build:module-facades && tsc",
"test": "cross-env DEBUG=e2e jest",
Expand Down Expand Up @@ -81,9 +85,7 @@
"nexus": "^1.0.0"
},
"dependencies": {
"@endemolshinegroup/cosmiconfig-typescript-loader": "^3.0.2",
"@prisma/generator-helper": "^2.22.1",
"cosmiconfig": "^7.0.0",
"debug": "^4.3.1",
"endent": "^2.0.1",
"fs-jetpack": "^4.1.0",
Expand Down
8 changes: 4 additions & 4 deletions scripts/build-module-facades.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import * as path from 'path'
import { PackageJson } from 'type-fest'

generateModuleFacades([
['scalars.d.ts', "export * from './dist/scalars'"],
['scalars.js', "module.exports = require('./dist/scalars')"],
['scalars.d.ts', "export * from './dist/entrypoints/scalars'"],
['scalars.js', "module.exports = require('./dist/entrypoints/scalars')"],

['plugin.d.ts', "export * from './dist/plugin'"],
['plugin.js', "exports.plugin = reuqire('./dist/plugin')"],
['generator.d.ts', "export * from './dist/entrypoints/generator'"],
['generator.js', "module.exports = require('./dist/entrypoints/generator')"],
])

function generateModuleFacades(facades: ModuleFacade[]) {
Expand Down
1 change: 1 addition & 0 deletions settings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './dist/settings'
1 change: 1 addition & 0 deletions settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/settings')
13 changes: 8 additions & 5 deletions src/cli/nexus-prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ process.env.DEBUG_HIDE_DATE = 'true'

import { generatorHandler } from '@prisma/generator-helper'
import * as Path from 'path'

import { generateRuntimeAndEmit } from '../generator'
import { loadUserGentimeSettings } from '../generator/gentime/settingsLoader'
import { Gentime } from '../generator/gentime/settingsSingleton'
import { externalToInternalDmmf } from '../helpers/prismaExternalToInternalDMMF'
import { getConfiguration } from '../configuration'

// todo by default error in ci and warn in local
// enforceValidPeerDependencies({
Expand All @@ -25,10 +25,13 @@ generatorHandler({
}
},
// async required by interface
// eslint-disable-next-line
async onGenerate({ dmmf }) {
const internalDMMF = externalToInternalDmmf(dmmf)
console.log('created internal dmmf')
const configuration = await getConfiguration()
generateRuntimeAndEmit(internalDMMF, configuration)
loadUserGentimeSettings()
generateRuntimeAndEmit(internalDMMF, Gentime.settings)
process.stdout.write(
`You can now start using Nexus Prisma in your code. Reference: https://pris.ly/d/nexus-prisma\n`
)
},
})
34 changes: 0 additions & 34 deletions src/configuration/configuration.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/configuration/index.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/entrypoints/generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Gentime } from '../generator/gentime/settingsSingleton'

export const settings = Gentime.changeSettings
4 changes: 2 additions & 2 deletions src/scalars/index.ts → src/entrypoints/scalars.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DateTime } from './DateTime'
import { Json } from './Json'
import { DateTime } from '../scalars/DateTime'
import { Json } from '../scalars/Json'

/**
* Predefined Nexus scalar type definitions to satisfy all custom scalars needed in GraphQL to map to the
Expand Down
17 changes: 9 additions & 8 deletions src/generator/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import * as fs from 'fs-jetpack'
import * as Path from 'path'
import * as pkgup from 'pkg-up'
import { d } from '../helpers/debugNexusPrisma'
import { Gentime } from './gentime/settingsSingleton'
import * as ModelsGenerator from './models'
import { ModuleSpec, Configuration } from './types'
import { ModuleSpec } from './types'

const OUTPUT_SOURCE_DIR = getOutputSourceDir()

/** Generate the Nexus Prisma runtime files and emit them into a "hole" in the internal package source tree. */
export function generateRuntimeAndEmit(dmmf: DMMF.Document, configuration: Configuration | null): void {
d('start generateRuntime with configuration %j', configuration)
export function generateRuntimeAndEmit(dmmf: DMMF.Document, settings: Gentime.Settings): void {
d('start generateRuntime with configuration %j', settings)

d('start generateRuntime')

Expand All @@ -19,8 +20,8 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, configuration: Confi
}

const sourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec(),
ModelsGenerator.TS.createModuleSpec(dmmf),
ModelsGenerator.JS.createModuleSpec(settings),
ModelsGenerator.TS.createModuleSpec(dmmf, settings),
]

fs.remove(OUTPUT_SOURCE_DIR)
Expand All @@ -36,10 +37,10 @@ export function generateRuntimeAndEmit(dmmf: DMMF.Document, configuration: Confi
}

/** Transform the given DMMF into JS source code with accompanying TS declarations. */
export function generateRuntime(dmmf: DMMF.Document): ModuleSpec[] {
export function generateRuntime(dmmf: DMMF.Document, settings: Gentime.Settings): ModuleSpec[] {
const sourceFiles: ModuleSpec[] = [
ModelsGenerator.JS.createModuleSpec(),
ModelsGenerator.TS.createModuleSpec(dmmf),
ModelsGenerator.JS.createModuleSpec(settings),
ModelsGenerator.TS.createModuleSpec(dmmf, settings),
]

return sourceFiles
Expand Down
Loading

0 comments on commit ef76e45

Please sign in to comment.