From 97b41d8e29b14aac1a2f5e9b2fc8bbeb1f8a9441 Mon Sep 17 00:00:00 2001 From: Zacherl Date: Mon, 11 Mar 2024 08:42:34 +0100 Subject: [PATCH 1/3] feat(signals): Allow intersecting stale results When the "intersectStaleData" flag is passed, the returned data of the queries will also be intersected if every query has data. --- query/src/lib/signals.ts | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/query/src/lib/signals.ts b/query/src/lib/signals.ts index 3412177..128456e 100644 --- a/query/src/lib/signals.ts +++ b/query/src/lib/signals.ts @@ -26,7 +26,8 @@ type UnifiedTypes = T extends Array>> * * This function is used to merge multiple signal queries into one. * It will return a new base query result that will merge the results of all the queries. - * Note that it should be used inside injection context + * Note that it should be used inside injection context. + * If you pass the 'intersectStaleData' flag, it will also intersect unsuccessful result if data for all queries is present. * * @example * @@ -35,7 +36,7 @@ type UnifiedTypes = T extends Array>> * posts: posts.result$, * }, ({ todos, posts }) => { * return todos + posts; - * }) + * }); * * * @example @@ -49,6 +50,16 @@ type UnifiedTypes = T extends Array>> * return todoOne.title + todoTwo.title; * } * ); + * + * + * @example + * + * const query = intersetResults({ + * todos: todos.result$, + * posts: posts.result$, + * }, ({ todos, posts }) => { + * return todos + posts; + * }, { intersectStaleData: true }); */ export function intersectResults< T extends @@ -58,10 +69,17 @@ export function intersectResults< >( signals: T, mapFn: (values: UnifiedTypes) => R, + options?: { intersectStaleData: boolean } ): Signal & { all: T }> { const isArray = Array.isArray(signals); const toArray = isArray ? signals : Object.values(signals); const refetch = () => Promise.all(toArray.map(v => v().refetch())); + const intersectData = isArray + ? () => toArray.map((r) => r().data) as UnifiedTypes + : () => Object.entries(signals).reduce((acc, [key, value]) => { + acc[key as keyof UnifiedTypes] = value().data; + return acc; + }, {} as UnifiedTypes) return computed(() => { const mappedResult = { @@ -76,20 +94,8 @@ export function intersectResults< refetch, } as unknown as QueryObserverResult & { all: T }; - if (mappedResult.isSuccess) { - if (isArray) { - mappedResult.data = mapFn( - toArray.map((r) => r().data) as UnifiedTypes, - ); - } else { - const data = Object.entries(signals).reduce((acc, [key, value]) => { - acc[key as keyof UnifiedTypes] = value().data; - - return acc; - }, {} as UnifiedTypes); - - mappedResult.data = mapFn(data); - } + if (mappedResult.isSuccess || (options?.intersectStaleData && toArray.every((v) => !!v().data))) { + mappedResult.data = mapFn(intersectData()); } return mappedResult; From 51749ab8525715b82f48afe6e3f8d991e70ca1b3 Mon Sep 17 00:00:00 2001 From: Zacherl Date: Mon, 11 Mar 2024 08:50:58 +0100 Subject: [PATCH 2/3] feat(operators): Allow intersecting stale results When the "intersectStaleData" flag is passed, the returned data of the queries will also be intersected if every query has data. --- query/src/lib/operators.ts | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/query/src/lib/operators.ts b/query/src/lib/operators.ts index d4af75e..3a4db26 100644 --- a/query/src/lib/operators.ts +++ b/query/src/lib/operators.ts @@ -118,6 +118,7 @@ type UnifiedTypes = T extends Array> * * This operator is used to merge multiple queries into one. * It will return a new base query result that will merge the results of all the queries. + * If you pass the 'intersectStaleData' flag, it will also intersect unsuccessful result in case data for all queries is present. * * @example * @@ -128,13 +129,25 @@ type UnifiedTypes = T extends Array> * intersectResults$(({ todos, posts }) => { * return { ... } * }) - * ) + * ); + * * @example * * const query = combineLatest([todos.result$, posts.result$]).pipe( * intersectResults$(([todos, posts]) => { * return { ... } * }) + * ); + * + * @example + * + * const query = combineLatest({ + * todos: todos.result$, + * posts: posts.result$, + * }).pipe( + * intersectResults$(({ todos, posts }) => { + * return { ... } + * }, { intersectStaleData: true }); * ) */ export function intersectResults$< @@ -144,6 +157,7 @@ export function intersectResults$< R, >( mapFn: (values: UnifiedTypes) => R, + options?: { intersectStaleData: boolean }, ): OperatorFunction & { all: T }> { return map((values) => { const isArray = Array.isArray(values); @@ -162,20 +176,14 @@ export function intersectResults$< refetch, } as unknown as QueryObserverResult & { all: T }; - if (mappedResult.isSuccess) { - if (isArray) { - mappedResult.data = mapFn( - toArray.map((r) => r.data) as UnifiedTypes, - ); - } else { - const data = Object.entries(values).reduce((acc, [key, value]) => { + if (mappedResult.isSuccess || (options?.intersectStaleData && toArray.every((r) => !!r.data))) { + const data = isArray + ? toArray.map((r) => r.data) as UnifiedTypes + : Object.entries(values).reduce((acc, [key, value]) => { acc[key as keyof UnifiedTypes] = value.data; - return acc; }, {} as UnifiedTypes); - - mappedResult.data = mapFn(data); - } + mappedResult.data = mapFn(data); } return mappedResult; From 989832292aad2c3401780f69ae9b1f4a94658e9c Mon Sep 17 00:00:00 2001 From: Zacherl Date: Mon, 11 Mar 2024 08:51:42 +0100 Subject: [PATCH 3/3] Update signals.ts --- query/src/lib/signals.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/query/src/lib/signals.ts b/query/src/lib/signals.ts index 128456e..9667d79 100644 --- a/query/src/lib/signals.ts +++ b/query/src/lib/signals.ts @@ -27,7 +27,7 @@ type UnifiedTypes = T extends Array>> * This function is used to merge multiple signal queries into one. * It will return a new base query result that will merge the results of all the queries. * Note that it should be used inside injection context. - * If you pass the 'intersectStaleData' flag, it will also intersect unsuccessful result if data for all queries is present. + * If you pass the 'intersectStaleData' flag, it will also intersect unsuccessful result in case data for all queries is present. * * @example * @@ -38,7 +38,6 @@ type UnifiedTypes = T extends Array>> * return todos + posts; * }); * - * * @example * * const query = intersectResults( @@ -51,7 +50,6 @@ type UnifiedTypes = T extends Array>> * } * ); * - * * @example * * const query = intersetResults({ @@ -79,7 +77,7 @@ export function intersectResults< : () => Object.entries(signals).reduce((acc, [key, value]) => { acc[key as keyof UnifiedTypes] = value().data; return acc; - }, {} as UnifiedTypes) + }, {} as UnifiedTypes); return computed(() => { const mappedResult = {