Skip to content

Commit 82007d7

Browse files
committed
feat: Generate JSON scalar type
1 parent ecc2fb8 commit 82007d7

File tree

7 files changed

+55
-16
lines changed

7 files changed

+55
-16
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ npx prisma generate
3939

4040
- https://ts-ast-viewer.com/
4141
- https://github.com/unlight/nestjs-graphql-prisma-realworld-example-app
42+
- https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-schema/data-model
43+
- JSON type for the code first approach - https://github.com/nestjs/graphql/issues/111#issuecomment-631452899
4244

4345
## Todo
4446

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"license": "MIT",
55
"description": "Generate object types, inputs, args, etc. from prisma schema file for usage with @nestjs/graphql module",
66
"main": "index.js",
7+
"bin": "index.js",
78
"repository": {
89
"type": "git",
910
"url": "git+https://github.com/unlight/nestjs-graphql-prisma.git"
@@ -33,8 +34,7 @@
3334
"eslint:w": "watchexec -w src \"npm run eslint\"",
3435
"eslint": "node node_modules/eslint/bin/eslint \"src/**/*.{ts,tsx}\"",
3536
"lint:fix": "npm run eslint -- --fix",
36-
"build": "sh Taskfile build",
37-
"bundle": "sh Taskfile bundle",
37+
"build": "sh Taskfile bundle",
3838
"prisma:g": "node node_modules/@prisma/cli/build/index.js generate",
3939
"unused": "no-unused-export \"src/**/*.ts\"",
4040
"prettier:format": "npx prettier src --write"
@@ -85,6 +85,7 @@
8585
"eslint-plugin-unicorn": "^21.0.0",
8686
"eslint-plugin-wix-editor": "^3.2.0",
8787
"git-branch-is": "^4.0.0",
88+
"graphql-type-json": "^0.3.2",
8889
"husky": "^4.2.5",
8990
"mocha": "^8.1.1",
9091
"no-unused-export": "^1.12.2",

src/generate-model.spec.ts

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import assert from 'assert';
2-
import { Project, QuoteKind, SourceFile } from 'ts-morph';
2+
import {
3+
Node,
4+
ObjectLiteralExpression,
5+
Project,
6+
PropertyDeclaration,
7+
QuoteKind,
8+
SourceFile,
9+
} from 'ts-morph';
310

411
import { generateModel } from './generate-model';
512
import { generatorOptions, stringContains, stringNotContains } from './testing';
@@ -20,11 +27,11 @@ describe('generate models', () => {
2027
const [model] = models;
2128
sourceFile = project.createSourceFile('_.ts', sourceFileText);
2229
generateModel({ model, sourceFile, projectFilePath: () => '_.ts' });
23-
return sourceFile;
30+
sourceText = sourceFile.getText();
2431
}
2532

2633
it('model', async () => {
27-
sourceFile = await getResult(`model User {
34+
await getResult(`model User {
2835
id String @id
2936
}`);
3037
sourceText = sourceFile.getText();
@@ -34,7 +41,7 @@ describe('generate models', () => {
3441
});
3542

3643
it('field nullable', async () => {
37-
sourceFile = await getResult(`model User {
44+
await getResult(`model User {
3845
id Int @id
3946
image String?
4047
}`);
@@ -47,7 +54,7 @@ describe('generate models', () => {
4754
});
4855

4956
it('default value', async () => {
50-
sourceFile = await getResult(`model User {
57+
await getResult(`model User {
5158
count Int @id @default(1)
5259
}`);
5360
const sourceText = sourceFile.getText();
@@ -58,7 +65,7 @@ describe('generate models', () => {
5865
});
5966

6067
it('self relation', async () => {
61-
sourceFile = await getResult(`
68+
await getResult(`
6269
model User {
6370
id String @id
6471
following User[] @relation("UserFollows", references: [id])
@@ -68,7 +75,7 @@ describe('generate models', () => {
6875
});
6976

7077
it('extend existing class', async () => {
71-
sourceFile = await getResult(
78+
await getResult(
7279
`model User {
7380
id String @id
7481
}`,
@@ -79,7 +86,7 @@ describe('generate models', () => {
7986
});
8087

8188
it('object type description', async () => {
82-
sourceFile = await getResult(
89+
await getResult(
8390
`/// User really
8491
model User {
8592
id Int @id
@@ -90,7 +97,7 @@ describe('generate models', () => {
9097
});
9198

9299
it('property description', async () => {
93-
sourceFile = await getResult(
100+
await getResult(
94101
`model User {
95102
/// user id
96103
id Int @id
@@ -104,7 +111,7 @@ describe('generate models', () => {
104111
});
105112

106113
it('update description to undefined', async () => {
107-
sourceFile = await getResult(
114+
await getResult(
108115
`model User {
109116
id String @id
110117
}`,
@@ -117,7 +124,7 @@ describe('generate models', () => {
117124
});
118125

119126
it('model import scalar types', async () => {
120-
sourceFile = await getResult(`model User {
127+
await getResult(`model User {
121128
id String @id
122129
count Int
123130
money Float
@@ -131,7 +138,6 @@ describe('generate models', () => {
131138
.flatMap((x) => x.getNamedImports())
132139
.map((x) => x.getName()),
133140
);
134-
sourceText = sourceFile.getText();
135141
stringContains(
136142
'@Field(() => Boolean, { nullable: false, description: undefined }) humanoid!: boolean',
137143
sourceText,
@@ -154,4 +160,24 @@ describe('generate models', () => {
154160
assert(imports.has('Int') === true, 'Imports should includes Int');
155161
assert(imports.has('Float') === true, 'Imports should includes Float');
156162
});
163+
164+
it('model scalar json', async () => {
165+
await getResult(`model User {
166+
id String @id
167+
data Json
168+
}`);
169+
sourceText = sourceFile.getText();
170+
const propertyDeclaration = sourceFile.getClass('User')?.getProperty('data');
171+
assert(propertyDeclaration);
172+
stringContains(`@Field(() => GraphQLJSON`, propertyDeclaration.getText());
173+
174+
const importDeclaration = sourceFile.getImportDeclaration(
175+
(d) => d.getModuleSpecifier().getLiteralValue() === 'graphql-type-json',
176+
);
177+
assert(importDeclaration, 'import graphql-type-json should exists');
178+
const importSpecifier = importDeclaration
179+
.getNamedImports()
180+
.find((x) => x.getName() === 'GraphQLJSON');
181+
assert(importSpecifier, 'const GraphQLJSON should be imported');
182+
});
157183
});

src/generate.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ describe('main generate', () => {
2020

2121
it('smoke one', async () => {
2222
await getResult({
23-
schema: `model User {
23+
schema: `
24+
model User {
2425
id Int @id
2526
}
2627
`,

src/testing/generator-options.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ export async function generatorOptions(
2121
if (!fs.existsSync(optionsCacheFile)) {
2222
const schemaFile = `${cachePath}/schema-${hash}.prisma`;
2323
const schemaData = `
24+
datasource database {
25+
provider = "postgresql"
26+
url = env("DATABASE_URL")
27+
}
2428
generator client {
2529
provider = "prisma-client-js"
2630
}

src/to-graphql-import-type.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
type ToGraphqlImportTypeArgs = {
22
isId?: boolean;
33
type: string;
4+
kind: string;
45
};
56

67
export function toGraphqlImportType(args: ToGraphqlImportTypeArgs) {
7-
const { isId, type } = args;
8+
const { isId, type, kind } = args;
89
let name = type;
910
if (isId) {
1011
return { name: 'ID', moduleSpecifier: '@nestjs/graphql' };
1112
}
1213
if (name === 'Int' || name === 'Float') {
1314
return { name, moduleSpecifier: '@nestjs/graphql' };
1415
}
16+
if (kind === 'scalar' && type === 'Json') {
17+
return { name: 'GraphQLJSON', moduleSpecifier: 'graphql-type-json' };
18+
}
1519
if (name === 'DateTime') {
1620
name = 'String';
1721
}

src/to-property-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const patterns = new Map([
44
[{ type: (type: string) => type === 'Float', kind: 'scalar' }, () => 'number'],
55
[{ type: (type: string) => type === 'Int', kind: 'scalar' }, () => 'number'],
66
[{ type: (type: string) => type === 'Boolean', kind: 'scalar' }, () => 'boolean'],
7+
[{ type: (type: string) => type === 'Json', kind: 'scalar' }, () => 'object'],
78
[{ type: () => true, kind: 'object' }, (field: { type: string }) => field.type],
89
[{ type: () => true, kind: 'enum' }, (field: { type: string }) => field.type],
910
[{ type: () => true, kind: 'scalar' }, (field: { type: string }) => field.type],

0 commit comments

Comments
 (0)