Skip to content

Instantly share code, notes, and snippets.

@renatoaraujoc
Created April 11, 2025 13:44
Show Gist options
  • Save renatoaraujoc/cee9f56c4ad85cf129048451afb3ab1f to your computer and use it in GitHub Desktop.
Save renatoaraujoc/cee9f56c4ad85cf129048451afb3ab1f to your computer and use it in GitHub Desktop.
import { catchError, map, type Observable, of, startWith } from 'rxjs';
import { rxResource } from '@angular/core/rxjs-interop';
import {
type Injector,
type ResourceRef,
type ResourceStatus,
type ValueEqualityFn
} from '@angular/core';
type StateMachine<T> =
| { status: 'LOADING' }
| { status: 'OK'; data: T }
| { status: 'ERROR'; message: string };
interface ResourceLoaderParams<R> {
request: Exclude<NoInfer<R>, undefined>;
abortSignal: AbortSignal;
previous: {
status: ResourceStatus;
};
}
interface StateMachineResourceOptions<T, R> {
request?: () => R;
loader: (params: ResourceLoaderParams<R>) => Observable<T>;
equal?: ValueEqualityFn<T>;
injector?: Injector;
}
function createStateMachineEqualityFn<T>(
dataEqualityFn?: ValueEqualityFn<T>
): ValueEqualityFn<StateMachine<T>> {
return (a, b) => {
if (a.status !== b.status) {
return false;
}
if (a.status === 'LOADING') {
return true;
}
if (a.status === 'ERROR' && b.status === 'ERROR') {
return a.message === b.message;
}
if (a.status === 'OK' && b.status === 'OK') {
return dataEqualityFn
? dataEqualityFn(a.data, b.data)
: a.data === b.data;
}
return true;
};
}
export function createStateMachineResource<T, R>(
params: StateMachineResourceOptions<T, R>
): ResourceRef<StateMachine<T>> {
return rxResource<StateMachine<T>, R>({
request: params.request,
loader: (loaderParams) =>
params.loader(loaderParams).pipe(
map((data) => ({
status: 'OK' as const,
data
})),
catchError((err: Error) =>
of({
status: 'ERROR' as const,
message: err.message
})
),
startWith({ status: 'LOADING' as const })
),
defaultValue: { status: 'LOADING' as const },
equal: createStateMachineEqualityFn(params.equal),
injector: params.injector
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment