@angular-experts/resource
Version:
### The missing create, update, delete (CUD) support for Angular resource
1 lines • 25.3 kB
Source Map (JSON)
{"version":3,"file":"angular-experts-resource-src-lib-resource.mjs","sources":["../../../projects/resource/src/lib/resource/resource.model.ts","../../../projects/resource/src/lib/resource/resource.util.ts","../../../projects/resource/src/lib/resource/resource.ts","../../../projects/resource/src/lib/resource/angular-experts-resource-src-lib-resource.ts"],"sourcesContent":["export type RequestType = 'create' | 'update' | 'remove';\nexport type Behavior = 'concat' | 'merge' | 'switch' | 'exhaust';\n\n/**\n * Strategy for handling resource requests\n *\n * - `'pessimistic'` - wait for server response, then reload the entire collection\n * - `'optimistic'` - update UI immediately and assume success\n * - `'incremental'` - patch returned item into the existing collection after server confirms\n */\nexport type Strategy = 'optimistic' | 'pessimistic' | 'incremental';\n\nexport interface RestResourceOptions<T, ID> {\n /**\n * Whether to log verbose information to the console.\n * This is useful for debugging and understanding the resource's behavior.\n *\n * @default false\n */\n verbose?: boolean;\n /**\n * A reactive function which determines the request to be made.\n * Whenever the params change, the loader will be triggered to fetch a new value for the resource.\n *\n * (works the same way as Angular's `resource`)\n *\n * @returns A string containing URL query parameters or undefined\n */\n params?: () => string | undefined;\n\n /**\n * Function to extract the ID from an item when the ID is not stored in the `id` field.\n * Used to identify items for update and remove operations.\n *\n * @param item The item from which to extract the ID\n * @returns The ID of the item\n */\n idSelector?: (item: T) => ID;\n\n /**\n * The default strategy for the resource for every request type,\n * it can be overridden by the request-type specific strategy\n *\n * - `'pessimistic'` - wait for server response, then reload the entire collection\n * - `'optimistic'` - update UI immediately and assume success\n * - `'incremental'` - patch returned item into the existing collection after server confirms\n *\n * @default 'pessimistic'\n */\n strategy?: Strategy;\n create?: {\n /**\n * Defines how create requests are handled when multiple requests are made.\n * Controls the RxJS flattening operator used for the HTTP request.\n *\n * @default 'concat'\n */\n behavior?: Behavior;\n /**\n * Determines whether changes are applied optimistically (before server confirmation)\n * or pessimistically (after server confirmation) for create operations.\n *\n * @default The value of the global strategy option\n */\n strategy?: Strategy;\n /**\n * Optionally generate a new item ID (if the target API does not handle this)\n * and set it on the item.\n *\n * @property generator A function that returns a new ID (e.g., UUID or auto-increment).\n * Used when the backend does not assign one automatically.\n *\n * @property setter (Optional) A function that sets the generated ID onto the item,\n * especially useful when the item’s ID field is not named `id`.\n *\n * @example\n * {\n * id: {\n * generator: () => uuid(),\n * setter: (id, item) => {\n * item.nonstandardId = id\n * }\n * }\n * }\n *\n */\n id?: {\n /**\n * A function that generates a new unique ID.\n * @example\n * () => uuid()\n */\n generator: () => ID;\n /**\n * (Optional) Custom logic for assigning the generated ID to the item.\n *\n * @param id The generated ID\n * @param item The item object to modify\n *\n * @example\n * setter: (id, item) => {\n * item.nonstandardId = id\n * }\n */\n setter?: (id: ID, item: Partial<T>) => void;\n };\n };\n update?: {\n /**\n * Defines how update requests are handled when multiple requests are made.\n * Controls the RxJS flattening operator used for the HTTP request.\n *\n * @default 'concat'\n */\n behavior?: Behavior;\n /**\n * Determines whether changes are applied optimistically (before server confirmation)\n * or pessimistically (after server confirmation) for update operations.\n *\n * @default The value of the global strategy option\n */\n strategy?: Strategy;\n };\n remove?: {\n /**\n * Defines how remove requests are handled when multiple requests are made.\n * Controls the RxJS flattening operator used for the HTTP request.\n *\n * @default 'concat'\n */\n behavior?: Behavior;\n /**\n * Determines whether changes are applied optimistically (before server confirmation)\n * or pessimistically (after server confirmation) for remove operations.\n *\n * @default The value of the global strategy option\n */\n strategy?: Strategy;\n };\n}\n\nexport const LOG_PREFIX = `[@angular-experts/resource]`;\n","import { DestroyRef, inject } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n concatMap,\n exhaustMap,\n mergeMap,\n Observable,\n Subject,\n switchMap,\n} from 'rxjs';\n\nimport { Behavior } from './resource.model';\n\nexport function streamify<T extends unknown[]>(\n impl: (stream: Observable<T>) => Observable<unknown>,\n) {\n const destroyRef = inject(DestroyRef);\n const subject = new Subject<T>();\n impl(subject).pipe(takeUntilDestroyed(destroyRef)).subscribe();\n return (...args: T) => {\n subject.next(args);\n };\n}\n\nexport function behaviorToOperator(behavior: Behavior = 'concat') {\n switch (behavior) {\n case 'concat':\n return concatMap;\n case 'merge':\n return mergeMap;\n case 'switch':\n return switchMap;\n case 'exhaust':\n return exhaustMap;\n }\n}\n","import { HttpClient } from '@angular/common/http';\nimport {\n inject,\n signal,\n computed,\n ResourceRef,\n linkedSignal,\n} from '@angular/core';\nimport { rxResource } from '@angular/core/rxjs-interop';\nimport { tap, catchError, map } from 'rxjs';\n\nimport {\n RestResourceOptions,\n RequestType,\n Strategy,\n LOG_PREFIX,\n} from './resource.model';\nimport { behaviorToOperator, streamify } from './resource.util';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function restResource<T, ID, E extends Error = Error>(\n apiEndpoint: string,\n options: RestResourceOptions<T, ID> = {},\n) {\n const http = inject(HttpClient);\n\n const strategy: Strategy = options.strategy ?? 'pessimistic';\n\n const loadingCreate = signal(false);\n const loadingUpdate = signal(false);\n const loadingRemove = signal(false);\n const errorCreate = signal<E | undefined>(undefined);\n const errorUpdate = signal<E | undefined>(undefined);\n const errorRemove = signal<E | undefined>(undefined);\n\n const resource = rxResource({\n params: () => options.params?.() ?? '',\n stream: ({ params }) => {\n const fullUrl = `${apiEndpoint}${params}`;\n verbose('Read (Angular resource)', { params, fullUrl });\n return http.get<T[]>(fullUrl);\n },\n });\n\n const values = linkedSignal({\n source: () => {\n try {\n return resource.value();\n } catch {\n return undefined;\n }\n },\n computation: (\n source: T[] | undefined,\n previous: { source: T[] | undefined; value: T[] | undefined } | undefined,\n ) => {\n if (!source && previous?.value) {\n return previous.value;\n } else {\n return source;\n }\n },\n });\n\n const value = computed(() => {\n const unwrappedItems = values();\n if (unwrappedItems?.length === 1) {\n return unwrappedItems[0];\n } else {\n return undefined;\n }\n });\n\n const create = streamify<[item: Partial<T>]>((stream) =>\n stream.pipe(\n map(([item]) => {\n if (options.create?.id?.generator) {\n const newId = options.create?.id.generator();\n if (options.create?.id?.setter) {\n options.create?.id?.setter(newId, item);\n } else {\n (item as unknown as { id: ID }).id = newId;\n }\n }\n return [item];\n }),\n tap(([item]) => {\n loadingCreate.set(true);\n if (isOptimistic('create', options)) {\n if (\n !options.create?.id?.generator &&\n !getItemId(item as T, options)\n ) {\n console.warn(\n LOG_PREFIX,\n `Optimistic update can only be performed if the provided item has an ID. ID can be added manually or using \"options.create.id.generator\", Skip...`,\n );\n return;\n }\n resource.update((prev) => [...(prev ?? []), item as T]);\n }\n }),\n behaviorToOperator(options.create?.behavior)(([item]) =>\n http.post<T | undefined | null>(apiEndpoint, item).pipe(\n tap((createdItem) => {\n if (isIncremental('create', options)) {\n if (!createdItem) {\n console.warn(\n LOG_PREFIX,\n `Incremental create request returned no item, this is unexpected, if your API does not return the created item, consider using \"optimistic\" strategy instead, Skip...`,\n );\n } else {\n resource.update((prev) => [...(prev ?? []), createdItem]);\n }\n }\n }),\n catchError((err) => {\n errorCreate.set(err);\n if (isOptimistic('create', options)) {\n resource.update((prev) =>\n prev?.filter((prevItem) => prevItem !== item),\n );\n }\n return [undefined];\n }),\n ),\n ),\n tap(() => {\n reloadIfPessimisticOrHasParams('create', resource, options);\n loadingCreate.set(false);\n }),\n ),\n );\n\n const update = streamify<[item: T]>((stream) =>\n stream.pipe(\n map(([item]) => {\n loadingUpdate.set(true);\n if (isOptimistic('update', options)) {\n const updatedItemId = getItemId(item, options);\n const prevVersionOfItem = resource\n .value()\n ?.find(\n (prevItem) => getItemId(prevItem, options) === updatedItemId,\n );\n resource.update((prev) =>\n prev?.map((prevItem) => {\n return getItemId(prevItem, options) === updatedItemId\n ? { ...prevItem, ...item }\n : prevItem;\n }),\n );\n return { item, prevVersionOfItem };\n }\n return { item };\n }),\n behaviorToOperator(options.update?.behavior)(\n ({ item, prevVersionOfItem }) => {\n const updatedItemId = getItemId(item!, options);\n return http\n .put<\n T | null | undefined\n >(`${apiEndpoint}/${updatedItemId?.toString()}`, item)\n .pipe(\n tap((updatedItem) => {\n if (isIncremental('update', options)) {\n if (!updatedItem) {\n console.warn(\n LOG_PREFIX,\n `Incremental update request returned no item, this is unexpected, if your API does not return the updated item, consider using \"optimistic\" strategy instead, Skip...`,\n );\n } else {\n resource.update((prev) =>\n prev?.map((prevItem) => {\n return getItemId(prevItem, options) === updatedItemId\n ? updatedItem\n : prevItem;\n }),\n );\n }\n }\n }),\n catchError((err) => {\n errorUpdate.set(err);\n if ((options.update?.strategy ?? strategy) === 'optimistic') {\n resource.update((prev) =>\n prev?.map((prevItem) => {\n return getItemId(prevItem, options) === updatedItemId\n ? prevVersionOfItem!\n : prevItem;\n }),\n );\n }\n return [undefined];\n }),\n );\n },\n ),\n tap(() => {\n reloadIfPessimisticOrHasParams('update', resource, options);\n loadingUpdate.set(false);\n }),\n ),\n );\n\n const remove = streamify<[item: T]>((stream) =>\n stream.pipe(\n tap(() => loadingRemove.set(true)),\n tap(([item]) => {\n if (isOptimistic('remove', options)) {\n resource.update((prev) =>\n prev?.filter((prevItem) => prevItem !== item),\n );\n }\n }),\n behaviorToOperator(options.remove?.behavior)(([item]) =>\n http\n .delete<\n T | ID | null | undefined\n >(`${apiEndpoint}/${getItemId(item, options)}`)\n .pipe(\n tap((removedItemOrId) => {\n if (isIncremental('remove', options)) {\n if (removedItemOrId === null || removedItemOrId === undefined) {\n console.warn(\n LOG_PREFIX,\n `Incremental remove request returned no item or item ID, this is unexpected, if your API does not return the removed item or removed item ID, consider using \"optimistic\" strategy instead, Skip...`,\n );\n } else {\n const removedItemId =\n typeof removedItemOrId === 'object'\n ? getItemId(removedItemOrId as T, options)\n : (removedItemOrId as ID);\n resource.update((prev) =>\n prev?.filter(\n (prevItem) =>\n getItemId(prevItem, options) !== removedItemId,\n ),\n );\n }\n }\n }),\n catchError((err) => {\n errorRemove.set(err);\n if (isOptimistic('remove', options)) {\n resource.update((prev) => [...(prev ?? []), item]);\n }\n return [undefined];\n }),\n ),\n ),\n tap(() => {\n reloadIfPessimisticOrHasParams('remove', resource, options);\n loadingRemove.set(false);\n }),\n ),\n );\n\n function getItemId(item: T, options: RestResourceOptions<T, ID>): ID {\n return options.idSelector?.(item) ?? (item as unknown as { id: ID }).id;\n }\n\n function isOptimistic(\n requestType: RequestType,\n options: RestResourceOptions<T, ID>,\n ) {\n return (options[requestType]?.strategy ?? strategy) === 'optimistic';\n }\n\n function isIncremental(\n requestType: RequestType,\n options: RestResourceOptions<T, ID>,\n ) {\n return (options[requestType]?.strategy ?? strategy) === 'incremental';\n }\n\n function reloadIfPessimisticOrHasParams(\n requestType: RequestType,\n resource: ResourceRef<T[] | undefined>,\n options: RestResourceOptions<T, ID>,\n ) {\n if (\n (options[requestType]?.strategy ?? options.strategy ?? 'pessimistic') ===\n 'pessimistic' ||\n options.params\n ) {\n resource.reload();\n }\n }\n\n function verbose(...args: unknown[]) {\n if (options.verbose) {\n console.debug(LOG_PREFIX, ...args);\n }\n }\n\n const loading = computed(\n () =>\n !loadingInitial() &&\n (resource.isLoading() ||\n loadingCreate() ||\n loadingUpdate() ||\n loadingRemove()),\n );\n const loadingInitial = computed(() => !values() && resource.isLoading());\n\n return {\n // LOADING\n loadingInitial,\n loading,\n loadingCreate,\n loadingUpdate,\n loadingRemove,\n\n // ERRORS\n errorRead: resource.error,\n errorCreate,\n errorUpdate,\n errorRemove,\n\n // VALUES\n /**\n * The value of the resource, ONLY if the resource is a single item.\n *\n * This is useful when building a resource to manage a single entity, eg detail view.\n *\n * @returns Signal of single item or undefined (also returns undefined if resource has more than one item)\n */\n value,\n /**\n * The values of the resource (eg list of 0 to n items).\n *\n * @returns Signal of a list of items or undefined (also returns undefined if resource has no items)\n */\n values,\n hasValue: computed(() => value() !== null && value() !== undefined),\n hasValues: computed(() => !!values()?.length),\n\n // METHODS\n reload: resource.reload.bind(resource),\n create,\n update,\n remove,\n\n // LIFECYCLE\n destroy: resource.destroy.bind(resource),\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}