##// END OF EJS Templates
Added tag v1.10.2 for changeset 6acbe6efbe20
Added tag v1.10.2 for changeset 6acbe6efbe20

File last commit:

r150:d9c99ae7dec8 v1.10.1 default
r156:46e0da3cebdf default
Show More
store.ts
170 lines | 5.9 KiB | video/mp2t | TypeScriptLexer
cin
added reduce() and next() methods to observable...
r116 import { PromiseOrValue } from "@implab/core-amd/interfaces";
cin
added store::get method to wrap up dojo/store/get
r136 import { isCancellable, isPromise } from "@implab/core-amd/safe";
import { observe, Observable, empty } from "./observable";
import { after } from "dojo/aspect";
cin
added reduce() and next() methods to observable...
r116
export interface OrderedUpdate<T> {
/** The item is being updated */
readonly item: T;
/** The previous index of the item, -1 in case it is inserted */
readonly prevIndex: number;
/** The new index of the item, -1 in case it is deleted */
readonly newIndex: number;
}
export type QueryResults<T> = Observable<OrderedUpdate<T>>;
interface DjObservableResults<T> {
/**
* Allows observation of results
*/
observe(listener: (object: T, previousIndex: number, newIndex: number) => void, includeUpdates?: boolean): {
remove(): void;
};
}
cin
added whenRendered() method to wait for pending oprations to complete
r118 interface Queryable<T, Q, O> {
query(query?: Q, options?: O): PromiseOrValue<T[]>;
cin
added reduce() and next() methods to observable...
r116 }
cin
added whenRendered() method to wait for pending oprations to complete
r118 export const isDjObservableResults = <T>(v: object): v is DjObservableResults<T> =>
cin
added reduce() and next() methods to observable...
r116 v && (typeof (v as { observe?: unknown; }).observe === "function");
cin
added tap() method to observable...
r144 export const query = <T, Q, O>(store: Queryable<T, Q, O>, includeUpdates = true) => {
const q = queryEx(store, includeUpdates);
return (query?: Q, options?: O & { observe?: boolean }) => {
const [data, updates] = q(query, options);
return options?.observe === false ? data : data.cat(updates);
};
};
cin
added observable.collect() method to collect a sequnce to the array...
r129
cin
Fixed queryEx: query fresh results every time when no active observers are exist
r150 /**
* Wraps the query method of the store, the resulting method takes a query
* expression and returns two observable sequences. The first sequence represents
* the results of the query, the second sequence provides the updates to the
* query results.
*
* @param store The store used to query data
* @param includeUpdates The flag to include item updates not only additions and
* deletions. By default this flag is set to true.
* @returns Two observable sequences
*/
cin
added tap() method to observable...
r144 export const queryEx = <T, Q, O>(store: Queryable<T, Q, O>, includeUpdates = true) =>
(query?: Q, options?: O): [data: QueryResults<T>, updates: QueryResults<T>] => {
cin
Fixed queryEx: query fresh results every time when no active observers are exist
r150 /** count active observers */
let listeners = 0;
let results: PromiseOrValue<T[]> = [];
cin
added tap() method to observable...
r144
const data = observe<OrderedUpdate<T>>(({ next, complete, error }) => {
cin
added observable.collect() method to collect a sequnce to the array...
r129 const processResults = (items: T[]) =>
items.forEach((item, newIndex) => next({ item, newIndex, prevIndex: -1 }));
cin
added reduce() and next() methods to observable...
r116 try {
cin
Fixed queryEx: query fresh results every time when no active observers are exist
r150 // is there are no active observers here, we need to query actual
// data from the store.
if (listeners === 0)
cin
added tap() method to observable...
r144 results = store.query(query, options);
cin
added reduce() and next() methods to observable...
r116 if (isPromise(results)) {
cin
added tap() method to observable...
r144 results.then(processResults).then(complete, error);
if (isCancellable(results))
return results.cancel.bind(results);
cin
added reduce() and next() methods to observable...
r116 } else {
cin
added observable.collect() method to collect a sequnce to the array...
r129 processResults(results);
cin
added tap() method to observable...
r144 complete();
cin
added reduce() and next() methods to observable...
r116 }
cin
added tap() method to observable...
r144 } catch (e) {
error(e);
}
});
cin
added reduce() and next() methods to observable...
r116
cin
added tap() method to observable...
r144 const updates = observe<OrderedUpdate<T>>(({ next, complete, error, isClosed }) => {
try {
if (!isClosed() && isDjObservableResults<T>(results)) {
cin
Fixed queryEx: query fresh results every time when no active observers are exist
r150 // subscribe fot the changes
listeners++;
cin
added reduce() and next() methods to observable...
r116 const h = results.observe((item, prevIndex, newIndex) => next({ item, prevIndex, newIndex }), includeUpdates);
cin
Fixed queryEx: query fresh results every time when no active observers are exist
r150 return () => {
// unsubscribe from changes
listeners--;
h.remove();
};
cin
added reduce() and next() methods to observable...
r116 } else {
complete();
}
cin
added tap() method to observable...
r144 } catch (e) {
error(e);
cin
added reduce() and next() methods to observable...
r116 }
});
cin
added tap() method to observable...
r144 return [data, updates];
cin
added reduce() and next() methods to observable...
r116 };
cin
added store::get method to wrap up dojo/store/get
r136
cin
added tap() method to observable...
r144
cin
added store::get method to wrap up dojo/store/get
r136 interface IndexedStore<T> {
get(id: string | number): PromiseLike<T> | T | null | undefined;
}
interface Notifications<T> {
notify(item: T | undefined, id: string | number | undefined): void;
}
const hasNotifications = <T>(x: unknown): x is Notifications<T> =>
typeof x === "object" && x !== null && (typeof (x as Notifications<T>).notify === "function");
interface GetOpts {
observe?: boolean;
}
cin
added tap() method to observable...
r144 export type ItemUpdate<T> = [item: NonNullable<T>, id: string | number | undefined] |
cin
added store::get method to wrap up dojo/store/get
r136 [item: undefined | null, id: string | number];
const filterItem = (itemId: string | number) =>
cin
added tap() method to observable...
r144 <T>(source: Observable<ItemUpdate<T>>) =>
cin
added store::get method to wrap up dojo/store/get
r136 observe<T>(({ next, complete, error }) => {
const subscription = source
.filter(([, id]) => id === itemId)
.subscribe({
next: ([item]) => item !== null && item !== undefined ? next(item) : complete(),
complete,
error
});
return () => subscription.unsubscribe();
});
export const get = <T>(store: IndexedStore<T>) => {
const changes = hasNotifications<T>(store) ?
cin
added tap() method to observable...
r144 observe<ItemUpdate<T>>(({ next }) => {
const handle = after(store, "notify", (...args: ItemUpdate<T>) => next(args), true);
cin
added store::get method to wrap up dojo/store/get
r136 return () => handle.remove();
cin
Added a fallback error handler to observables, it will report unhandled errors
r138 }) : empty;
cin
added store::get method to wrap up dojo/store/get
r136
return (id: string | number, opts: GetOpts = {}) =>
observe<T>(({ next, complete, error }) => {
cin
Added a fallback error handler to observables, it will report unhandled errors
r138 try {
const result = store.get(id);
cin
added store::get method to wrap up dojo/store/get
r136
cin
Added a fallback error handler to observables, it will report unhandled errors
r138 const handle = (x: T | null | undefined) => {
if (x !== null && x !== undefined)
next(x);
complete();
};
cin
added store::get method to wrap up dojo/store/get
r136
cin
Added a fallback error handler to observables, it will report unhandled errors
r138 if (isPromise(result)) {
result.then(handle).then(undefined, error);
cin
added store::get method to wrap up dojo/store/get
r136
cin
Added a fallback error handler to observables, it will report unhandled errors
r138 if (isCancellable(result))
return () => result.cancel();
} else {
handle(result);
}
} catch (e) {
error(e);
cin
added store::get method to wrap up dojo/store/get
r136 }
}).cat(opts.observe !== false ? changes.pipe(filterItem(id)) : empty);
};