Skip to content

Commit

Permalink
feat: add toListLoader utility and deprecate toListDataLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
vanya2h committed Sep 12, 2022
1 parent 63d0298 commit 4a244d4
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ npm-debug.*
.classpath
.project
.settings

.yarn-error.log
1 change: 1 addition & 0 deletions packages/cache/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
byKeyWithDefaultFactory,
byKey,
toListDataLoader,
toListLoader,
} from "./key"
export { toWrapped, toCache } from "./utils"
export { Memo, MemoImpl } from "./memo"
Expand Down
32 changes: 31 additions & 1 deletion packages/cache/src/key.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Map as IM } from "immutable"
import waitForExpect from "wait-for-expect"
import { createFulfilledWrapped, pendingWrapped, Rejected, Wrapped } from "@rixio/wrapped"
import { waitFor } from "@testing-library/react"
import { KeyCacheImpl, toListDataLoader } from "./key"
import { KeyCacheImpl, toListLoader, toListDataLoader } from "./key"
import { createAddKeyEvent, createErrorKeyEvent, KeyEvent } from "./domain"
import { CacheState, createFulfilledCache } from "./index"

Expand Down Expand Up @@ -123,3 +123,33 @@ describe("KeyCacheImpl", () => {
})
})
})

describe("toListLoader", () => {
it("should resolve all values", async () => {
const loader = toListLoader<string, string, undefined>(x => Promise.resolve(x + "1"), undefined)
const result = await loader(["hello", "world"])
expect(result).toStrictEqual([
["hello", "hello1"],
["world", "world1"],
])
})

it("should return default value if one element fails", async () => {
const logger = jest.fn()
const err = new Error("My error")
const loader = toListLoader<string, string, undefined>(
x => {
if (x === "hello") return Promise.reject(err)
return Promise.resolve(x + "1")
},
undefined,
logger
)
const result = await loader(["hello", "world"])
expect(result).toStrictEqual([
["hello", undefined],
["world", "world1"],
])
expect(logger.mock.calls[0]).toEqual(["hello", err])
})
})
27 changes: 27 additions & 0 deletions packages/cache/src/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,37 @@ export type DataLoader<K, V> = (key: K) => Promise<V>

export type ListDataLoader<K, V> = (keys: K[]) => Promise<[K, V][]>

/**
* @deprecated please use toListLoader
* since it can handle errors and doesn't trigger fail of whole chain
*/

export function toListDataLoader<K, V>(loader: DataLoader<K, V>): ListDataLoader<K, V> {
return ids => Promise.all(ids.map(id => loader(id).then(v => [id, v] as [K, V])))
}

/**
* Utility to conver your single-loader to list loader
*/

export function toListLoader<K, V, J>(
loader: DataLoader<K, V>,
defaultValue: J,
onError?: (id: K, error: unknown) => void
): ListDataLoader<K, V | J> {
return ids =>
Promise.all(
ids.map(id =>
loader(id)
.then(v => [id, v] as [K, V])
.catch(err => {
onError?.(id, err)
return [id, defaultValue] as [K, J]
})
)
)
}

export interface KeyCache<K, V> {
get(key: K, force?: boolean): Promise<V>
set(key: K, value: V): void
Expand Down

0 comments on commit 4a244d4

Please sign in to comment.