import Memory = require("dojo/store/Memory"); import Observable = require("dojo/store/Observable"); import { Appointment, Member } from "./Appointment"; import { Contact } from "./Contact"; import { Uuid } from "@implab/core-amd/Uuid"; import { Observable as RxjsObservable } from "rxjs"; import { QueryResultUpdate } from "@implab/djx/tsx"; type AppointmentRecord = Omit & {id: string}; type ContactRecord = Contact; type MemberRecord = Member & { appointmentId: string; }; export interface ObservableResults { /** * Allows observation of results */ observe(listener: (object: T, previousIndex: number, newIndex: number) => void, includeUpdates?: boolean): { remove(): void; }; } export function isObservable(v: PromiseLike> | ArrayLike): v is ArrayLike & ObservableResults { return v && (typeof (v as any).observe === "function"); } export function observe(results: T[], includeObjectUpdates?: boolean): RxjsObservable>; export function observe(results: PromiseLike, includeObjectUpdates?: boolean): PromiseLike>>; export function observe(results: any, includeObjectUpdates = true) { // results может быть асинхронным, т.е. до завершения // получения результатов store может быть обновлен. В любом // случае, если между подключением хотя бы одного наблюдателя // была выполнена команда обновления, results считается устаревшим // и не может быть использован для отслеживания обновлений. // Конкретно с dojo/store/Observable тут вообще возникает проблема: // 1. Синхронные store типа Memory будут давать ошибку на методах // обновления (add,put,remove) // 2. Асинхронные store типа JsonRest будут выдавать предупреждения // о необработанной ошибке в Promise при обращении к методам // обновления (add,put,remove) const _subscribe = (items: any[]) => new RxjsObservable>(subscriber => { items .forEach((value, newIndex) => subscriber.next({ item: value, newIndex, prevIndex: -1})); try { if (isObservable(results)) { const h = results.observe( (value, prevIndex, newIndex) => subscriber.next({ item: value, prevIndex, newIndex }), includeObjectUpdates ); return () => { h.remove(); }; } } catch (err) { subscriber.error(err); } }); return isPromise(results) ? results.then(_subscribe) : _subscribe(results || []); } export class MainContext { private _appointments = new Observable(new Memory()); private _contacts = new Observable(new Memory()); private _members = new Observable(new Memory()); createAppointment(title: string, startAt: Date, duration: number, members: Member[]) { const id = Uuid(); this._appointments.add({ id: Uuid(), startAt, duration, title }); members.forEach(member => this._members.add({ appointmentId: id, ...member }, {id: Uuid()}) ); } queryAppointments(dateFrom: Date, dateTo: Date) { this._appointments.query().map() } private _mapAppointment = ({startAt, title, duration, id}: AppointmentRecord) => ({ }) }