@mmuscat/angular-resource
Version:
Data fetching library for Angular Composition API
237 lines (232 loc) • 7.86 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable } from '@angular/core';
import { inject, use, select, subscribe, Service } from '@mmuscat/angular-composition-api';
import { tap, switchMap, materialize, takeUntil, repeat, filter, sample, exhaust } from 'rxjs/operators';
import { of, Subject, merge } from 'rxjs';
class Resource {
constructor(value, error, pending, done) {
this.value = value;
this.error = error;
this.pending = pending;
this.done = done;
}
static createPending(value) {
return new Resource(value, undefined, true, false);
}
static createNext(value) {
return new Resource(value, undefined, false, false);
}
static createError(value, error) {
return new Resource(value, error, false, true);
}
static createComplete(value) {
return new Resource(value, undefined, false, true);
}
}
class ResultObserver {
constructor(value) {
this.value = value;
}
next(value) {
this.value.next(Resource.createNext(value));
}
error(error) {
this.value.next(Resource.createError(this.value.value.value, error));
}
complete() {
this.value.next(Resource.createComplete(this.value.value.value));
}
}
class PendingObserver {
constructor(value) {
this.value = value;
}
next() {
this.value.next(Resource.createPending(this.value.value.value));
}
}
class Cache {
constructor(factory, cache, unsubscribe) {
this.factory = factory;
this.cache = cache;
this.unsubscribe = unsubscribe;
}
get(params, invalidate) {
this.params = params;
const { cache, factory } = this;
const key = JSON.stringify(params);
if (invalidate) {
cache.delete(key);
}
if (cache.has(key)) {
return of(cache.get(key));
}
return factory(params).pipe(tap((value) => cache.set(key, value)));
}
clear() {
this.cache.clear();
}
invalidate() {
return this.get(this.params, true);
}
subscribe() {
return this;
}
}
const globalCache = new Map();
class CacheFactory {
get(token, queryFactory) {
function unsubscribe() {
var _a;
(_a = globalCache.get(token)) === null || _a === void 0 ? void 0 : _a.delete(this);
}
const cache = new Cache(queryFactory, new Map(), unsubscribe);
if (globalCache.has(token)) {
globalCache.get(token).add(cache);
return cache;
}
else {
globalCache.set(token, new Set([cache]));
return cache;
}
}
}
CacheFactory.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: CacheFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
CacheFactory.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: CacheFactory, providedIn: "root" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.0.4", ngImport: i0, type: CacheFactory, decorators: [{
type: Injectable,
args: [{ providedIn: "root" }]
}] });
function queryFactory(factory, forwardRef, config) {
const cacheFactory = inject(CacheFactory);
const queryFunction = factory();
return function query(...params) {
var _a;
const args = params[params.length - 2];
const options = params[params.length - 1];
const value = use(Resource.createNext(options.initialValue));
const query = select({
next(valueOrCommand) {
if (valueOrCommand instanceof Command) {
switch (valueOrCommand.signal) {
case CANCEL:
cancel.next();
break;
case INVALIDATE:
if (valueOrCommand.params) {
fetch(valueOrCommand.params, true);
}
else {
cache.clear();
}
break;
default:
throwInvalidCommand();
}
}
else {
value(valueOrCommand);
}
},
value,
});
const cache = cacheFactory.get(forwardRef(), queryFunction);
const operator = (_a = config === null || config === void 0 ? void 0 : config.operator) !== null && _a !== void 0 ? _a : switchMap;
const cancel = new Subject();
const fetch = use((args, invalidate) => [
args,
invalidate,
]);
const result = fetch.pipe(operator(([args, invalidate]) => cache.get(args, invalidate)), materialize(), takeUntil(cancel), repeat());
subscribe(cache);
subscribe(fetch, new PendingObserver(value));
subscribe(result, new ResultObserver(value));
if (options.refetch) {
const signal = merge(...options.refetch).pipe(filter((value) => (value instanceof Resource ? value.done : true)));
subscribe(fetch.pipe(sample(signal)), (params) => fetch(params, true));
}
if (args) {
subscribe(merge(...(Array.isArray(args) ? args : [args])), fetch);
}
return query;
};
}
function createQueryFactory(factory, config) {
const Query = new Service(queryFactory, {
providedIn: "root",
name: factory.name,
arguments: [factory, () => Query, config],
});
return Query;
}
const Query = createQueryFactory;
const CANCEL = 0;
const INVALIDATE = 1;
class Command {
constructor(signal, params) {
this.signal = signal;
this.params = params;
}
}
function throwInvalidCommand() {
throw new Error("Invalid command");
}
function mutateFactory(factory, config) {
var _a, _b;
const operator = (_b = (_a = config === null || config === void 0 ? void 0 : config.operator) === null || _a === void 0 ? void 0 : _a.call(config)) !== null && _b !== void 0 ? _b : exhaust();
const queue = use(Function);
const cancel = new Subject();
const result = queue.pipe(operator);
const createStream = factory();
const value = use(Resource.createNext(undefined));
function mutate(params) {
if (params instanceof Command) {
switch (params.signal) {
case CANCEL:
return cancel.next();
default:
throwInvalidCommand();
}
}
queue.next(createStream(params).pipe(materialize(), takeUntil(cancel)));
}
const mutation = select({
next: mutate,
value,
});
subscribe(queue, new PendingObserver(value));
subscribe(result, new ResultObserver(value));
return mutation;
}
function createMutationFactory(factory, config) {
return new Service(mutateFactory, {
providedIn: "root",
name: factory.name,
arguments: [factory, config],
});
}
const Mutation = createMutationFactory;
function cancel(resource) {
resource.next(new Command(CANCEL));
}
function invalidate(query, params) {
var _a;
if (query.__ng_value) {
query.next(new Command(INVALIDATE, params));
}
else {
const set = (_a = globalCache.get(query)) !== null && _a !== void 0 ? _a : [];
for (const cache of set) {
cache.clear();
cache.invalidate();
}
}
}
/*
* Public API Surface of resource
*/
/**
* Generated bundle index. Do not edit.
*/
export { Mutation, Query, Resource, cancel, invalidate };
//# sourceMappingURL=mmuscat-angular-resource.js.map