Skip to content

Commit

Permalink
fix: new query deep signals
Browse files Browse the repository at this point in the history
  • Loading branch information
SaulMoro committed Feb 29, 2024
1 parent dfca2a8 commit 87b4b45
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 43 deletions.
42 changes: 32 additions & 10 deletions projects/ngrx-rtk-query/src/lib/build-hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
isFetching,
isLoading,
isSuccess,
// Deep signals required init in undefined atleast
endpointName: currentState.endpointName,
error: currentState.error,
fulfilledTimeStamp: currentState.fulfilledTimeStamp,
originalArgs: currentState.originalArgs,
requestId: currentState.requestId,
startedTimeStamp: currentState.startedTimeStamp,
} as UseQueryStateDefaultResult<any>;
}

Expand Down Expand Up @@ -370,8 +377,9 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
lastValue = selectDefaultResult(getState());
return currentState();
});
const deepSignal = toDeepSignal(currentState);

return currentState;
return deepSignal as any;
};

return {
Expand All @@ -385,11 +393,10 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
skip: arg() === UNINITIALIZED_VALUE,
}));
const queryStateResults = useQueryState(arg, subscriptionOptions);
const queryState = computed(() => ({ ...queryStateResults(), lastArg: arg() }));
const deepSignal = toDeepSignal(queryState);
Object.assign(deepSignal, { fetch: trigger });
Object.assign(queryStateResults, { fetch: trigger });
Object.assign(queryStateResults, { lastArg: arg });

return deepSignal as any;
return queryStateResults as any;
},
useQuery(arg, options) {
const querySubscriptionResults = useQuerySubscription(arg, options);
Expand All @@ -400,10 +407,9 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
return { selectFromResult, ...options };
});
const queryStateResults = useQueryState(arg, subscriptionOptions);
const queryState = computed(() => ({ ...queryStateResults(), ...querySubscriptionResults }));
const deepSignal = toDeepSignal(queryState);
Object.assign(queryStateResults, querySubscriptionResults);

return deepSignal as any;
return queryStateResults as any;
},
selector: select as QuerySelector<any>,
};
Expand Down Expand Up @@ -433,8 +439,22 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
return promise;
};

const fixedSelect: typeof select = (args) => (state) => {
const currentState = select(args)(state);
return {
...currentState,
// Deep signals required init in undefined atleast
data: currentState.data,
endpointName: currentState.endpointName,
error: currentState.error,
fulfilledTimeStamp: currentState.fulfilledTimeStamp,
requestId: currentState.requestId,
startedTimeStamp: currentState.startedTimeStamp,
} as any;
};

const requestId = computed(() => promiseRef()?.requestId);
const selectDefaultResult = (requestId?: string) => select({ fixedCacheKey, requestId });
const selectDefaultResult = (requestId?: string) => fixedSelect({ fixedCacheKey, requestId });
const mutationSelector = (
requestId?: string,
): MemoizedSelector<RootState<Definitions, any, any>, any, DefaultProjectorFn<any>> =>
Expand Down Expand Up @@ -462,9 +482,11 @@ export function buildHooks<Definitions extends EndpointDefinitions>({
}
};

const finalState = computed(() => ({ ...currentState()(), originalArgs: originalArgs(), reset }));
const finalState = computed(() => currentState()());
const deepSignal = toDeepSignal(finalState);
Object.assign(deepSignal, { dispatch: triggerMutation });
Object.assign(deepSignal, { originalArgs });
Object.assign(deepSignal, { reset });

return deepSignal as any;
};
Expand Down
19 changes: 11 additions & 8 deletions projects/ngrx-rtk-query/src/lib/types/hooks-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export type UseQuery<D extends QueryDefinition<any, any, any, any>> = <
>(
arg: Signal<QueryArgFrom<D> | SkipToken> | QueryArgFrom<D> | SkipToken,
options?: UseQueryOptions<D, R> | Signal<UseQueryOptions<D, R>>,
) => DeepSignal<UseQueryHookResult<D, R>>;
) => UseQueryHookResult<D, R>;

export type TypedUseQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseQuery<
QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>
Expand Down Expand Up @@ -238,8 +238,9 @@ export type UseLazyQuery<D extends QueryDefinition<any, any, any, any>> = <
R extends Record<string, any> = UseQueryStateDefaultResult<D>,
>(
options?: UseLazyQueryOptions<D, R> | Signal<UseLazyQueryOptions<D, R>>,
) => DeepSignal<UseQueryStateResult<D, R> & { lastArg: QueryArgFrom<D> }> & {
) => UseQueryStateResult<D, R> & {
fetch: LazyQueryTrigger<D>;
lastArg: Signal<QueryArgFrom<D>>;
};

