-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(utils): 添加批量更新相关的一个数据转换工具函数 normBulkUpdate
在批量接口使用 PUT 请求时,后端 response 上往往不会把所有更新的对象一 一罗列,而是以 `{ xxIds: Id[], ...updatedFields }` 的压缩形式呈现。这 样的数据是没办法直接更新到缓存层(RDB)的。 这里添加的 normBulkUpdate 函数可以用来将后端返回的这种压缩形式转换为缓 存层能接收的形式。如: ``` normBulkUpdate({ taskIds: ['123', '456'], isArchived: true, updated: '2018-08-21T05:43:10.000Z' }, 'taskIds', '_id') ``` 会得到 ``` [ {_id: '123', isArchived: true, updated: '2018-08-21T05:43:10.000Z'}, {_id: '456', isArchived: true, updated: '2018-08-21T05:43:10.000Z'} ] ``` 更多边界条件的行为定义,请见相应测试。
- Loading branch information
Showing
7 changed files
with
137 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Omit } from './internalTypes' | ||
|
||
/** | ||
* 从类型 T(如 `{ _taskId: TaskId[] }`)上获得给定字段 K | ||
* (如 `_taskId`)对应的数组的元素类型(如 `TaskId`)。如果 | ||
* `T[K]` 不是数组类型,则放弃类型推断,返回 any。 | ||
*/ | ||
export type ArrayPropertyElement<T, K extends keyof T> = T[K] extends (infer U)[] | ||
? U | ||
: any | ||
|
||
/** | ||
* 生成的结果类型,替换了类型 T(如 `{ taskIds: TaskId[], isArchived: boolean }`) | ||
* 上的字段 K(如 `taskIds`)为字段 S(如 `_id`),而字段 S | ||
* 对应的值类型则是字段 K 对应的数组值的元素类型(如 `TaskId`)。 | ||
* 如果 `T[K]` 不是数组类型,则字段 S(如 `_id`)的类型将是 any。 | ||
*/ | ||
export type NormBulkUpdateResult<T, K extends keyof T, S extends string> = Array< | ||
Record<S, ArrayPropertyElement<T, K>> & Omit<T, K> | ||
> | ||
|
||
/** | ||
* 将批量 PUT 的返回结果转变为可以直接被缓存层消费的数据。 | ||
* 用法如:有 response$ 的元素形状为 | ||
* `{ taskIds: TaskId[], isArchived: boolean, updated: string }` | ||
* 则调用 `normBulkUpdate(response$, 'taskIds', '_id')` 将推出元素形状为 | ||
* `{ _id: TaskId, isArchived: boolean, updated: string }[]` | ||
* 的数据。 | ||
*/ | ||
export function normBulkUpdate< | ||
T extends {}, | ||
K extends keyof T, | ||
U extends string | ||
>( | ||
response: T, | ||
responseIdsField: K, | ||
entityIdField: U | ||
): NormBulkUpdateResult<T, K, U> { | ||
const { [responseIdsField]: ids, ...rest } = response as any | ||
|
||
return ids | ||
? (ids as Array<ArrayPropertyElement<T, K>>).map((id) => { | ||
const existingValue = rest[entityIdField] | ||
if (existingValue != null && existingValue !== id) { | ||
throw new Error( | ||
`normBulkUpdate: specified key-value pair(${entityIdField}-${id})` + | ||
` is conflicting to an existing one(${entityIdField}-${existingValue}).)` | ||
) | ||
} | ||
return { | ||
...rest, | ||
[entityIdField]: id | ||
} | ||
}) | ||
: [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,4 @@ import './mock' | |
import './apis' | ||
import './sockets' | ||
import './net' | ||
import './utils/index' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { expect } from 'chai' | ||
import { it, describe } from 'tman' | ||
import { TaskId } from 'teambition-types' | ||
import { normBulkUpdate } from '../../src/utils' | ||
|
||
describe('httpclient utils spec', () => { | ||
it(`${normBulkUpdate.name} should produce [] when responseIdsField is undefined`, () => { | ||
expect(normBulkUpdate( | ||
{ | ||
taskIds: ['123', '456'], | ||
isArchived: true, | ||
updated: '2018-08-21T05:43:10.000Z' | ||
} as any, | ||
'_taskIds', | ||
'_id' | ||
)).to.deep.equal([]) | ||
}) | ||
|
||
it(`${normBulkUpdate.name} should produce [] when responseIdsField is empty`, () => { | ||
expect(normBulkUpdate( | ||
{ | ||
taskIds: [], | ||
isArchived: true, | ||
updated: '2018-08-21T05:43:10.000Z' | ||
}, | ||
'taskIds', | ||
'_id' | ||
)).to.deep.equal([]) | ||
}) | ||
|
||
it(`${normBulkUpdate.name} should work when responseIdsField and entityIdField are the same`, () => { | ||
expect(normBulkUpdate( | ||
{ | ||
_id: ['123' as TaskId, '456' as TaskId], | ||
isArchived: true, | ||
updated: '2018-08-21T05:43:10.000Z' | ||
}, | ||
'_id', | ||
'_id' | ||
)).to.deep.equal([ | ||
{ _id: '123', isArchived: true, updated: '2018-08-21T05:43:10.000Z' }, | ||
{ _id: '456', isArchived: true, updated: '2018-08-21T05:43:10.000Z' } | ||
]) | ||
}) | ||
|
||
it(`${normBulkUpdate.name} should work when responseIdsField and entityIdField are different`, () => { | ||
expect(normBulkUpdate( | ||
{ | ||
taskIds: ['123' as TaskId, '456' as TaskId], | ||
isArchived: true, | ||
updated: '2018-08-21T05:43:10.000Z' | ||
}, | ||
'taskIds', | ||
'_id' | ||
)).to.deep.equal([ | ||
{ _id: '123', isArchived: true, updated: '2018-08-21T05:43:10.000Z' }, | ||
{ _id: '456', isArchived: true, updated: '2018-08-21T05:43:10.000Z' } | ||
]) | ||
}) | ||
|
||
it(`${normBulkUpdate.name} should throw when property conflict happends`, () => { | ||
expect(() => normBulkUpdate( | ||
{ | ||
taskIds: ['123', '456'], | ||
cid: '789', // 语义为 child id | ||
isArchived: true, | ||
updated: '2018-08-21T05:43:10.000Z' | ||
}, | ||
'taskIds', | ||
'cid' // 语义为 backbone 的 client id | ||
)).to.throw() | ||
}) | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './httpclient' |