Skip to content

Commit

Permalink
feat: new codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
timsuchanek committed Apr 13, 2018
1 parent a927433 commit bddad62
Show file tree
Hide file tree
Showing 36 changed files with 7,599 additions and 137 deletions.
54 changes: 25 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ GraphQL Binding for Prisma services (GraphQL Database)

Here is how it works:

1. Create your Prisma service by defining data model
1. Download generated database schema definition `prisma.graphql` (contains the full CRUD API)
1. Define your application schema, typically called `app.graphql`
1. Instantiate `Prisma` with information about your Prisma service (such as its endpoint and the path to the database schema definition)
1. Implement the resolvers for your application schema by delegating to the underlying Prisma service using the generated delegate resolver functions
1. Create your Prisma service by defining data model
1. Download generated database schema definition `prisma.graphql` (contains the full CRUD API)
1. Define your application schema, typically called `app.graphql`
1. Instantiate `Prisma` with information about your Prisma service (such as its endpoint and the path to the database schema definition)
1. Implement the resolvers for your application schema by delegating to the underlying Prisma service using the generated delegate resolver functions

> **Note**: If you're using a [GraphQL boilerplate](https://github.com/graphql-boilerplates/) project (e.g. with `graphql create`), the Prisma binding will already be configured and a few example resolvers implemented for you. You can either try the _dynamic binding_ (e.g. in the [`node-basic`](https://github.com/graphql-boilerplates/node-graphql-server/tree/master/basic) boilerplate) or a _static binding_ (e.g in the [`typescript-basic`](https://github.com/graphql-boilerplates/typescript-graphql-server/tree/master/basic) boilerplate).
Expand Down Expand Up @@ -73,8 +73,8 @@ The API also allows to ask whether a specific node exists in your Prisma databas
prisma.exists.Post({
id: 'abc',
author: {
name: 'Sarah'
}
name: 'Sarah',
},
})
```

Expand All @@ -84,13 +84,13 @@ prisma.exists.Post({

The `PrismaOptions` type has the following fields:

| Key | Required | Type | Default | Note |
| --- | --- | --- | --- | --- |
| `typeDefs` | Yes | `string` | - | Type definition string or file path to the schema definition of your Prisma service (typically a file called `database.graphql`) |
| `endpoint` | Yes | `string` | - | The endpoint of your Prisma service |
| `secret` | Yes | `string` | - | The secret of your Prisma service |
| `fragmentReplacements` | No | `FragmentReplacements` | `null` | A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly |
| `debug` | No | `boolean` | `false` | Log all queries/mutations to the console |
| Key | Required | Type | Default | Note |
| ---------------------- | -------- | ---------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `typeDefs` | Yes | `string` | - | Type definition string or file path to the schema definition of your Prisma service (typically a file called `database.graphql`) |
| `endpoint` | Yes | `string` | - | The endpoint of your Prisma service |
| `secret` | Yes | `string` | - | The secret of your Prisma service |
| `fragmentReplacements` | No | `FragmentReplacements` | `null` | A list of GraphQL fragment definitions, specifying fields that are required for the resolver to function correctly |
| `debug` | No | `boolean` | `false` | Log all queries/mutations to the console |

### `query` and `mutation`

Expand All @@ -106,10 +106,10 @@ Delegate resolver have the following interface:

The input arguments are used as follows:

- `args`: An object carrying potential arguments for the query/mutation
- `info`: An object representing the selection set of the query/mutation, either expressed directly as a string or in the form of `GraphQLResolveInfo` (you can find more info about the `GraphQLResolveInfo` type [here](http://graphql.org/graphql-js/type/#graphqlobjecttype))
* `args`: An object carrying potential arguments for the query/mutation
* `info`: An object representing the selection set of the query/mutation, either expressed directly as a string or in the form of `GraphQLResolveInfo` (you can find more info about the `GraphQLResolveInfo` type [here](http://graphql.org/graphql-js/type/#graphqlobjecttype))

The generic type `T` corresponds to the type of the respective field.
The generic type `T` corresponds to the type of the respective field.

### `exists`

Expand All @@ -135,8 +135,7 @@ const query = `

const variables = { userId: 'abc' }

prisma.request(query, variables)
.then(result => console.log(result))
prisma.request(query, variables).then(result => console.log(result))
// sample result:
// {"data": { "user": { "id": "abc", "name": "Sarah" } } }
```
Expand All @@ -146,12 +145,12 @@ prisma.request(query, variables)
If you just want to forward a query to the exact same underlying prisma query, you can use `forwardTo`:

```js
const {forwardTo} = require('prisma-binding')
const { forwardTo } = require('prisma-binding')

const resolvers = {
Query: {
posts: forwardTo('db')
}
posts: forwardTo('db'),
},
}

const server = new GraphQLServer({
Expand All @@ -168,17 +167,14 @@ const server = new GraphQLServer({
}),
})

server.start(
() => console.log(`Server is running on http://localhost:4000`),
)
server.start(() => console.log(`Server is running on http://localhost:4000`))
```


## Usage

- [graphql-boilerplate](https://github.com/graphcool/graphql-boilerplate).
- [graphql-server-example](https://github.com/graphcool/graphql-server-example).
* [graphql-boilerplate](https://github.com/graphcool/graphql-boilerplate).
* [graphql-server-example](https://github.com/graphcool/graphql-server-example).

## Next steps

- Code generation at build-time for the auto-generated delegate resolvers
* Code generation at build-time for the auto-generated delegate resolvers
34 changes: 34 additions & 0 deletions packages/graphql-codegen-prisma-binding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# graphql-codegen-binding

## Usage

### CLI

```sh
$ npm install -g graphql-codegen-binding
$ graphql-codegen-binding