export type TypedUseLazyQuery<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseLazyQuery<
Expand Down Expand Up @@ -304,7 +305,7 @@ export type UseQueryState<D extends QueryDefinition<any, any, any, any>> = <
>(
arg: Signal<QueryArgFrom<D> | SkipToken> | QueryArgFrom<D> | SkipToken,
options?: UseQueryStateOptions<D, R> | Signal<UseQueryStateOptions<D, R>>,
) => Signal<UseQueryStateResult<D, R>>;
) => UseQueryStateResult<D, R>;

export type UseQueryStateOptions<D extends QueryDefinition<any, any, any, any>, R extends Record<string, any>> = {
/**
Expand Down Expand Up @@ -349,7 +350,7 @@ export type UseQueryStateOptions<D extends QueryDefinition<any, any, any, any>,
selectFromResult?: QueryStateSelector<R, D>;
};

export type UseQueryStateResult<_ extends QueryDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R>;
export type UseQueryStateResult<_ extends QueryDefinition<any, any, any, any>, R> = DeepSignal<TSHelpersNoInfer<R>>;

/**
* Helper type to manually type the result
Expand All @@ -360,7 +361,7 @@ export type TypedUseQueryStateResult<
QueryArg,
BaseQuery extends BaseQueryFn,
R = UseQueryStateDefaultResult<QueryDefinition<QueryArg, BaseQuery, string, ResultType, string>>,
> = TSHelpersNoInfer<R>;
> = DeepSignal<TSHelpersNoInfer<R>>;

type UseQueryStateBaseResult<D extends QueryDefinition<any, any, any, any>> = QuerySubState<D> & {
/**
Expand Down Expand Up @@ -429,8 +430,10 @@ export type UseMutationStateOptions<D extends MutationDefinition<any, any, any,
fixedCacheKey?: string;
};

export type UseMutationStateResult<D extends MutationDefinition<any, any, any, any>, R> = TSHelpersNoInfer<R> & {
originalArgs?: QueryArgFrom<D>;
export type UseMutationStateResult<D extends MutationDefinition<any, any, any, any>, R> = DeepSignal<
TSHelpersNoInfer<R>
> & {
originalArgs: Signal<QueryArgFrom<D> | undefined>;
/**
* Resets the hook state to it's initial `uninitialized` state.
* This will also remove the last result from the cache.
Expand Down Expand Up @@ -464,7 +467,7 @@ export type UseMutation<D extends MutationDefinition<any, any, any, any>> = <
R extends Record<string, any> = MutationResultSelectorResult<D>,
>(
options?: UseMutationStateOptions<D, R>,
) => DeepSignal<UseMutationStateResult<D, R>> & { dispatch: MutationTrigger<D> };
) => UseMutationStateResult<D, R> & { dispatch: MutationTrigger<D> };

export type TypedUseMutation<ResultType, QueryArg, BaseQuery extends BaseQueryFn> = UseMutation<
MutationDefinition<QueryArg, BaseQuery, string, ResultType, string>
Expand Down
10 changes: 5 additions & 5 deletions projects/ngrx-rtk-query/src/lib/utils/deep-signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export interface Signal<T> extends NgSignal<T> {
}

export type DeepSignal<T> = Signal<T> &
(IsKnownRecord<T> extends true
? Readonly<{
[K in keyof T]: IsKnownRecord<T[K]> extends true ? DeepSignal<T[K]> : Signal<T[K]>;
}>
: unknown);
Readonly<
Required<{
[K in keyof T]: IsKnownRecord<T[K]> extends true ? DeepSignal<T[K]> : Signal<T[K]>;
}>
>;

export function toDeepSignal<T>(signal: Signal<T>): DeepSignal<T> {
const value = untracked(() => signal());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { nanoid } from '@reduxjs/toolkit';
<button class="btn-outline btn-primary" [disabled]="increment.isLoading()" (click)="increment.dispatch(1)">
+
</button>
<span class="text-3xl font-bold">{{ countQuery().data?.count || 0 }}</span>
<span class="text-3xl font-bold">{{ countQuery.data()?.count || 0 }}</span>
<button class="btn-outline btn-primary" (click)="decrement.dispatch(1)">-</button>
</div>
<small>Decrease is a optimistic update!</small>
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/counter/counter/counter.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { pollingOptions } from '../utils/polling-options';
+
</button>
<span class="text-3xl font-bold" [class.bg-green-100]="countQuery.isFetching()">{{
countQuery().data?.count || 0
countQuery.data()?.count || 0
}}</span>
<button class="btn-outline btn-primary" [disabled]="decrement.isLoading()" (click)="decrementCounter()">
-
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/lazy/lazy-counter/lazy.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const { getCountById } = counterApiEndpoints;
</form>
<section class="space-y-4">
<h1 class="text-md font-medium">Current id: {{ countLazyQuery().originalArgs || 'Not Started' }}</h1>
<h1 class="text-md font-medium">Current id: {{ countLazyQuery.originalArgs() || 'Not Started' }}</h1>
<app-counter-row [counterData]="countLazyQuery()"></app-counter-row>
</section>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { useLazyGetEpisodeQuery } from '../services';
></div>
<ng-template #episodeName>
<span class="inline-block text-indigo-700 hover:text-indigo-800">
{{ episodeQuery().data?.name }}
{{ episodeQuery.data()?.name }}
</span>
</ng-template>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,31 @@ import { useGetCharactersQuery } from '../services';
<div class="flex items-center justify-between">
<button
class="btn-outline btn-primary w-32"
[disabled]="charactersQuery().isFetching"
(click)="charactersQuery().refetch()"
[disabled]="charactersQuery.isFetching()"
(click)="charactersQuery.refetch()"
>
{{ charactersQuery().isFetching ? 'Fetching...' : 'Refresh' }}
{{ charactersQuery.isFetching() ? 'Fetching...' : 'Refresh' }}
</button>
<div>
<app-paginator
[currentPage]="charactersQuery().originalArgs || 1"
[pages]="charactersQuery().data?.info?.pages"
[currentPage]="charactersQuery.originalArgs() || 1"
[pages]="charactersQuery.data()?.info?.pages"
></app-paginator>
</div>
<button
class="btn-outline btn-primary"
queryParamsHandling="merge"
[disabled]="charactersQuery().isLoading"
[disabled]="charactersQuery.isLoading()"
[routerLink]="['./']"
[queryParams]="{ page: 999 }"
>
Nav to bad page
</button>
</div>
<pre *ngIf="charactersQuery().isError">{{ charactersQuery().error | json }}</pre>
<pre *ngIf="charactersQuery.isError()">{{ charactersQuery.error() | json }}</pre>
<div *ngIf="charactersQuery().data?.results as characters" class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<div *ngIf="charactersQuery.data()?.results as characters" class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
<app-character-card
*ngFor="let character of characters; trackBy: trackByFn"
[character]="character"
Expand Down
14 changes: 7 additions & 7 deletions src/app/features/posts/post-detail/post-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,28 @@ import { useDeletePostMutation, useGetPostQuery, useUpdatePostMutation } from '.
template: `
<section class="space-y-4">
<div>
<h1 class="text-xl font-semibold">{{ postQuery().data?.name }}</h1>
<small *ngIf="postQuery().isFetching">Loading...</small>
<h1 class="text-xl font-semibold">{{ postQuery.data()?.name }}</h1>
<small *ngIf="postQuery.isFetching()">Loading...</small>
</div>
<ng-container *ngIf="!isEditing(); else editionSection">
<div class="flex items-center space-x-4">
<button
class="btn-outline btn-primary"
[disabled]="postQuery().isLoading || deletePostMutation.isLoading() || updatePostMutation.isLoading()"
[disabled]="postQuery.isLoading() || deletePostMutation.isLoading() || updatePostMutation.isLoading()"
(click)="toggleEdit()"
>
{{ updatePostMutation.isLoading() ? 'Updating...' : 'Edit' }}
</button>
<button
class="btn-outline btn-primary"
[disabled]="postQuery().isLoading || deletePostMutation.isLoading()"
[disabled]="postQuery.isLoading() || deletePostMutation.isLoading()"
(click)="deletePost()"
>
{{ deletePostMutation.isLoading() ? 'Deleting...' : 'Delete' }}
</button>
<button class="btn-outline btn-primary" [disabled]="postQuery().isFetching" (click)="postQuery().refetch()">
{{ postQuery().isFetching ? 'Fetching...' : 'Refresh' }}
<button class="btn-outline btn-primary" [disabled]="postQuery.isFetching()" (click)="postQuery.refetch()">
{{ postQuery.isFetching() ? 'Fetching...' : 'Refresh' }}
</button>
</div>
</ng-container>
Expand All @@ -46,7 +46,7 @@ import { useDeletePostMutation, useGetPostQuery, useUpdatePostMutation } from '.
</div>
</ng-template>
<pre class="bg-gray-200">{{ postQuery().data | json }}</pre>
<pre class="bg-gray-200">{{ postQuery.data() | json }}</pre>
</section>
`,
styles: [],
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/posts/posts-list/posts-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useGetPostsQuery } from '../services';
selector: 'app-posts-list',
template: `
<section class="space-y-4">
<ng-container *ngIf="postsQuery().data as posts; else loading">
<ng-container *ngIf="postsQuery.data() as posts; else loading">
<div *ngIf="posts.length; else emptyPosts">
<li *ngFor="let post of posts; trackBy: trackByFn">
<a class="hover:underline" [routerLink]="['/posts', post.id]">{{ post.name }}</a>
Expand Down

0 comments on commit 87b4b45

Please sign in to comment.