Commit 85fd5c0b authored by nanahira's avatar nanahira

clean omit fields in relations

parent 109829e6
......@@ -24,6 +24,7 @@ import {
ReturnMessageDto,
} from 'nesties';
import { getNotInResultFields } from './utility/metadata';
import { getTypeormRelations } from './utility/get-typeorm-relations';
export type EntityId<T extends { id: any }> = T['id'];
export interface RelationDef {
......@@ -83,15 +84,39 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
}
_cleanEntityNotInResultFields(ent: T): T {
const fields = getNotInResultFields(
this.entityClass,
this.crudOptions.keepEntityVersioningDates,
);
const visited = new Set();
const runSingleObject = (o: any, cl) => {
if (visited.has(o)) {
return o;
}
const fields = getNotInResultFields(
cl,
this.crudOptions.keepEntityVersioningDates,
);
for (const field of fields) {
delete o[field];
}
visited.add(o);
const relations = getTypeormRelations(cl);
for (const relation of relations) {
const propertyName = relation.propertyName as string;
if (o[propertyName]) {
if (Array.isArray(o[propertyName])) {
o[propertyName] = o[propertyName].map((r) =>
runSingleObject(r, relation.propertyClass),
);
} else {
o[propertyName] = runSingleObject(
o[propertyName],
relation.propertyClass,
);
}
}
}
return o;
};
for (const field of fields) {
delete (ent as any)[field];
}
return ent;
return runSingleObject(ent, this.entityClass);
}
cleanEntityNotInResultFields<E extends T | T[]>(ents: E): E {
......@@ -203,11 +228,8 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
results = results.concat(savedChunk);
}
return {
results: this.cleanEntityNotInResultFields(results),
skipped: skipped.map((e) => ({
...e,
entry: this.cleanEntityNotInResultFields(e.entry),
})),
results,
skipped,
};
} catch (e) {
this.log.error(
......@@ -448,9 +470,14 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
}
async importEntities(
ents: T[],
_ents: T[],
extraChecking?: (ent: T) => string | Promise<string>,
) {
const ents = _ents.map((ent) => {
const newEnt = new this.entityClass();
Object.assign(newEnt, ent);
return newEnt;
});
const invalidResults = _.compact(
await Promise.all(
ents.map(async (ent) => {
......@@ -484,6 +511,7 @@ export class CrudBase<T extends ValidCrudEntity<T>> {
results.map((r) => {
const entry = new this.importEntryDto();
Object.assign(entry, r);
entry.entry = this.cleanEntityNotInResultFields(r.entry);
return entry;
}),
);
......
......@@ -35,8 +35,8 @@ import { OperationObject } from '@nestjs/swagger/dist/interfaces/open-api-spec.i
import _ from 'lodash';
import { getNotInResultFields, getSpecificFields } from '../utility/metadata';
import { RenameClass } from '../utility/rename-class';
import { getMetadataArgsStorage } from 'typeorm';
import { DECORATORS } from '@nestjs/swagger/dist/constants';
import { getTypeormRelations } from '../utility/get-typeorm-relations';
export interface RestfulFactoryOptions<T> {
fieldsToOmit?: (keyof T)[];
......@@ -54,9 +54,7 @@ export class RestfulFactory<T> {
readonly fieldsToOmit = _.uniq([
...(getSpecificFields(this.entityClass, 'notColumn') as (keyof T)[]),
...(this.options.fieldsToOmit || []),
...getMetadataArgsStorage()
.relations.filter((r) => r.target === this.entityClass)
.map((r) => r.propertyName as keyof T),
...getTypeormRelations(this.entityClass).map((r) => r.propertyName),
]);
private readonly basicInputDto = OmitType(
this.entityClass,
......@@ -99,18 +97,9 @@ export class RestfulFactory<T> {
...(this.options.outputFieldsToOmit || []),
]);
const resultDto = OmitType(this.entityClass, [...outputFieldsToOmit]);
const { relations } = getMetadataArgsStorage();
const relations = getTypeormRelations(this.entityClass);
for (const relation of relations) {
if (
outputFieldsToOmit.has(relation.propertyName as keyof T) ||
relation.target !== this.entityClass
)
continue;
const relationClassFactory = relation.type;
// check if it's a callable function
if (typeof relationClassFactory !== 'function') continue;
const relationClass = (relationClassFactory as () => AnyClass)();
if (typeof relationClass !== 'function') continue;
if (outputFieldsToOmit.has(relation.propertyName)) continue;
const replace = (useClass: [AnyClass]) => {
const oldApiProperty =
Reflect.getMetadata(
......@@ -118,14 +107,13 @@ export class RestfulFactory<T> {
this.entityClass.prototype,
relation.propertyName,
) || {};
const isArray = relation.relationType.endsWith('-many');
ApiProperty({
...oldApiProperty,
required: false,
type: () => (isArray ? [useClass[0]] : useClass[0]),
type: () => (relation.isArray ? [useClass[0]] : useClass[0]),
})(resultDto.prototype, relation.propertyName);
};
const existing = this.__resolveVisited.get(relationClass);
const existing = this.__resolveVisited.get(relation.propertyClass);
if (existing) {
replace(existing);
} else {
......@@ -133,17 +121,17 @@ export class RestfulFactory<T> {
this.__resolveVisited.set(this.entityClass, [null]);
}
const relationFactory = new RestfulFactory(
relationClass,
relation.propertyClass,
{
entityClassName: `${this.getEntityClassName()}${
relationClass.name
relation.propertyClass.name
}`,
},
this.__resolveVisited,
);
const relationResultDto = relationFactory.entityResultDto;
replace([relationResultDto]);
this.__resolveVisited.set(relationClass, [relationResultDto]);
this.__resolveVisited.set(relation.propertyClass, [relationResultDto]);
}
}
const res = RenameClass(
......
import { AnyClass, ClassType } from 'nesties';
import { getMetadataArgsStorage } from 'typeorm';
export function getTypeormRelations<T>(cl: ClassType<T>) {
const relations = getMetadataArgsStorage().relations.filter(
(r) => r.target === cl,
);
return relations.map((relation) => {
const isArray = relation.relationType.endsWith('-many');
const relationClassFactory = relation.type;
// check if it's a callable function
let propertyClass: AnyClass;
if (typeof relationClassFactory === 'function') {
const relationClass = (relationClassFactory as () => AnyClass)();
if (typeof relationClass === 'function') {
propertyClass = relationClass;
}
}
if (!propertyClass) {
propertyClass = Reflect.getMetadata(
'design:type',
cl.prototype,
relation.propertyName,
);
}
return {
isArray,
propertyClass,
propertyName: relation.propertyName as keyof T & string,
};
});
}
export function getTypeormRelationsMap<T>(cl: ClassType<T>) {
return Object.fromEntries(
getTypeormRelations(cl).map((r) => [r.propertyName, r]),
) as {
[key in keyof T]: {
isArray: boolean;
propertyClass: ClassType<T[key]>;
propertyName: key;
};
};
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment