Skip to content

Commit

Permalink
feat: Ability to hide field in schema
Browse files Browse the repository at this point in the history
closes: #8
  • Loading branch information
unlight committed Mar 1, 2021
1 parent 5d7656e commit a222955
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 130 deletions.
170 changes: 110 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,66 +33,116 @@ npx prisma generate

## Generator options

- `output` Output folder relative to this schema file
- `outputFilePattern` File pattern
Type: `string`
Default: `{feature}/{name}.{type}.ts`
Possible tokens:
- `{feature}` Model name in dashed case or 'prisma' if unknown
- `{name}` Dashed-case name of model/input/arg without suffix
- `{type}` Short type name (model, input, args, output)
- `{plural.type}` Plural short type name (models, inputs, enums)
- `combineScalarFilters` Combine nested/nullable scalar filters to single
Type: `boolean`
Default: `true`
- `noAtomicOperations` Remove input types for atomic operations
Type: `boolean`
Default: `false`
- `reExportAll` Create `index.ts` files for each directory with re-export
Type: `boolean`
Default: `false`
- `types_*` - Map prisma types in [flatten](https://github.com/hughsk/flat) style

- `types_{type}_fieldType` TypeScript field type name
- `types_{type}_fieldModule` Module to import
- `types_{type}_graphqlType` GraphQL type name
- `types_{type}_graphqlModule` Module to import

Where `{type}` is prisma type in schema

Example (Decimal):

```prisma
types_Decimal_fieldType = "Decimal"
types_Decimal_fieldModule = "decimal.js"
types_Decimal_graphqlType = "GraphQLDecimal"
types_Decimal_graphqlModule = "graphql-type-decimal"
```
Generates field:
```ts
import { GraphQLDecimal } from 'graphql-type-decimal';
import { Decimal } from 'decimal.js';
...
@Field(() => GraphQLDecimal)
field: Decimal;
```
Example (DateTime):
```prisma
types_DateTime_fieldType = "Date"
types_DateTime_graphqlType = "GraphQLISODateTime"
types_DateTime_graphqlModule = "@nestjs/graphql"
```
Generated fields:
```ts
@Field(() => GraphQLISODateTime)
field: Date;
```
#### `output`

Output folder relative to this schema file

#### `outputFilePattern`

File pattern
Type: `string`
Default: `{feature}/{name}.{type}.ts`
Possible tokens:

- `{feature}` Model name in dashed case or 'prisma' if unknown
- `{name}` Dashed-case name of model/input/arg without suffix
- `{type}` Short type name (model, input, args, output)
- `{plural.type}` Plural short type name (models, inputs, enums)

#### `combineScalarFilters`

Combine nested/nullable scalar filters to single
Type: `boolean`
Default: `true`

#### `noAtomicOperations`

Remove input types for atomic operations
Type: `boolean`
Default: `false`

#### `reExportAll`

Create `index.ts` files for each directory with re-export
Type: `boolean`
Default: `false`

#### `types_*`

Map prisma types in [flatten](https://github.com/hughsk/flat) style

- `types_{type}_fieldType` TypeScript field type name
- `types_{type}_fieldModule` Module to import
- `types_{type}_graphqlType` GraphQL type name
- `types_{type}_graphqlModule` Module to import

Where `{type}` is prisma type in schema

Example (Decimal):

```prisma
types_Decimal_fieldType = "Decimal"
types_Decimal_fieldModule = "decimal.js"
types_Decimal_graphqlType = "GraphQLDecimal"
types_Decimal_graphqlModule = "graphql-type-decimal"
```

Generates field:

```ts
import { GraphQLDecimal } from 'graphql-type-decimal';
import { Decimal } from 'decimal.js';
...
@Field(() => GraphQLDecimal)
field: Decimal;
```

Example (DateTime):

```prisma
types_DateTime_fieldType = "Date"
types_DateTime_graphqlType = "GraphQLISODateTime"
types_DateTime_graphqlModule = "@nestjs/graphql"
```

Generated fields:

```ts
@Field(() => GraphQLISODateTime)
field: Date;
```

## Field Metadata

Special directives in triple slash comments for more precise code generation.

#### `@HideField()`

Removes field from GraphQL schema.
Alias: `@TypeGraphQL.omit(output: true)`

Note: Field will be decorated for hide only in output types (type in schema),
but not in inputs.

Example:

```prisma
model User {
id String @id @default(cuid())
/// @HideField()
password String
}
```

Generates fields:

```ts
@ObjectType()
export class User {
@HideField()
password: string;
}
```

## Similar Projects

Expand Down
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ model User {
email String @unique
/// User's name
name String @unique
/// @HideField()
password String
bio String?
image String?
Expand Down
6 changes: 2 additions & 4 deletions src/@generated/user/user-count-aggregate.output.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Field, HideField, Int, ObjectType } from '@nestjs/graphql';

@ObjectType()
export class UserCountAggregate {
Expand All @@ -17,9 +17,7 @@ export class UserCountAggregate {
})
name?: number;

@Field(() => Int, {
nullable: true,
})
@HideField()
password?: number;

@Field(() => Int, {
Expand Down
6 changes: 2 additions & 4 deletions src/@generated/user/user-group-by.output.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Float, Int, ObjectType } from '@nestjs/graphql';
import { Field, Float, HideField, Int, ObjectType } from '@nestjs/graphql';

import { Role } from '../prisma/role.enum';
import { UserAvgAggregate } from './user-avg-aggregate.output';
Expand All @@ -24,9 +24,7 @@ export class UserGroupBy {
})
name!: string;

@Field(() => String, {
nullable: false,
})
@HideField()
password!: string;

@Field(() => String, {
Expand Down
6 changes: 2 additions & 4 deletions src/@generated/user/user-max-aggregate.output.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Float, Int, ObjectType } from '@nestjs/graphql';
import { Field, Float, HideField, Int, ObjectType } from '@nestjs/graphql';

import { Role } from '../prisma/role.enum';

Expand All @@ -19,9 +19,7 @@ export class UserMaxAggregate {
})
name?: string;

@Field(() => String, {
nullable: true,
})
@HideField()
password?: string;

@Field(() => String, {
Expand Down
6 changes: 2 additions & 4 deletions src/@generated/user/user-min-aggregate.output.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Float, Int, ObjectType } from '@nestjs/graphql';
import { Field, Float, HideField, Int, ObjectType } from '@nestjs/graphql';

import { Role } from '../prisma/role.enum';

Expand All @@ -19,9 +19,7 @@ export class UserMinAggregate {
})
name?: string;

@Field(() => String, {
nullable: true,
})
@HideField()
password?: string;

@Field(() => String, {
Expand Down
6 changes: 2 additions & 4 deletions src/@generated/user/user.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Float, ID, Int, ObjectType } from '@nestjs/graphql';
import { Field, Float, HideField, ID, Int, ObjectType } from '@nestjs/graphql';

import { Article } from '../article/article.model';
import { Comment } from '../comment/comment.model';
Expand All @@ -22,9 +22,7 @@ export class User {
})
name!: string;

@Field(() => String, {
nullable: false,
})
@HideField()
password!: string;

@Field(() => String, {
Expand Down
1 change: 0 additions & 1 deletion src/example/user/user.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const prisma = new PrismaClient({
],
});

// @ts-ignore
prisma.$on('query', event => {
console.log(event);
});
Expand Down
61 changes: 50 additions & 11 deletions src/generate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ let project: Project;
let propertyStructure: PropertyDeclarationStructure;
let imports: ReturnType<typeof getImportDeclarations>;

const p = (name: string) => getPropertyStructure(sourceFile, name);
const d = (name: string) => getPropertyStructure(sourceFile, name)?.decorators?.[0];

async function testGenerate(args: {
schema: string;
options?: string[];
Expand Down Expand Up @@ -396,7 +399,7 @@ describe('one model with scalar types', () => {
expect(getFieldType(sourceFile, 'not')).toContain('DateTimeFilter');
});

it('compatiblity datetime filter', async () => {
it('compatiblity datetime filter', () => {
const classFile = sourceFile.getClass('DateTimeFilter')!;
const fieldIn = classFile.getProperty('in')!;
expect(fieldIn.getStructure().type).toEqual('Array<Date> | Array<string>');
Expand Down Expand Up @@ -1179,20 +1182,56 @@ describe('export all from index', () => {
});
});

it.skip('hide field', async () => {
await testGenerate({
schema: `
describe('hide field', () => {
before(async () => {
await testGenerate({
schema: `
model User {
id String @id
/// @TypeGraphQL.omit(output: true)
/// Regular documentation
password String
id String @id
/// @TypeGraphQL.omit(output: true)
/// Password1
password1 String
/// @HideField()
/// Password2
password2 String
}
`,
options: [],
options: [],
});
// const filePaths = sourceFiles.map(s => s.getFilePath());
});

describe('model', () => {
before(() => {
sourceFile = project.getSourceFile(s =>
s.getFilePath().endsWith('/user.model.ts'),
)!;
});

// it('^', () => console.log(sourceFile.getText()));

it('TypeGraphQL omit should hide password1', () => {
expect(d('password1')?.name).toBe('HideField');
expect(d('password1')?.arguments).toEqual([]);
});

it('HideField should hide field', () => {
expect(d('password2')?.name).toBe('HideField');
expect(d('password2')?.arguments).toEqual([]);
});
});

describe('other outputs', () => {
it('user-max-aggregate', () => {
sourceFile = project.getSourceFile(s =>
s.getFilePath().endsWith('/user-max-aggregate.output.ts'),
)!;
expect(d('password1')?.name).toBe('HideField');
expect(d('password1')?.arguments).toEqual([]);
expect(d('password2')?.name).toBe('HideField');
expect(d('password2')?.arguments).toEqual([]);
});
});
const property = getPropertyStructure(sourceFile, 'password');
expect(property?.decorators?.[0]?.name).toEqual('HideField');
});

// it('^', () => console.log(sourceFile.getText()));
5 changes: 3 additions & 2 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { registerEnum } from './handlers/register-enum';
import { typeNames } from './handlers/type-names';
import { createConfig } from './helpers/create-config';
import { generateFileName } from './helpers/generate-file-name';
import { DMMF, EventArguments, Model, OutputType } from './types';
import { DMMF, EventArguments, Field, Model, OutputType } from './types';

export async function generate(
args: GeneratorOptions & {
Expand Down Expand Up @@ -58,6 +58,7 @@ export async function generate(

const models = new Map<string, Model>();
const modelNames: string[] = [];
const modelFields = new Map<string, Map<string, Field>>();
const queryOutputTypes: OutputType[] = [];
const getSourceFile = (args: { type: string; name: string }) => {
const filePath = generateFileName({
Expand All @@ -83,7 +84,7 @@ export async function generate(
eventEmitter,
typeNames: new Set<string>(),
enums: mapKeys(datamodel.enums, x => x.name),
context: {},
modelFields,
};

if (connectCallback) {
Expand Down
Loading

0 comments on commit a222955

Please sign in to comment.