mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 13:39:24 +08:00
137 lines
3.8 KiB
TypeScript
137 lines
3.8 KiB
TypeScript
/**
|
|
* This file is part of the NocoBase (R) project.
|
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
* Authors: NocoBase Team.
|
|
*
|
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
*/
|
|
|
|
import { Context } from '@nocobase/actions';
|
|
import { Collection } from '@nocobase/database';
|
|
|
|
export async function dataTemplate(ctx: Context, next) {
|
|
const { resourceName, actionName } = ctx.action;
|
|
const { isTemplate, fields, appends } = ctx.action.params;
|
|
|
|
await next();
|
|
|
|
if (isTemplate && actionName === 'get') {
|
|
ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), {
|
|
collection: ctx.db.getCollection(resourceName),
|
|
include: [...(fields || []), ...(appends || [])],
|
|
});
|
|
}
|
|
}
|
|
|
|
type TraverseOptions = {
|
|
collection: Collection;
|
|
exclude?: string[];
|
|
include?: string[];
|
|
through?: string;
|
|
excludePk?: boolean;
|
|
};
|
|
|
|
const traverseHasMany = (arr: any[], { collection, exclude = [], include = [] }: TraverseOptions) => {
|
|
if (!arr) {
|
|
return arr;
|
|
}
|
|
return arr.map((item) => traverseJSON(item, { collection, exclude, include }));
|
|
};
|
|
|
|
const traverseBelongsToMany = (arr: any[], { collection, exclude = [], through }: TraverseOptions) => {
|
|
if (!arr) {
|
|
return arr;
|
|
}
|
|
const throughCollection = collection.db.getCollection(through);
|
|
return arr.map((item) => {
|
|
const data = traverseJSON(item[through], { collection: throughCollection, exclude });
|
|
if (data && Object.keys(data).length) {
|
|
item[through] = data;
|
|
} else {
|
|
delete item[through];
|
|
}
|
|
return traverseJSON(item, {
|
|
collection,
|
|
excludePk: false,
|
|
});
|
|
});
|
|
};
|
|
|
|
const parseInclude = (keys: string[]) => {
|
|
const map = {};
|
|
for (const key of keys) {
|
|
const args = key.split('.');
|
|
const field = args.shift();
|
|
map[field] = map[field] || [];
|
|
if (args.length) {
|
|
map[field].push(args.join('.'));
|
|
}
|
|
}
|
|
return map;
|
|
};
|
|
|
|
const traverseJSON = (data, options: TraverseOptions) => {
|
|
if (!data) {
|
|
return data;
|
|
}
|
|
const { collection, exclude = [], include = [], excludePk = true } = options;
|
|
const map = parseInclude(include);
|
|
const result = {};
|
|
for (const key of Object.keys(data || {})) {
|
|
const subInclude = map[key];
|
|
if (include.length > 0 && !subInclude) {
|
|
continue;
|
|
}
|
|
if (exclude.includes(key)) {
|
|
continue;
|
|
}
|
|
if (['createdAt', 'updatedAt', 'createdBy', 'createdById', 'updatedById', 'updatedBy'].includes(key)) {
|
|
continue;
|
|
}
|
|
const field = collection.getField(key);
|
|
if (!field) {
|
|
result[key] = data[key];
|
|
continue;
|
|
}
|
|
if (field.options.primaryKey && excludePk) {
|
|
continue;
|
|
}
|
|
if (field.options.isForeignKey) {
|
|
continue;
|
|
}
|
|
if (['sort', 'password', 'sequence'].includes(field.type)) {
|
|
continue;
|
|
}
|
|
if (field.type === 'hasOne') {
|
|
result[key] = traverseJSON(data[key], {
|
|
collection: collection.db.getCollection(field.target),
|
|
exclude: [field.foreignKey],
|
|
include: subInclude,
|
|
});
|
|
} else if (field.type === 'hasMany') {
|
|
result[key] = traverseHasMany(data[key], {
|
|
collection: collection.db.getCollection(field.target),
|
|
exclude: [field.foreignKey],
|
|
include: subInclude,
|
|
});
|
|
} else if (field.type === 'belongsTo') {
|
|
result[key] = traverseJSON(data[key], {
|
|
collection: collection.db.getCollection(field.target),
|
|
// exclude: [field.foreignKey],
|
|
include: subInclude,
|
|
excludePk: false,
|
|
});
|
|
} else if (field.type === 'belongsToMany') {
|
|
result[key] = traverseBelongsToMany(data[key], {
|
|
collection: collection.db.getCollection(field.target),
|
|
exclude: [field.foreignKey, field.otherKey],
|
|
through: field.through,
|
|
});
|
|
} else {
|
|
result[key] = data[key];
|
|
}
|
|
}
|
|
return result;
|
|
};
|