Skip to content

Commit ce269ad

Browse files
committed
feat(json-api-nestjs): add allowSetId option for enhanced control over entity ID assignment during POST operations
1 parent e382bce commit ce269ad

File tree

6 files changed

+44
-8
lines changed

6 files changed

+44
-8
lines changed

libs/json-api/json-api-nestjs/src/lib/modules/mixin/pipe/post-input/post-input.pipe.spec.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ import {
77

88
import { PostInputPipe } from './post-input.pipe';
99
import { PostData, ZodPost } from '../../zod';
10-
import { JSONValue } from '../../types';
11-
import { ZOD_POST_SCHEMA } from '../../../../constants';
10+
import { EntityControllerParam, JSONValue } from '../../types';
11+
import {
12+
CONTROLLER_OPTIONS_TOKEN,
13+
ZOD_POST_SCHEMA,
14+
} from '../../../../constants';
1215
import { Users } from '../../../../utils/___test___/test-classes.helper';
1316

1417
describe('PostInputPipe', () => {
1518
let pipe: PostInputPipe<Users>;
1619
let mockSchema: ZodPost<Users, 'id'>;
17-
20+
let controllerOptions: EntityControllerParam;
1821
beforeEach(async () => {
1922
const module: TestingModule = await Test.createTestingModule({
2023
providers: [
@@ -25,17 +28,24 @@ describe('PostInputPipe', () => {
2528
parse: vi.fn(),
2629
},
2730
},
31+
{
32+
provide: CONTROLLER_OPTIONS_TOKEN,
33+
useValue: {
34+
allowSetId: false,
35+
},
36+
}
2837
],
2938
}).compile();
3039

3140
pipe = module.get<PostInputPipe<Users>>(PostInputPipe);
3241
mockSchema = module.get<ZodPost<Users, 'id'>>(ZOD_POST_SCHEMA);
42+
controllerOptions = module.get<EntityControllerParam>(CONTROLLER_OPTIONS_TOKEN);
3343
});
3444

3545
it('should transform JSONValue to PostData on success', () => {
3646
const input: JSONValue = { key: 'value' } as any;
3747
const expectedData: PostData<Users, 'id'> = { id: 1, key: 'value' } as any;
38-
48+
controllerOptions.allowSetId = false;
3949
vi
4050
.spyOn(mockSchema, 'parse')
4151
.mockReturnValue({ data: expectedData } as any);
@@ -44,6 +54,18 @@ describe('PostInputPipe', () => {
4454
expect(mockSchema.parse).toHaveBeenCalledWith(input);
4555
});
4656

57+
it('should transform JSONValue to PostData on success and delete id', () => {
58+
const input: JSONValue = { key: 'value' } as any;
59+
const expectedData: PostData<Users, 'id'> = { id: 1, key: 'value' } as any;
60+
61+
vi
62+
.spyOn(mockSchema, 'parse')
63+
.mockReturnValue({ data: expectedData } as any);
64+
65+
expect(pipe.transform(input)).toEqual({key: 'value'});
66+
expect(mockSchema.parse).toHaveBeenCalledWith(input);
67+
});
68+
4769
it('should throw BadRequestException if ZodError occurs', () => {
4870
const input: JSONValue = { key: 'value' };
4971

libs/json-api/json-api-nestjs/src/lib/modules/mixin/pipe/post-input/post-input.pipe.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,24 @@ import {
77
import { ZodError } from 'zod';
88

99
import { PostData, ZodPost } from '../../zod';
10-
import { ZOD_POST_SCHEMA } from '../../../../constants';
11-
import { JSONValue } from '../../types';
10+
import {
11+
CONTROLLER_OPTIONS_TOKEN,
12+
ZOD_POST_SCHEMA,
13+
} from '../../../../constants';
14+
import { EntityControllerParam, JSONValue } from '../../types';
1215

1316
export class PostInputPipe<E extends object>
1417
implements PipeTransform<JSONValue, PostData<E, 'id'>>
1518
{
1619
@Inject(ZOD_POST_SCHEMA) private zodInputPostSchema!: ZodPost<E, 'id'>;
20+
@Inject(CONTROLLER_OPTIONS_TOKEN) private controllerParams!: EntityControllerParam;
1721
transform(value: JSONValue): PostData<E, 'id'> {
1822
try {
19-
return this.zodInputPostSchema.parse(value)['data'] as PostData<E, 'id'>;
23+
const result = this.zodInputPostSchema.parse(value)['data'] as PostData<E, 'id'>;
24+
if (!this.controllerParams.allowSetId) {
25+
delete result.id;
26+
}
27+
return result;
2028
} catch (e) {
2129
if (e instanceof ZodError) {
2230
throw new BadRequestException(e.issues);

libs/json-api/json-api-nestjs/src/lib/modules/mixin/types/decorator-options.type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { PrepareParams } from '../../../types';
55
type ControllerOptions = {
66
allowMethod: Array<MethodName>;
77
overrideRoute: string;
8+
allowSetId: boolean
89
};
910

1011
export type DecoratorOptions<OrmParams = NonNullable<unknown>> = Partial<

libs/json-api/json-api-nestjs/src/lib/types/module-options.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type ModuleCommonOptions = {
2222
debug?: boolean;
2323
pipeForId?: PipeMixin;
2424
operationUrl?: string;
25+
allowSetId?: boolean
2526
};
2627

2728
type ModuleOptionsParams<OrmParams = NonNullable<unknown>> = IfEquals<

libs/json-api/json-api-nestjs/src/lib/utils/module-helper.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ describe('module-helper', () => {
8383
operationUrl: undefined,
8484
requiredSelectField: false,
8585
debug: false,
86+
allowSetId: false,
8687
pipeForId: ParseIntPipe,
8788
},
8889
});
@@ -115,6 +116,7 @@ describe('module-helper', () => {
115116
const result = prepareConfig(moduleParams);
116117

117118
expect(result.options).toEqual({
119+
allowSetId: false,
118120
operationUrl: 'http://example.com',
119121
requiredSelectField: false,
120122
debug: true,
@@ -179,6 +181,7 @@ describe('module-helper', () => {
179181
expect(result.entities).toBe(entities);
180182
expect(result).toHaveProperty('options');
181183
expect(result.options).toEqual({
184+
allowSetId: false,
182185
operationUrl: undefined,
183186
requiredSelectField: false,
184187
debug: false,

libs/json-api/json-api-nestjs/src/lib/utils/module-helper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ export function prepareConfig<OrmParams>(
2929
requiredSelectField: !!options['requiredSelectField'],
3030
debug: !!options['debug'],
3131
pipeForId: options['pipeForId'] || ParseIntPipe,
32-
},
32+
allowSetId: !!options['allowSetId']
33+
}
3334
};
3435
}
3536

0 commit comments

Comments
 (0)