-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'LotfiMEZIANI-feature/virtual-decorator'
- Loading branch information
Showing
9 changed files
with
287 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './prop.decorator'; | ||
export * from './schema.decorator'; | ||
export * from './virtual.decorator'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { VirtualTypeOptions } from 'mongoose'; | ||
import { TypeMetadataStorage } from '../storages/type-metadata.storage'; | ||
|
||
/** | ||
* Interface defining the options that can be passed to the `@Virtual()` decorator. | ||
*/ | ||
export interface VirtualOptions { | ||
/** | ||
* The options to pass to the virtual type. | ||
*/ | ||
options?: VirtualTypeOptions; | ||
/** | ||
* The sub path to use for the virtual. | ||
* Defaults to the property key. | ||
*/ | ||
subPath?: string; | ||
/** | ||
* The getter function to use for the virtual. | ||
*/ | ||
get?: (...args: any[]) => any; | ||
/** | ||
* The setter function to use for the virtual. | ||
*/ | ||
set?: (...args: any[]) => any; | ||
} | ||
|
||
/** | ||
* The Virtual decorator marks a class property as a Mongoose virtual. | ||
*/ | ||
export function Virtual(options?: VirtualOptions): PropertyDecorator { | ||
return (target: object, propertyKey: string | symbol) => { | ||
TypeMetadataStorage.addVirtualMetadata({ | ||
target: target.constructor, | ||
options: options?.options, | ||
name: | ||
propertyKey.toString() + | ||
(options?.subPath ? `.${options.subPath}` : ''), | ||
setter: options?.set, | ||
getter: options?.get, | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './definitions.factory'; | ||
export * from './schema.factory'; | ||
export * from './virtuals.factory'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Type } from '@nestjs/common'; | ||
import * as mongoose from 'mongoose'; | ||
import { TypeMetadataStorage } from '../storages/type-metadata.storage'; | ||
|
||
export class VirtualsFactory { | ||
static inspect<TClass = any>( | ||
target: Type<TClass>, | ||
schema: mongoose.Schema<TClass>, | ||
): void { | ||
const virtuals = TypeMetadataStorage.getVirtualsMetadataByTarget(target); | ||
|
||
virtuals.forEach(({ options, name, getter, setter }) => { | ||
const virtual = schema.virtual(name, options); | ||
|
||
if (getter) { | ||
virtual.get(getter); | ||
} | ||
|
||
if (setter) { | ||
virtual.set(setter); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { VirtualTypeOptions } from 'mongoose'; | ||
|
||
export interface VirtualMetadataInterface { | ||
target: Function; | ||
name: string; | ||
options?: VirtualTypeOptions; | ||
getter?: (...args: any[]) => any; | ||
setter?: (...args: any[]) => any; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { VirtualsFactory } from '../../lib'; | ||
import { VirtualMetadataInterface } from '../../lib/metadata/virtual-metadata.interface'; | ||
import { TypeMetadataStorage } from '../../lib/storages/type-metadata.storage'; | ||
|
||
describe('VirtualsFactory', () => { | ||
const setVirtualSetterFunctionMock = jest.fn(); | ||
const setVirtualGetterFunctionMock = jest.fn(); | ||
const schemaMock = { | ||
virtual: jest.fn(() => ({ | ||
get: setVirtualGetterFunctionMock, | ||
set: setVirtualSetterFunctionMock, | ||
})), | ||
} as any; | ||
|
||
const targetConstructorMock = jest.fn(); | ||
|
||
const virtualOptionsMock = { | ||
ref: 'collectionNameMock', | ||
localField: 'localFieldMockValue', | ||
foreignField: 'foreignFieldMockValue', | ||
}; | ||
|
||
const virtualMetadataWithOnlyRequiredAttributesMock = { | ||
target: targetConstructorMock, | ||
name: 'attribute1Mock', | ||
}; | ||
|
||
const virtualMetadataNotLikedToModelMock = { | ||
target: jest.fn(), | ||
name: 'attribute1Mock', | ||
}; | ||
|
||
const virtualMetadataWithOptionsMock = { | ||
target: targetConstructorMock, | ||
name: 'virtualMetadataWithOptionsMock', | ||
options: virtualOptionsMock, | ||
}; | ||
|
||
const virtualMetadataWithGetterMock = { | ||
target: targetConstructorMock, | ||
name: 'virtualMetadataWithGetterMock', | ||
options: virtualOptionsMock, | ||
getter: jest.fn(), | ||
}; | ||
|
||
const virtualMetadataWithSetterMock = { | ||
target: targetConstructorMock, | ||
name: 'virtualMetadataWithSetterMock', | ||
options: virtualOptionsMock, | ||
setter: jest.fn(), | ||
}; | ||
|
||
const virtualMetadataWithGetterSetterMock = { | ||
target: targetConstructorMock, | ||
name: 'virtualMetadataWithGetterSetterMock', | ||
options: virtualOptionsMock, | ||
getter: jest.fn(), | ||
setter: jest.fn(), | ||
}; | ||
|
||
beforeEach(() => { | ||
(schemaMock.virtual as any) = jest.fn(() => ({ | ||
get: setVirtualGetterFunctionMock, | ||
set: setVirtualSetterFunctionMock, | ||
})); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
describe('Schema virtual definition', () => { | ||
it('should not define virtuals if there is no stored virtual definition', () => { | ||
TypeMetadataStorage['virtuals'] = []; | ||
|
||
VirtualsFactory.inspect(targetConstructorMock, schemaMock); | ||
|
||
expect(schemaMock.virtual).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
it('should not define virtuals if there is no stored virtual definition linked to schema model', () => { | ||
TypeMetadataStorage['virtuals'] = [virtualMetadataNotLikedToModelMock]; | ||
|
||
VirtualsFactory.inspect(targetConstructorMock, schemaMock); | ||
|
||
expect(schemaMock.virtual).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
it('should defines virtual for each stored virtualMetadata linked to schema model', () => { | ||
TypeMetadataStorage['virtuals'] = [ | ||
virtualMetadataWithOnlyRequiredAttributesMock, | ||
virtualMetadataNotLikedToModelMock, | ||
virtualMetadataWithOptionsMock, | ||
]; | ||
|
||
VirtualsFactory.inspect(targetConstructorMock, schemaMock); | ||
|
||
expect(schemaMock.virtual['mock'].calls).toEqual([ | ||
[virtualMetadataWithOnlyRequiredAttributesMock.name, undefined], | ||
[ | ||
virtualMetadataWithOptionsMock.name, | ||
virtualMetadataWithOptionsMock.options, | ||
], | ||
]); | ||
}); | ||
}); | ||
|
||
describe('Schema virtual getter/setter definition', () => { | ||
it('should not call the getter/setter definition method if no getter/setter defined in the stored virtual metadata linked to the schema model', () => { | ||
TypeMetadataStorage['virtuals'] = [ | ||
virtualMetadataWithOptionsMock, | ||
] as VirtualMetadataInterface[]; | ||
|
||
VirtualsFactory.inspect(targetConstructorMock, schemaMock); | ||
|
||
expect(setVirtualGetterFunctionMock).toHaveBeenCalledTimes(0); | ||
expect(setVirtualSetterFunctionMock).toHaveBeenCalledTimes(0); | ||
}); | ||
|
||
it('should call the getter/setter definition method for each stored virtuals metadata with defined getter/setter linked to the schema model', () => { | ||
TypeMetadataStorage['virtuals'] = [ | ||
virtualMetadataWithOptionsMock, | ||
virtualMetadataWithGetterMock, | ||
virtualMetadataWithSetterMock, | ||
virtualMetadataWithGetterSetterMock, | ||
] as VirtualMetadataInterface[]; | ||
|
||
VirtualsFactory.inspect(targetConstructorMock, schemaMock); | ||
|
||
expect(setVirtualGetterFunctionMock.mock.calls).toEqual([ | ||
[virtualMetadataWithGetterMock.getter], | ||
[virtualMetadataWithGetterSetterMock.getter], | ||
]); | ||
expect(setVirtualSetterFunctionMock.mock.calls).toEqual([ | ||
[virtualMetadataWithSetterMock.setter], | ||
[virtualMetadataWithGetterSetterMock.setter], | ||
]); | ||
}); | ||
}); | ||
}); |