From cf3c7dbd35f90b8aa5efba81ff26ca10daf8c9bc Mon Sep 17 00:00:00 2001 From: "guokai.jgk" Date: Thu, 29 Oct 2020 17:54:53 +0800 Subject: [PATCH] feat: update datasource engine --- packages/datasource-engine/.eslintrc.js | 1 + packages/datasource-engine/.prettierrc.js | 1 + .../src/core/RuntimeDataSourceItem.ts | 28 +++--- .../datasource-engine/src/core/adapter.ts | 62 +++++-------- .../src/core/reloadDataSourceFactory.ts | 20 ++--- .../datasource-engine/src/helpers/index.ts | 26 ++++-- .../src/interpret/DataSourceEngineFactory.ts | 22 ++--- .../runtime/RuntimeDataSourceEngineFactory.ts | 29 ++---- .../p0-0-custom-request-handlers/README.md | 3 + .../_datasource-runtime.ts | 67 ++++++++++++++ .../_datasource-schema.ts | 67 ++++++++++++++ .../_macro-normal.ts | 90 +++++++++++++++++++ .../normal-interpret.test.ts | 20 +++++ .../normal-runtime.test.ts | 20 +++++ packages/types/src/data-source-handlers.ts | 10 ++- packages/types/src/data-source-runtime.ts | 6 +- 16 files changed, 355 insertions(+), 117 deletions(-) create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts create mode 100644 packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts diff --git a/packages/datasource-engine/.eslintrc.js b/packages/datasource-engine/.eslintrc.js index 258d60040..6cbc6c8e9 100644 --- a/packages/datasource-engine/.eslintrc.js +++ b/packages/datasource-engine/.eslintrc.js @@ -3,5 +3,6 @@ module.exports = { rules: { '@typescript-eslint/no-parameter-properties': 0, 'no-param-reassign': 0, + 'max-len': 0, }, }; diff --git a/packages/datasource-engine/.prettierrc.js b/packages/datasource-engine/.prettierrc.js index de2f53cdf..21ec86215 100644 --- a/packages/datasource-engine/.prettierrc.js +++ b/packages/datasource-engine/.prettierrc.js @@ -1,4 +1,5 @@ module.exports = { singleQuote: true, trailingComma: 'all', + printWidth: 120, }; diff --git a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts index 0abfe5a18..5d71e2e1b 100644 --- a/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts +++ b/packages/datasource-engine/src/core/RuntimeDataSourceItem.ts @@ -9,10 +9,8 @@ import { UrlParamsHandler, } from '@ali/lowcode-types'; -class RuntimeDataSourceItem< - TParams extends Record = Record, - TResultData = unknown -> implements IRuntimeDataSource { +class RuntimeDataSourceItem = Record, TResultData = unknown> + implements IRuntimeDataSource { private _data?: TResultData; private _error?: Error; @@ -21,9 +19,7 @@ class RuntimeDataSourceItem< private _dataSourceConfig: RuntimeDataSourceConfig; - private _request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler; + private _request: RequestHandler<{ data: TResultData }> | UrlParamsHandler; private _context: IDataSourceRuntimeContext; @@ -31,9 +27,7 @@ class RuntimeDataSourceItem< constructor( dataSourceConfig: RuntimeDataSourceConfig, - request: - | RequestHandler<{ data: TResultData }> - | UrlParamsHandler, + request: RequestHandler<{ data: TResultData }> | UrlParamsHandler, context: IDataSourceRuntimeContext, ) { this._dataSourceConfig = dataSourceConfig; @@ -57,14 +51,14 @@ class RuntimeDataSourceItem< if (!this._dataSourceConfig) return; // 考虑没有绑定对应的 handler 的情况 if (!this._request) { - throw new Error(`no ${this._dataSourceConfig.type} handler provide`); + this._error = new Error(`no ${this._dataSourceConfig.type} handler provide`); + this._status = RuntimeDataSourceStatus.Error; + throw this._error; } // TODO: urlParams 有没有更好的处理方式 if (this._dataSourceConfig.type === 'urlParams') { - const response = await (this._request as UrlParamsHandler)( - this._context, - ); + const response = await (this._request as UrlParamsHandler)(this._context); this._context.setState({ [this._dataSourceConfig.id]: response, }); @@ -100,10 +94,8 @@ class RuntimeDataSourceItem< if (!shouldFetch) { this._status = RuntimeDataSourceStatus.Error; - this._error = new Error( - `the ${this._dataSourceConfig.id} request should not fetch, please check the condition`, - ); - return; + this._error = new Error(`the ${this._dataSourceConfig.id} request should not fetch, please check the condition`); + throw this._error; } let fetchOptions = this._options; diff --git a/packages/datasource-engine/src/core/adapter.ts b/packages/datasource-engine/src/core/adapter.ts index 41a476bc7..71f930bea 100644 --- a/packages/datasource-engine/src/core/adapter.ts +++ b/packages/datasource-engine/src/core/adapter.ts @@ -1,10 +1,4 @@ -import { - transformFunction, - getRuntimeValueFromConfig, - getRuntimeJsValue, - buildOptions, - buildShouldFetch, -} from './../utils'; +import { getRuntimeValueFromConfig, getRuntimeJsValue, buildOptions, buildShouldFetch } from './../utils'; // 将不同渠道给的 schema 转为 runtime 需要的类型 import { defaultDataHandler, defaultWillFetch } from '../helpers'; @@ -16,18 +10,11 @@ import { RuntimeDataSourceConfig, } from '@ali/lowcode-types'; -const adapt2Runtime = ( - dataSource: InterpretDataSource, - context: IDataSourceRuntimeContext, -) => { - const { - list: interpretConfigList, - dataHandler: interpretDataHandler, - } = dataSource; - const dataHandler: (dataMap?: DataSourceMap) => void = - interpretDataHandler && - interpretDataHandler.compiled && - transformFunction(interpretDataHandler.compiled, context); +const adapt2Runtime = (dataSource: InterpretDataSource, context: IDataSourceRuntimeContext) => { + const { list: interpretConfigList, dataHandler: interpretDataHandler } = dataSource; + const dataHandler: (dataMap?: DataSourceMap) => void = interpretDataHandler + ? getRuntimeJsValue(interpretDataHandler, context) + : undefined; // 为空判断 if (!interpretConfigList || !interpretConfigList.length) { @@ -36,29 +23,20 @@ const adapt2Runtime = ( dataHandler, }; } - const list: RuntimeDataSourceConfig[] = interpretConfigList.map( - (el: InterpretDataSourceConfig) => { - return { - id: el.id, - isInit: - getRuntimeValueFromConfig('boolean', el.isInit, context) || true, // 默认 true - isSync: - getRuntimeValueFromConfig('boolean', el.isSync, context) || false, // 默认 false - type: el.type || 'fetch', - willFetch: el.willFetch - ? getRuntimeJsValue(el.willFetch, context) - : defaultWillFetch, - shouldFetch: buildShouldFetch(el, context), - dataHandler: el.dataHandler - ? getRuntimeJsValue(el.dataHandler, context) - : defaultDataHandler, - errorHandler: el.errorHandler - ? getRuntimeJsValue(el.errorHandler, context) - : undefined, - options: buildOptions(el, context), - }; - }, - ); + const list: RuntimeDataSourceConfig[] = interpretConfigList.map((el: InterpretDataSourceConfig) => { + return { + id: el.id, + isInit: getRuntimeValueFromConfig('boolean', el.isInit, context) || true, // 默认 true + isSync: getRuntimeValueFromConfig('boolean', el.isSync, context) || false, // 默认 false + type: el.type || 'fetch', + willFetch: el.willFetch ? getRuntimeJsValue(el.willFetch, context) : defaultWillFetch, + shouldFetch: buildShouldFetch(el, context), + dataHandler: el.dataHandler ? getRuntimeJsValue(el.dataHandler, context) : defaultDataHandler, + errorHandler: el.errorHandler ? getRuntimeJsValue(el.errorHandler, context) : undefined, + requestHandler: el.requestHandler ? getRuntimeJsValue(el.requestHandler, context) : undefined, + options: buildOptions(el, context), + }; + }); return { list, diff --git a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts index b871c2f37..87a111ca0 100644 --- a/packages/datasource-engine/src/core/reloadDataSourceFactory.ts +++ b/packages/datasource-engine/src/core/reloadDataSourceFactory.ts @@ -1,12 +1,9 @@ -import { - DataSourceMap, - RuntimeDataSource, - RuntimeDataSourceConfig, -} from '@ali/lowcode-types'; +import { DataSourceMap, RuntimeDataSource, RuntimeDataSourceConfig } from '@ali/lowcode-types'; export const reloadDataSourceFactory = ( dataSource: RuntimeDataSource, dataSourceMap: DataSourceMap, + dataHandler?: (dataSourceMap: DataSourceMap) => void, ) => async () => { const allAsyncLoadings: Array> = []; @@ -16,16 +13,13 @@ export const reloadDataSourceFactory = ( .filter( (el: RuntimeDataSourceConfig) => // eslint-disable-next-line implicit-arrow-linebreak - el.type === 'urlParams' && - (typeof el.isInit === 'boolean' ? el.isInit : true), + el.type === 'urlParams' && (typeof el.isInit === 'boolean' ? el.isInit : true), ) .forEach((el: RuntimeDataSourceConfig) => { dataSourceMap[el.id].load(); }); - const remainRuntimeDataSourceList = dataSource.list.filter( - (el: RuntimeDataSourceConfig) => el.type !== 'urlParams', - ); + const remainRuntimeDataSourceList = dataSource.list.filter((el: RuntimeDataSourceConfig) => el.type !== 'urlParams'); // 处理并行 for (const ds of remainRuntimeDataSourceList) { @@ -63,4 +57,10 @@ export const reloadDataSourceFactory = ( } await Promise.allSettled(allAsyncLoadings); + + // 所有的初始化请求都结束之后,调用钩子函数 + + if (dataHandler) { + dataHandler(dataSourceMap); + } }; diff --git a/packages/datasource-engine/src/helpers/index.ts b/packages/datasource-engine/src/helpers/index.ts index 1b2726566..6202e61b2 100644 --- a/packages/datasource-engine/src/helpers/index.ts +++ b/packages/datasource-engine/src/helpers/index.ts @@ -1,17 +1,33 @@ import { DataHandler, + RequestHandler, + RequestHandlersMap, + RuntimeDataSourceConfig, RuntimeOptionsConfig, + UrlParamsHandler, WillFetch, } from '@ali/lowcode-types'; // 默认的 dataSourceItem 的 dataHandler -export const defaultDataHandler: DataHandler = async (response: { - data: T; -}) => response.data; +export const defaultDataHandler: DataHandler = async (response: { data: T }) => response.data; // 默认的 dataSourceItem 的 willFetch -export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => - options; +export const defaultWillFetch: WillFetch = (options: RuntimeOptionsConfig) => options; // 默认的 dataSourceItem 的 shouldFetch export const defaultShouldFetch = () => true; + +type GetRequestHandler = ( + ds: RuntimeDataSourceConfig, + requestHandlersMap: RequestHandlersMap<{ data: T }>, +) => RequestHandler<{ data: T }> | UrlParamsHandler; + +// 从当前 dataSourceItem 中获取 requestHandler +export const getRequestHandler: GetRequestHandler = (ds, requestHandlersMap) => { + if (ds.type === 'custom') { + // 自定义类型处理 + return (ds.requestHandler as unknown) as RequestHandler<{ data: unknown }>; // 理论上这里应该是能强转的,就算为空,应该在 request 请求的时候触发失败 + } + // type 协议默认值 fetch + return requestHandlersMap[ds.type || 'fetch']; +}; diff --git a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts index 4adcf1f82..15d4dc5d8 100644 --- a/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/interpret/DataSourceEngineFactory.ts @@ -9,11 +9,12 @@ import { RuntimeDataSource, RuntimeDataSourceConfig, } from '@ali/lowcode-types'; +import { getRequestHandler } from '../helpers'; -// TODO: requestConfig mtop 默认的请求 config 怎么处理? /** * @param dataSource * @param context + * @param extraConfig: { requestHandlersMap } */ export default ( @@ -25,22 +26,11 @@ export default ( ) => { const { requestHandlersMap } = extraConfig; - const runtimeDataSource: RuntimeDataSource = adapt2Runtime( - dataSource, - context, - ); + const runtimeDataSource: RuntimeDataSource = adapt2Runtime(dataSource, context); const dataSourceMap = runtimeDataSource.list.reduce( - ( - prev: Record, - current: RuntimeDataSourceConfig, - ) => { - prev[current.id] = new RuntimeDataSourceItem( - current, - // type 协议默认值 fetch - requestHandlersMap[current.type || 'fetch'], - context, - ); + (prev: Record, current: RuntimeDataSourceConfig) => { + prev[current.id] = new RuntimeDataSourceItem(current, getRequestHandler(current, requestHandlersMap), context); return prev; }, {}, @@ -48,6 +38,6 @@ export default ( return { dataSourceMap, - reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap), + reloadDataSource: reloadDataSourceFactory(runtimeDataSource, dataSourceMap, runtimeDataSource.dataHandler), }; }; diff --git a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts index d504054c3..e1cdead62 100644 --- a/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts +++ b/packages/datasource-engine/src/runtime/RuntimeDataSourceEngineFactory.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/indent */ -/* eslint-disable no-nested-ternary */ import { IRuntimeDataSource, IDataSourceRuntimeContext, @@ -10,17 +9,14 @@ import { import { RuntimeDataSourceItem } from '../core'; import { reloadDataSourceFactory } from '../core/reloadDataSourceFactory'; -import { - defaultDataHandler, - defaultShouldFetch, - defaultWillFetch, -} from '../helpers'; +import { defaultDataHandler, defaultShouldFetch, defaultWillFetch, getRequestHandler } from '../helpers'; -// TODO: requestConfig mtop 默认的请求 config 怎么处理? /** * @param dataSource * @param context + * @param extraConfig: { requestHandlersMap } */ + export default ( dataSource: RuntimeDataSource, context: IDataSourceRuntimeContext, @@ -34,28 +30,19 @@ export default ( dataSource.list.forEach(ds => { ds.isInit = ds.isInit || true; ds.isSync = ds.isSync || false; + // eslint-disable-next-line no-nested-ternary ds.shouldFetch = !ds.shouldFetch ? defaultShouldFetch : typeof ds.shouldFetch === 'function' ? ds.shouldFetch.bind(context) : ds.shouldFetch; ds.willFetch = ds.willFetch ? ds.willFetch.bind(context) : defaultWillFetch; - ds.dataHandler = ds.dataHandler - ? ds.dataHandler.bind(context) - : defaultDataHandler; + ds.dataHandler = ds.dataHandler ? ds.dataHandler.bind(context) : defaultDataHandler; }); const dataSourceMap = dataSource.list.reduce( - ( - prev: Record, - current: RuntimeDataSourceConfig, - ) => { - prev[current.id] = new RuntimeDataSourceItem( - current, - // type 协议默认值 fetch - requestHandlersMap[current.type || 'fetch'], - context, - ); + (prev: Record, current: RuntimeDataSourceConfig) => { + prev[current.id] = new RuntimeDataSourceItem(current, getRequestHandler(current, requestHandlersMap), context); return prev; }, {}, @@ -63,6 +50,6 @@ export default ( return { dataSourceMap, - reloadDataSource: reloadDataSourceFactory(dataSource, dataSourceMap), + reloadDataSource: reloadDataSourceFactory(dataSource, dataSourceMap, dataSource.dataHandler), }; }; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md new file mode 100644 index 000000000..355853ddd --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/README.md @@ -0,0 +1,3 @@ +# 关于此场景 + +数据源的 type 可以是 `custom` 类型的, 此时需要提供 `requestHandler` 给数据源 diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts new file mode 100644 index 000000000..fc46c3459 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-runtime.ts @@ -0,0 +1,67 @@ +import { RuntimeDataSource } from '@ali/lowcode-types'; + +// 这里仅仅是数据源部分的: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const dataSource: RuntimeDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: options => { + return new Promise(res => { + setTimeout(() => { + // test return data + res({ + data: { + id: 9527, + name: 'Alice', + uri: options.uri, + }, + }); + }, 1000); + }); + }, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/user.json', + }; + }, + }, + { + id: 'orders', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: () => { + return new Promise((res, rej) => { + setTimeout(() => { + // test return data + rej(new Error('test error')); + }, 1000); + }); + }, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + userId: this.state.user.id, + }, + }; + }, + }, + { + // 这个 api 是假的,调不通的,当前场景是故意需要报错的 + id: 'members', + isInit: true, + type: 'custom', + isSync: true, + options() { + return { + uri: 'https://mocks.alibaba-inc.com/members.json', + }; + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts new file mode 100644 index 000000000..0a71914ca --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_datasource-schema.ts @@ -0,0 +1,67 @@ +import { InterpretDataSource } from '@ali/lowcode-types'; + +// 这里仅仅是数据源部分的 schema: +// @see: https://yuque.antfin-inc.com/mo/spec/spec-low-code-building-schema#XMeF5 +export const DATA_SOURCE_SCHEMA: InterpretDataSource = { + list: [ + { + id: 'user', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: { + type: 'JSFunction', + value: `function(options){ + return new Promise(res => { + setTimeout(() => { + // test return data + res({ + data: { + id: 9527, + name: 'Alice', + uri: options.uri, + } + }); + }, 1000); + }); + }`, + }, + options: { + uri: 'https://mocks.alibaba-inc.com/user.json', + }, + }, + { + id: 'orders', + isInit: true, + type: 'custom', + isSync: true, + requestHandler: { + type: 'JSFunction', + value: `function(options){ + return new Promise((res, rej) => { + setTimeout(() => { + // test return data + return rej(new Error('test error')); + }, 1000); + }); + }`, + }, + options: { + uri: 'https://mocks.alibaba-inc.com/orders.json', + params: { + type: 'JSExpression', + value: '{ userId: this.state.user.id }', + }, + }, + }, + { + id: 'members', + isInit: true, + type: 'custom', + isSync: true, + options: { + uri: 'https://mocks.alibaba-inc.com/members.json', + }, + }, + ], +}; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts new file mode 100644 index 000000000..1fe39c61e --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/_macro-normal.ts @@ -0,0 +1,90 @@ +import { + InterpretDataSource, + IDataSourceEngine, + IDataSourceRuntimeContext, + RuntimeDataSource, + RuntimeDataSourceStatus, +} from '@ali/lowcode-types'; +import sinon from 'sinon'; + +import { bindRuntimeContext, MockContext } from '../../_helpers'; + +import type { ExecutionContext, Macro } from 'ava'; +import type { SinonFakeTimers } from 'sinon'; + +export const normalScene: Macro<[ + { + create: ( + dataSource: any, + ctx: IDataSourceRuntimeContext, + options?: any + ) => IDataSourceEngine; + dataSource: RuntimeDataSource | InterpretDataSource; + } +]> = async ( + t: ExecutionContext<{ clock: SinonFakeTimers }>, + { create, dataSource }, +) => { + const { clock } = t.context; + + const USER_DATA = { + id: 9527, + name: 'Alice', + uri: 'https://mocks.alibaba-inc.com/user.json' + }; + const ERROR_MSG = 'test error'; + + + const context = new MockContext>({}, (ctx) => create(bindRuntimeContext(dataSource, ctx), ctx)); + + const setState = sinon.spy(context, 'setState'); + + // 一开始应该是初始状态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Initial); + t.is(context.dataSourceMap.members.status, RuntimeDataSourceStatus.Initial); + + const loading = context.reloadDataSource(); + + await clock.tickAsync(50); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(1050); + + // 中间应该有 loading 态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Loading); + + await clock.tickAsync(1050); + + // members 因为没有 requestHandler 直接就挂了 + t.is(context.dataSourceMap.members.status, RuntimeDataSourceStatus.Error) + + await Promise.all([clock.runAllAsync(), loading]); + + // 最后 user 应该成功了,loaded + t.is(context.dataSourceMap.user.status, RuntimeDataSourceStatus.Loaded); + // 最后 orders 应该失败了,error 状态 + t.is(context.dataSourceMap.orders.status, RuntimeDataSourceStatus.Error); + + // 检查数据源的数据 + t.deepEqual(context.dataSourceMap.user.data, USER_DATA); + t.is(context.dataSourceMap.user.error, undefined); + t.deepEqual(context.dataSourceMap.orders.data, undefined); + t.not(context.dataSourceMap.orders.error, undefined); + t.deepEqual(context.dataSourceMap.members.data, undefined); + t.not(context.dataSourceMap.members.error, undefined); + t.regex(context.dataSourceMap.orders.error!.message, new RegExp(ERROR_MSG)); + t.regex(context.dataSourceMap.members.error!.message, new RegExp('no custom handler provide')); + + + + // 检查状态数据 + t.assert(setState.calledOnce); + t.deepEqual(context.state.user, USER_DATA); + t.is(context.state.orders, undefined); + t.is(context.state.members, undefined); +}; + +normalScene.title = (providedTitle) => providedTitle || 'normal scene'; diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts new file mode 100644 index 000000000..9dac84e8d --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-interpret.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/interpret'; + +import { DATA_SOURCE_SCHEMA } from './_datasource-schema'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource: DATA_SOURCE_SCHEMA, +}); diff --git a/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts new file mode 100644 index 000000000..761979c30 --- /dev/null +++ b/packages/datasource-engine/test/scenes/p0-0-custom-request-handlers/normal-runtime.test.ts @@ -0,0 +1,20 @@ +import test, { ExecutionContext } from 'ava'; +import sinon, { SinonFakeTimers } from 'sinon'; + +import { create } from '../../../src/runtime'; + +import { dataSource } from './_datasource-runtime'; +import { normalScene } from './_macro-normal'; + +test.before((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock = sinon.useFakeTimers(); +}); + +test.after((t: ExecutionContext<{ clock: SinonFakeTimers }>) => { + t.context.clock.restore(); +}); + +test(normalScene, { + create, + dataSource, +}); diff --git a/packages/types/src/data-source-handlers.ts b/packages/types/src/data-source-handlers.ts index 2e054b4e8..4ee7f6a0b 100644 --- a/packages/types/src/data-source-handlers.ts +++ b/packages/types/src/data-source-handlers.ts @@ -5,11 +5,17 @@ import { export type RequestHandler = ( options: RuntimeOptionsConfig, - context: IDataSourceRuntimeContext + context?: IDataSourceRuntimeContext, ) => Promise; export type UrlParamsHandler = ( - context?: IDataSourceRuntimeContext + context?: IDataSourceRuntimeContext, ) => Promise; export type RequestHandlersMap = Record>; + +// 仅在 type=custom 的时候生效的 handler +export type CustomRequestHandler = ( + options: RuntimeOptionsConfig, + context?: IDataSourceRuntimeContext, +) => Promise; diff --git a/packages/types/src/data-source-runtime.ts b/packages/types/src/data-source-runtime.ts index 9a89e39aa..878039340 100644 --- a/packages/types/src/data-source-runtime.ts +++ b/packages/types/src/data-source-runtime.ts @@ -1,10 +1,10 @@ import { IRuntimeDataSource } from './data-source'; +import { CustomRequestHandler } from './data-source-handlers'; // 先定义运行模式的类型 export interface RuntimeDataSource { list: RuntimeDataSourceConfig[]; - // TODO: dataMap 格式不对要处理 - dataHandler?: (dataMap: DataSourceMap) => void; + dataHandler?: (dataSourceMap: DataSourceMap) => void; } export type DataSourceMap = Record; @@ -16,7 +16,7 @@ export interface RuntimeDataSourceConfig { type?: string; willFetch?: WillFetch; shouldFetch?: () => boolean; - requestHandler?: () => void; // TODO: 待定 + requestHandler?: CustomRequestHandler; dataHandler?: DataHandler; errorHandler?: ErrorHandler; options?: RuntimeOptions;