json-api-nestjs
Version:
JsonApi Plugin for NestJs
222 lines • 9.03 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonApiTransformerService = void 0;
const tslib_1 = require("tslib");
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const nestjs_shared_1 = require("../../../utils/nestjs-shared");
const constants_1 = require("../../../constants");
const route_path_factory_1 = require("@nestjs/core/router/route-path-factory");
(0, common_1.Injectable)();
class JsonApiTransformerService {
applicationConfig;
entityMapProps;
currentEntity;
_urlPath;
_currentMapProps;
get currentMapProps() {
if (!this._currentMapProps) {
const result = this.entityMapProps.get(this.currentEntity);
if (!result)
throw new Error('Not found map for ' + this.currentEntity.name);
this._currentMapProps = result;
}
return this._currentMapProps;
}
get urlPath() {
if (this._urlPath)
return [...this._urlPath];
this._urlPath = [''];
const prefix = this.applicationConfig.getGlobalPrefix();
const version = this.applicationConfig.getVersioning();
const routePathFactory = new route_path_factory_1.RoutePathFactory(this.applicationConfig);
if (prefix) {
this._urlPath.push(this.applicationConfig.getGlobalPrefix());
}
if (version && version.type === common_1.VersioningType.URI) {
const firstVersion = Array.isArray(version.defaultVersion)
? version.defaultVersion[0]
: version.defaultVersion;
if (firstVersion) {
this._urlPath.push(`${routePathFactory.getVersionPrefix(version)}${firstVersion.toString()}`);
}
}
return [...this._urlPath];
}
transformData(data, query) {
if (Array.isArray(data)) {
const resultData = {
data: data.map((item) => this.transformItem(item, this.currentMapProps, query)),
};
if (query.include) {
resultData.included = this.extractIncluded(data, query);
}
return resultData;
}
const resultData = {
data: this.transformItem(data, this.currentMapProps, query),
};
if (query.include) {
resultData.included = this.extractIncluded([data], query);
}
return resultData;
}
transformItem(item, mapProps, query) {
const { fields } = query;
const target = Reflect.get(fields || {}, 'target');
return {
id: item[mapProps.primaryColumnName].toString(),
type: mapProps.typeName,
attributes: this.extractAttributes(item, mapProps.props.filter((i) => {
if (i === mapProps.primaryColumnName) {
return false;
}
if (!target) {
return true;
}
return target.includes(i);
})),
links: {
self: this.getLink(mapProps.typeName, item[mapProps.primaryColumnName]),
},
relationships: this.transformRelationships(item, mapProps, query),
};
}
transformRel(item, rel) {
const relProps = Reflect.get(this.currentMapProps.relationProperty, rel);
const relationMapPops = this.entityMapProps.get(relProps.entityClass);
if (!relationMapPops)
throw new Error('Not found props map for ' + relProps.entityClass);
const props = item[rel];
if (Array.isArray(props)) {
return props.map((i) => ({
type: relationMapPops.typeName,
id: i[relationMapPops.primaryColumnName].toString(),
}));
}
else {
return props
? {
type: relationMapPops.typeName,
id: props[relationMapPops.primaryColumnName].toString(),
}
: null;
}
}
transformRelationships(item, mapProps, query) {
const { include } = query;
const includeMap = new Map((include || []).map((i) => [i, true]));
return mapProps.relations.reduce((acum, i) => {
acum[i] = {
links: {
self: this.getLink(mapProps.typeName, item[mapProps.primaryColumnName], 'relationships', i),
},
};
if (includeMap.has(i)) {
const relationMapPops = this.entityMapProps.get(mapProps.relationProperty[i].entityClass);
if (!relationMapPops)
throw new Error('Not found props map for ' +
mapProps.relationProperty[i].entityClass.name);
if (mapProps.relationProperty[i].isArray) {
if (item[i] && Array.isArray(item[i]) && item[i].length > 0) {
// @ts-expect-error incorrect parse
acum[i]['data'] = item[i].map((rel) => ({
id: rel[relationMapPops.primaryColumnName].toString(),
type: relationMapPops.typeName,
}));
}
else {
// @ts-expect-error incorrect parse
acum[i]['data'] = [];
}
}
else {
// @ts-expect-error incorrect parse
acum[i]['data'] = item[i]
? {
id: item[i][relationMapPops.primaryColumnName].toString(),
type: relationMapPops.typeName,
}
: null;
}
}
return acum;
}, {});
}
extractAttributes(item, fields) {
const mapFields = fields.reduce((acum, field) => {
acum[field.toString()] = true;
return acum;
}, {});
return nestjs_shared_1.ObjectTyped.entries(item).reduce((acum, [name, value]) => {
if (name in mapFields && mapFields[name.toString()]) {
// @ts-expect-error assign key to object entity
acum[name] = value;
}
return acum;
}, {});
}
extractIncluded(data, query) {
const includeArray = [];
const { include } = query;
if (!include)
return [];
for (const relationPropsFromInclude of include) {
const relationProps = this.currentMapProps.relationProperty[relationPropsFromInclude];
if (!relationProps)
continue;
const relationMapProp = this.entityMapProps.get(relationProps.entityClass);
if (!relationMapProp)
throw new Error('Not found props for relation ' +
relationPropsFromInclude +
'in' +
this.currentEntity.name);
const { fields } = query;
const selectFieldForInclude = Reflect.get(fields || {}, relationPropsFromInclude);
const queryForInclude = {
...query,
fields: {
target: selectFieldForInclude &&
Array.isArray(selectFieldForInclude) &&
selectFieldForInclude.length > 0
? selectFieldForInclude
: null,
},
include: null,
};
for (const dataItem of data) {
const propRel = dataItem[relationPropsFromInclude];
if (!propRel)
continue;
if (Array.isArray(propRel)) {
for (const i of propRel) {
includeArray.push(this.transformItem(i, relationMapProp, queryForInclude));
}
}
else {
includeArray.push(this.transformItem(propRel, relationMapProp, queryForInclude));
}
}
}
return includeArray;
}
getLink(...partOfUrl) {
const urlPath = this.urlPath;
urlPath.push(...partOfUrl);
return urlPath.join('/');
}
}
exports.JsonApiTransformerService = JsonApiTransformerService;
tslib_1.__decorate([
(0, common_1.Inject)(core_1.ApplicationConfig),
tslib_1.__metadata("design:type", core_1.ApplicationConfig)
], JsonApiTransformerService.prototype, "applicationConfig", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(constants_1.ENTITY_MAP_PROPS),
tslib_1.__metadata("design:type", Map)
], JsonApiTransformerService.prototype, "entityMapProps", void 0);
tslib_1.__decorate([
(0, common_1.Inject)(constants_1.CURRENT_ENTITY),
tslib_1.__metadata("design:type", Object)
], JsonApiTransformerService.prototype, "currentEntity", void 0);
//# sourceMappingURL=json-api-transformer.service.js.map