UNPKG

@dazejs/framework

Version:

Daze.js - A powerful web framework for Node.js

399 lines (358 loc) 8.29 kB
/** * Copyright (c) 2020 Chan Zewail * * This software is released under the MIT License. * https: //opensource.org/licenses/MIT */ import { Container } from '../container'; import { Application } from '../foundation/application'; import { ResourceInterface } from '../interfaces'; import { Repository } from '../supports/orm/repository'; import { Paginator } from '../pagination'; const DEFAULT_KEY = 'data'; export const enum EResourceTypeList { Item = 'item', Collection = 'collection' } export class Resource { /** * @var app Application instance */ app: Application = Container.get('app'); /** * @var key resource data key */ key?: string = DEFAULT_KEY; /** * @var data resource data */ data: any; /** * @var formatter resource data formatter */ formatter: any = (data: any) => { if (data instanceof Repository) return data.getAttributes(); return data; }; /** * @var formatter resource meta data formatter */ metaFormatter: any; /** * @var meta resource meta data */ meta: any; /** * resource type */ type: EResourceTypeList; /** * Create Resource */ constructor(formatter?: any) { if (formatter) this.formatter = formatter; } /** * 返回 item 类型资源 * @param data */ item(data: any) { this.type = EResourceTypeList.Item; this.setData(data); return this; } static item(data: any) { return new Resource().item(data); } /** * 返回 collection 类型资源 * @param data */ collection(data: any) { this.type = EResourceTypeList.Collection; if (data instanceof Paginator) { this.setData(data.getData()); this.addMeta( data.getCurrentPageKey(), data.getCurrentPage() ); this.addMeta( data.getTotalKey(), data.getTotal() ); this.addMeta( data.getPerPageKey(), data.getPerPage() ); return this; } this.setData(data); return this; } static collection(data: any) { return new Resource().collection(data); } /** * set resource data formatter * @param formatter resource data formatter */ setFormatter(formatter: any) { this.formatter = formatter; return this; } /** * get resource data formatter */ getFormatter() { return this.formatter; } /** * Resource Key getter * @var {string} resource key */ getKey() { return this.key; } /** * Resource Key Setter * @var resource key */ setKey(val: string) { this.key = val; return this; } /** * Resource data getter */ getData() { return this.data; } /** * Resource data Setter */ setData(val: any) { this.data = val; return this; } /** * Resource meta getter */ getMeta() { return this.meta; } /** * Resource meta Setter * @var resource meta */ setMeta(val: any) { this.meta = val; return this; } /** * meta formatter formatter getter */ getMetaFormatter() { return this.metaFormatter; } /** * meta formatter formatter setter * @var meta formatter */ setMetaFormatter(val: any) { this.metaFormatter = val; return this; } /** * add meta object * @param name meta object key name * @param value meta value for name key */ addMeta(name: string | object, value?: any) { if (!this.meta) this.meta = {}; if (name && typeof name === 'object') { this.meta = Object.assign({}, this.meta, name); } else if (typeof name === 'string') { this.meta[name] = value; } return this; } /** * remove reource key */ withoutKey() { this.key = undefined; return this; } /** * transform resource meta object */ transformResourceMeta() { return this.useTransformer(this.metaFormatter, this.meta); } /** * transform resource data object or array */ transformResourceData() { if (this.type === EResourceTypeList.Item) { return this.useTransformer(this.formatter, this.data); } if (this.type === EResourceTypeList.Collection) { return this.data.map((i: any) => this.useTransformer(this.formatter, i)); } return this.data; } /** * use tansformer transform data or meta * @param formatter resource formatter * @param data resource meta or data */ useTransformer(formatter: any, data: any) { if (!data) return null; // 如果是字符串 if (typeof formatter === 'string') { return this.recursiveFilter( this.useStringFormatter(formatter, data) ); } // 如果是资源类 if (this.isResourceFormatter(formatter as any)) { return this.recursiveFilter( this.useResourceFormatter(formatter as any, data) ); } // 如果是回调函数/类 if (typeof formatter === 'function') { // 容器中已绑定 return this.recursiveFilter( this.useCallbackFormatter(formatter as any, data) ); } return this.recursiveFilter(data); } /** * check if is resource component * @param formatter */ isResourceFormatter(formatter: { new(): any } | ((...args: any[]) => any)): formatter is { new(): any } { return formatter && Reflect.getMetadata('type', formatter) === 'resource'; } /** * use string type formatter * @param formatter * @param data */ useStringFormatter(formatterName: string, data: any) { // AMRK: COMPONENT_NAME // const Transformer = this.app.get(`resource.${formatter}`, this.__context__); const Transformer = this.app.get<ResourceInterface>(formatterName); return Transformer.resolve(data); } /** * use resource type formatter * @param formatter * @param data */ useResourceFormatter(formatter: { new(): ResourceInterface }, data: any) { const Transformer = this.app.get<ResourceInterface>(formatter); return Transformer.resolve(data); } /** * use function formatter * @param formatter * @param data */ useCallbackFormatter(formatter: (...args: any[]) => any, data: any) { return formatter(data); } /** * serialize Rource data * @param isWrapCollection is collection use wrap key */ serializeResourceData(isOverstore = true, hasMeta = false) { const data = this.transformResourceData(); if (this.type === EResourceTypeList.Collection) { if (this.key) { return { [this.key]: data, }; } return (isOverstore || hasMeta) ? { data, } : data; } if (this.type === EResourceTypeList.Item) { if (this.key) { return { [this.key]: data, }; } return data; } if (this.key) { return { [this.key]: null, }; } return null; } /** * serialize resource meta */ serializeResourceMeta() { const meta = this.transformResourceMeta(); return meta ? { meta, } : null; } /** * transform data */ transform(isOverstore = true) { const meta = this.serializeResourceMeta(); const data = this.serializeResourceData(isOverstore, !!meta) || {}; if (meta) { return { ...data, ...meta }; } return data; } /** * 递归过滤数据 * @param data */ private recursiveFilter(data: any): any { // 资源类进行转换 if (data instanceof Resource) { return data.withoutKey().transform(false); } // 模型类进行属性获取 else if (data instanceof Repository) { return data.getAttributes(); } // 数组过滤 else if (Array.isArray(data)) { return data.map(item => this.recursiveFilter(item)); } // 对象过滤 else if (data !== null && typeof data === 'object') { const res: any = {}; for (const key in data) { if (Object.prototype.hasOwnProperty.call(data, key)) { const item = data[key]; res[key] = this.recursiveFilter(item); } } return res; } // 其他直接使用 else { return data; } } /** * output result */ output(isOverstore = true) { const data = this.transform(isOverstore); return data; } }