123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import {
- IDisposable, DisposableSet
- } from '@phosphor/disposable';
- import {
- ISignal, Signal
- } from '@phosphor/signaling';
- import {
- JSONValue, JSONObject
- } from '@phosphor/coreutils';
- import {
- ObservableMap
- } from './observablemap';
- import {
- IObservableJSON, ObservableJSON
- } from './observablejson';
- import {
- IObservableString, ObservableString
- } from './observablestring';
- import {
- IObservableUndoableList, ObservableUndoableList
- } from './undoablelist';
- import {
- IObservableMap
- } from './observablemap';
- /**
- * String type annotations for Observable objects that can be
- * created and placed in the IModelDB interface.
- */
- export
- type ObservableType = 'Map' | 'List' | 'String' | 'Value';
- /**
- * Base interface for Observable objects.
- */
- export
- interface IObservable extends IDisposable {
- /**
- * The type of this object.
- */
- readonly type: ObservableType;
- }
- /**
- * Interface for an Observable object that represents
- * an opaque JSON value.
- */
- export
- interface IObservableValue extends IObservable {
- /**
- * The type of this object.
- */
- readonly type: 'Value';
- /**
- * The changed signal.
- */
- readonly changed: ISignal<IObservableValue, ObservableValue.IChangedArgs>;
- /**
- * Get the current value, or `undefined` if it has not been set.
- */
- get(): JSONValue | undefined;
- /**
- * Set the value.
- */
- set(value: JSONValue): void;
- }
- /**
- * Interface for an object representing a single collaborator
- * on a realtime model.
- */
- export
- interface ICollaborator extends JSONObject {
- /**
- * A user id for the collaborator.
- * This might not be unique, if the user has more than
- * one editing session at a time.
- */
- readonly userId: string;
- /**
- * A session id, which should be unique to a
- * particular view on a collaborative model.
- */
- readonly sessionId: string;
- /**
- * A human-readable display name for a collaborator.
- */
- readonly displayName: string;
- /**
- * A color to be used to identify the collaborator in
- * UI elements.
- */
- readonly color: string;
- /**
- * A human-readable short name for a collaborator, for
- * use in places where the full `displayName` would take
- * too much space.
- */
- readonly shortName: string;
- }
- /**
- * Interface for an IObservableMap that tracks collaborators.
- */
- export
- interface ICollaboratorMap extends IObservableMap<ICollaborator> {
- /**
- * The local collaborator on a model.
- */
- readonly localCollaborator: ICollaborator;
- }
- /**
- * An interface for a path based database for
- * creating and storing values, which is agnostic
- * to the particular type of store in the backend.
- */
- export
- interface IModelDB extends IDisposable {
- /**
- * The base path for the `IModelDB`. This is prepended
- * to all the paths that are passed in to the member
- * functions of the object.
- */
- readonly basePath: string;
- /**
- * Whether the database has been disposed.
- */
- readonly isDisposed: boolean;
- /**
- * Whether the database has been populated
- * with model values prior to connection.
- */
- readonly isPrepopulated: boolean;
- /**
- * Whether the database is collaborative.
- */
- readonly isCollaborative: boolean;
- /**
- * A promise that resolves when the database
- * has connected to its backend, if any.
- */
- readonly connected: Promise<void>;
- /**
- * A map of the currently active collaborators
- * for the database, including the local user.
- */
- readonly collaborators?: ICollaboratorMap;
- /**
- * Get a value for a path.
- *
- * @param path: the path for the object.
- *
- * @returns an `IObservable`.
- */
- get(path: string): IObservable | undefined;
- /**
- * Whether the `IModelDB` has an object at this path.
- *
- * @param path: the path for the object.
- *
- * @returns a boolean for whether an object is at `path`.
- */
- has(path: string): boolean;
- /**
- * Create a string and insert it in the database.
- *
- * @param path: the path for the string.
- *
- * @returns the string that was created.
- */
- createString(path: string): IObservableString;
- /**
- * Create an undoable list and insert it in the database.
- *
- * @param path: the path for the list.
- *
- * @returns the list that was created.
- *
- * #### Notes
- * The list can only store objects that are simple
- * JSON Objects and primitives.
- */
- createList<T extends JSONValue>(path: string): IObservableUndoableList<T>;
- /**
- * Create a map and insert it in the database.
- *
- * @param path: the path for the map.
- *
- * @returns the map that was created.
- *
- * #### Notes
- * The map can only store objects that are simple
- * JSON Objects and primitives.
- */
- createMap(path: string): IObservableJSON;
- /**
- * Create an opaque value and insert it in the database.
- *
- * @param path: the path for the value.
- *
- * @returns the value that was created.
- */
- createValue(path: string): IObservableValue;
- /**
- * Get a value at a path, or `undefined if it has not been set
- * That value must already have been created using `createValue`.
- *
- * @param path: the path for the value.
- */
- getValue(path: string): JSONValue | undefined;
- /**
- * Set a value at a path. That value must already have
- * been created using `createValue`.
- *
- * @param path: the path for the value.
- *
- * @param value: the new value.
- */
- setValue(path: string, value: JSONValue): void;
- /**
- * Create a view onto a subtree of the model database.
- *
- * @param basePath: the path for the root of the subtree.
- *
- * @returns an `IModelDB` with a view onto the original
- * `IModelDB`, with `basePath` prepended to all paths.
- */
- view(basePath: string): IModelDB;
- /**
- * Dispose of the resources held by the database.
- */
- dispose(): void;
- }
- /**
- * A concrete implementation of an `IObservableValue`.
- */
- export
- class ObservableValue implements IObservableValue {
- /**
- * Constructor for the value.
- *
- * @param initialValue: the starting value for the `ObservableValue`.
- */
- constructor(initialValue: JSONValue = null) {
- this._value = initialValue;
- }
- /**
- * The observable type.
- */
- get type(): 'Value' {
- return 'Value';
- }
- /**
- * Whether the value has been disposed.
- */
- get isDisposed(): boolean {
- return this._isDisposed;
- }
- /**
- * The changed signal.
- */
- get changed(): ISignal<this, ObservableValue.IChangedArgs> {
- return this._changed;
- }
- /**
- * Get the current value, or `undefined` if it has not been set.
- */
- get(): JSONValue {
- return this._value;
- }
- /**
- * Set the current value.
- */
- set(value: JSONValue): void {
- let oldValue = this._value;
- this._value = value;
- this._changed.emit({
- oldValue: oldValue,
- newValue: value
- });
- }
- /**
- * Dispose of the resources held by the value.
- */
- dispose(): void {
- if (this._isDisposed) {
- return;
- }
- this._isDisposed = true;
- Signal.clearData(this);
- this._value = null;
- }
- private _value: JSONValue = null;
- private _changed = new Signal<this, ObservableValue.IChangedArgs>(this);
- private _isDisposed = false;
- }
- /**
- * The namespace for the `ObservableValue` class statics.
- */
- export
- namespace ObservableValue {
- /**
- * The changed args object emitted by the `IObservableValue`.
- */
- export
- class IChangedArgs {
- /**
- * The old value.
- */
- oldValue: JSONValue | undefined;
- /**
- * The new value.
- */
- newValue: JSONValue | undefined;
- }
- }
- /**
- * A concrete implementation of an `IModelDB`.
- */
- export
- class ModelDB implements IModelDB {
- /**
- * Constructor for the `ModelDB`.
- */
- constructor(options: ModelDB.ICreateOptions = {}) {
- this._basePath = options.basePath || '';
- if (options.baseDB) {
- this._db = options.baseDB;
- } else {
- this._db = new ObservableMap<IObservable>();
- this._toDispose = true;
- }
- }
- /**
- * The base path for the `ModelDB`. This is prepended
- * to all the paths that are passed in to the member
- * functions of the object.
- */
- get basePath(): string {
- return this._basePath;
- }
- /**
- * Whether the database is disposed.
- */
- get isDisposed(): boolean {
- return this._isDisposed;
- }
- /**
- * Whether the model has been populated with
- * any model values.
- */
- readonly isPrepopulated: boolean = false;
- /**
- * Whether the model is collaborative.
- */
- readonly isCollaborative: boolean = false;
- /**
- * A promise resolved when the model is connected
- * to its backend. For the in-memory ModelDB it
- * is immediately resolved.
- */
- readonly connected: Promise<void> = Promise.resolve(void 0);
- /**
- * Get a value for a path.
- *
- * @param path: the path for the object.
- *
- * @returns an `IObservable`.
- */
- get(path: string): IObservable | undefined {
- return this._db.get(this._resolvePath(path));
- }
- /**
- * Whether the `IModelDB` has an object at this path.
- *
- * @param path: the path for the object.
- *
- * @returns a boolean for whether an object is at `path`.
- */
- has(path: string): boolean {
- return this._db.has(this._resolvePath(path));
- }
- /**
- * Create a string and insert it in the database.
- *
- * @param path: the path for the string.
- *
- * @returns the string that was created.
- */
- createString(path: string): IObservableString {
- let str = new ObservableString();
- this._disposables.add(str);
- this.set(path, str);
- return str;
- }
- /**
- * Create an undoable list and insert it in the database.
- *
- * @param path: the path for the list.
- *
- * @returns the list that was created.
- *
- * #### Notes
- * The list can only store objects that are simple
- * JSON Objects and primitives.
- */
- createList<T extends JSONValue>(path: string): IObservableUndoableList<T> {
- let vec = new ObservableUndoableList<T>(
- new ObservableUndoableList.IdentitySerializer<T>());
- this._disposables.add(vec);
- this.set(path, vec);
- return vec;
- }
- /**
- * Create a map and insert it in the database.
- *
- * @param path: the path for the map.
- *
- * @returns the map that was created.
- *
- * #### Notes
- * The map can only store objects that are simple
- * JSON Objects and primitives.
- */
- createMap(path: string): IObservableJSON {
- let map = new ObservableJSON();
- this._disposables.add(map);
- this.set(path, map);
- return map;
- }
- /**
- * Create an opaque value and insert it in the database.
- *
- * @param path: the path for the value.
- *
- * @returns the value that was created.
- */
- createValue(path: string): IObservableValue {
- let val = new ObservableValue();
- this._disposables.add(val);
- this.set(path, val);
- return val;
- }
- /**
- * Get a value at a path, or `undefined if it has not been set
- * That value must already have been created using `createValue`.
- *
- * @param path: the path for the value.
- */
- getValue(path: string): JSONValue | undefined {
- let val = this.get(path);
- if (!val || val.type !== 'Value') {
- throw Error('Can only call getValue for an ObservableValue');
- }
- return (val as ObservableValue).get();
- }
- /**
- * Set a value at a path. That value must already have
- * been created using `createValue`.
- *
- * @param path: the path for the value.
- *
- * @param value: the new value.
- */
- setValue(path: string, value: JSONValue): void {
- let val = this.get(path);
- if (!val || val.type !== 'Value') {
- throw Error('Can only call setValue on an ObservableValue');
- }
- (val as ObservableValue).set(value);
- }
- /**
- * Create a view onto a subtree of the model database.
- *
- * @param basePath: the path for the root of the subtree.
- *
- * @returns an `IModelDB` with a view onto the original
- * `IModelDB`, with `basePath` prepended to all paths.
- */
- view(basePath: string): ModelDB {
- let view = new ModelDB({basePath, baseDB: this});
- this._disposables.add(view);
- return view;
- }
- /**
- * Set a value at a path. Not intended to
- * be called by user code, instead use the
- * `create*` factory methods.
- *
- * @param path: the path to set the value at.
- *
- * @param value: the value to set at the path.
- */
- set(path: string, value: IObservable): void {
- this._db.set(this._resolvePath(path), value);
- }
- /**
- * Dispose of the resources held by the database.
- */
- dispose(): void {
- if (this.isDisposed) {
- return;
- }
- this._isDisposed = true;
- if (this._toDispose) {
- this._db.dispose();
- }
- this._disposables.dispose();
- }
- /**
- * Compute the fully resolved path for a path argument.
- */
- private _resolvePath(path: string): string {
- if (this._basePath) {
- path = this._basePath + '.' + path;
- }
- return path;
- }
- private _basePath: string;
- private _db: ModelDB | ObservableMap<IObservable>;
- private _toDispose = false;
- private _isDisposed = false;
- private _disposables = new DisposableSet();
- }
- /**
- * A namespace for the `ModelDB` class statics.
- */
- export
- namespace ModelDB {
- /**
- * Options for creating a `ModelDB` object.
- */
- export
- interface ICreateOptions {
- /**
- * The base path to prepend to all the path arguments.
- */
- basePath?: string;
- /**
- * A ModelDB to use as the store for this
- * ModelDB. If none is given, it uses its own store.
- */
- baseDB?: ModelDB;
- }
- /**
- * A factory interface for creating `IModelDB` objects.
- */
- export
- interface IFactory {
- /**
- * Create a new `IModelDB` instance.
- */
- createNew(path: string): IModelDB;
- }
- }
|