Usage: graphql-codegen-binding -s [schema] -e [endpoint] -h [headers] -g [generator] -t [target]

Options:
--help Show help [boolean]
--version Show version number [boolean]
--schema, -s Path to schema.graphql file [string]
--endpoint, -e GraphQL endpoint to fetch schema from [string]
--headers, -h Header to use for downloading the schema (with endpoint URL)
[string]
--generator, -g Type of the generator. Available generators: typescript,
javascript [string] [required]
--target, -t Target file. Example: schema.ts [string] [required]
```

### Typescript

```ts
import { generateCode } from 'graphql-codegen-binding'
import * as fs from 'fs'

const code = generateCode(fs.readFileSync('schema.graphql'), 'typescript')

fs.writeFileSync('MyBinding.ts', code)
```
70 changes: 70 additions & 0 deletions packages/graphql-codegen-prisma-binding/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"name": "graphql-codegen-prisma-binding",
"version": "0.0.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"repository": {
"url": "https://github.com/graphcool/graphql-codegen-binding.git"
},
"bin": {
"graphql-codegen-prisma-binding": "./dist/bin.js"
},
"files": [
"dist"
],
"contributors": [
{
"name": "Tim Suchanek",
"email": "suchanek@prisma.io"
}
],
"license": "MIT",
"devDependencies": {
"@types/graphql": "^0.13.0",
"@types/jest": "^22.2.2",
"@types/node": "^9.6.2",
"jest": "^22.4.3",
"prettier": "^1.10.2",
"ts-jest": "^22.4.2",
"tslint": "^5.6.0",
"typescript": "^2.6.2"
},
"scripts": {
"test": "jest",
"build": "tsc -d && chmod +x dist/bin.js",
"lint": "tslint src/**/*.ts",
"precommit": "lint-staged",
"prepublishOnly": "yarn lint && yarn test && yarn build"
},
"peerDependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0"
},
"jest": {
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json"
],
"rootDir": "./src",
"transform": {
"^.+\\.(ts|tsx)$": "../node_modules/ts-jest/preprocessor.js"
},
"testMatch": [
"**/*.test.(ts|js)"
],
"globals": {
"ts-jest": {
"tsConfigFile": "../tsconfig.json"
}
}
},
"dependencies": {
"graphql": "^0.11.0 || ^0.12.0 || ^0.13.0",
"graphql-codegen-binding": "^0.0.15",
"graphql-config": "2.0.1",
"mkdirp": "^0.5.1",
"yargs": "^11.0.0"
}
}
64 changes: 64 additions & 0 deletions packages/graphql-codegen-prisma-binding/src/bin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env node

import * as yargs from 'yargs'
import { generateCode } from '.'

const argv = yargs
.usage(
`Usage: $0 -s [schema] -e [endpoint] -h [headers] -g [generator] -t [target]`,
)
.options({
schema: {
alias: 's',
describe: 'Path to schema.graphql file',
type: 'string',
},
endpoint: {
alias: 'e',
describe: 'GraphQL endpoint to fetch schema from',
type: 'string',
},
headers: {
alias: 'h',
describe: 'Header to use for downloading the schema (with endpoint URL)',
type: 'string',
},
generator: {
alias: 'g',
describe:
'Type of the generator. Available generators: typescript, javascript',
type: 'string',
},
target: {
alias: 't',
describe: 'Target file. Example: schema.ts',
type: 'string',
},
})
.demandOption(['g', 't']).argv

run(argv)

async function run(argv) {
const endpointHeaders = {}
const headers = argv.headers
? Array.isArray(argv.headers) ? argv.headers : [argv.headers]
: undefined
if (headers) {
Object.assign(
endpointHeaders,
...headers.map(h => ({ [h.split('=')[0]]: h.split('=')[1] })),
)
}

const { generator, target, endpoint } = argv
await generateCode({
schemaPath: argv.schema,
generator,
target,
endpoint,
headers: endpointHeaders,
})

console.log('Done generating binding')
}
42 changes: 42 additions & 0 deletions packages/graphql-codegen-prisma-binding/src/generateCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import * as fs from 'fs'
import { GraphQLEndpoint } from 'graphql-config'
import { makeBinding } from './makeBinding'
import { GeneratorType } from './types'
import * as mkdirp from 'mkdirp'
import * as path from 'path'

export interface CodeGenerationInput {
schemaPath?: string
schema?: string
endpoint?: string
generator: GeneratorType
target: string
headers?: any
}

export async function generateCode(argv: CodeGenerationInput) {
if (!argv.schema && !argv.schemaPath && !argv.endpoint) {
throw new Error(
'Please either provide the schema or the endpoint you want to get the schema from.',
)
}

const schema = argv.schema
? argv.schema
: argv.schemaPath
? fs.readFileSync(argv.schemaPath, 'utf-8')
: await downloadFromEndpointUrl(argv)

const code = makeBinding(schema, argv.generator)
mkdirp(path.dirname(argv.target))
fs.writeFileSync(argv.target, code)
}

function downloadFromEndpointUrl(argv) {
const endpoint = new GraphQLEndpoint({
url: argv.endpoint,
headers: argv.headers,
})

return endpoint.resolveSchemaSDL()
}
Loading

0 comments on commit bddad62

Please sign in to comment.