Skip to content

Commit

Permalink
feat: dropping AsyncResult and related"loading" concept
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamChelman committed Dec 5, 2024
1 parent 73de9e2 commit d4e60c4
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 56 deletions.
15 changes: 7 additions & 8 deletions libs/cdk/fetch-cache/services/fetch-cache.service.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
import { inject, Injectable } from '@angular/core';
import { AsyncResult, completableToObservable, loading, success } from '@cognizone/model-utils';
import { completableToObservable, Result, ok } from '@cognizone/model-utils';
import { shareReplaySafe } from '@cognizone/ng-core';
import { Observable, of, startWith, switchMap } from 'rxjs';
import { Observable, of, switchMap } from 'rxjs';

import { CacheService } from './cache.service';

@Injectable({ providedIn: 'root' })
export class FetchCache {
private cache: CacheService = inject(CacheService);
private currentFetchMap: { [key: string]: Observable<AsyncResult> } = {};
private currentFetchMap: { [key: string]: Observable<Result> } = {};

get<T>(key: string, fetch: () => Observable<AsyncResult<T>>, options?: FetchCacheOptions): Observable<AsyncResult<T>> {
if (this.currentFetchMap[key]) return this.currentFetchMap[key] as Observable<AsyncResult<T>>;
get<T>(key: string, fetch: () => Observable<Result<T>>, options?: FetchCacheOptions): Observable<Result<T>> {
if (this.currentFetchMap[key]) return this.currentFetchMap[key] as Observable<Result<T>>;
const cache = (options?.cache ?? this.cache) as CacheService<T>;

return this.getFromCache<T>(key, cache).pipe(
switchMap(cached => {
if (cached) {
return of(success(cached));
return of(ok(cached));
}

return (this.currentFetchMap[key] = fetch().pipe(
switchMap(async result => {
if (result.type === 'success') {
if (result.type === 'ok') {
await cache.set(key, result.content);
}
delete this.currentFetchMap[key];
return result;
}),
startWith(loading()),
shareReplaySafe(1)
));
})
Expand Down
3 changes: 1 addition & 2 deletions libs/cdk/result/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './pipes/get-success.pipe';
export * from './pipes/is-error.pipe';
export * from './pipes/is-loading.pipe';
export * from './pipes/unwrap.pipe';
12 changes: 0 additions & 12 deletions libs/cdk/result/pipes/get-success.pipe.ts

This file was deleted.

4 changes: 2 additions & 2 deletions libs/cdk/result/pipes/is-error.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Pipe, PipeTransform } from '@angular/core';
import { AsyncResult, Nil, ResultError } from '@cognizone/model-utils';
import { Result, Nil, ResultError } from '@cognizone/model-utils';

@Pipe({
name: 'isError',
standalone: true,
})
export class IsErrorPipe implements PipeTransform {
transform(value: Nil<AsyncResult>): value is ResultError<unknown> {
transform(value: Nil<Result>): value is ResultError<unknown> {
return value?.type === 'error';
}
}
12 changes: 0 additions & 12 deletions libs/cdk/result/pipes/is-loading.pipe.ts

This file was deleted.

12 changes: 12 additions & 0 deletions libs/cdk/result/pipes/unwrap.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Result } from '@cognizone/model-utils';

@Pipe({
name: 'unwrap',
standalone: true,
})
export class UnwrapPipe implements PipeTransform {
transform<T>(value: Result<T>, defaultValue: T): T {
return value.type === 'ok' ? value.content : defaultValue;
}
}
27 changes: 7 additions & 20 deletions libs/model-utils/src/lib/models/result.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
/**
* @description Represents a remote data and its related state
* @description Wraps a value in an ok if the related operations went well, otherwise wrap the result in an error.
* The idea is to force consumers for `Result` to handle error cases, and not be dependant on try/catch behaviors
*/
export type AsyncResult<T = unknown, E = unknown> = ResultSuccess<T> | ResultError<E> | ResultLoading;
export type Result<T = unknown, E = unknown> = ResultSuccess<T> | ResultError<E>;
export type Result<T = unknown, E = unknown> = ResultOk<T> | ResultError<E>;

/**
* @description the resource has been successfully retrieved and is stored in `content`
*/
export type ResultSuccess<T> = {
type: 'success';
export type ResultOk<T> = {
type: 'ok';
content: T;
};

export function success<T>(content: T): ResultSuccess<T> {
return { type: 'success', content };
export function ok<T>(content: T): ResultOk<T> {
return { type: 'ok', content };
}

/**
Expand All @@ -27,16 +27,3 @@ export type ResultError<E> = {
export function error<T>(err: T): ResultError<T> {
return { type: 'error', error: err };
}

/**
* @description the query to fetch the resource has been started but the response did not arrive yet
*/
export type ResultLoading = {
type: 'loading';
};

// always the same, no need to re-create it every time
const _loading = { type: 'loading' as const };
export function loading(): ResultLoading {
return _loading;
}

0 comments on commit d4e60c4

Please sign in to comment.