Browse Source

mol-state: builder fixes, StateObjectSelector

David Sehnal 5 years ago
parent
commit
ab0dcb0de9
2 changed files with 45 additions and 20 deletions
  1. 32 9
      src/mol-state/object.ts
  2. 13 11
      src/mol-state/state/builder.ts

+ 32 - 9
src/mol-state/object.ts

@@ -55,7 +55,7 @@ namespace StateObject {
     };
 }
 
-interface StateObjectCell<T extends StateObject = StateObject, F extends StateTransform<StateTransformer<any, T, any>> = StateTransform<StateTransformer<any, T, any>>> {
+interface StateObjectCell<T extends StateObject = StateObject, F extends StateTransform = StateTransform> {
     parent: State,
 
     transform: F,
@@ -88,6 +88,11 @@ namespace StateObjectCell {
     export type Obj<C extends StateObjectCell> = C extends StateObjectCell<infer T> ? T : never
     export type Transform<C extends StateObjectCell> = C extends StateObjectCell<any, infer T> ? T : never
     export type Transformer<C extends StateObjectCell> = C extends StateObjectCell<any, StateTransform<infer T>> ? T : never
+
+    export function is(o: any): o is StateObjectCell {
+        const c: StateObjectCell = o;
+        return !!c && !!c.transform && !!c.parent && !!c.status;
+    }
 }
 
 // TODO: improve the API?
@@ -115,12 +120,35 @@ export class StateObjectTracker<T extends StateObject> {
 }
 
 export class StateObjectSelector<S extends StateObject = StateObject, T extends StateTransformer = StateTransformer> {
-    getObj(): S | undefined {
+    get cell(): StateObjectCell<S, StateTransform<T>> | undefined {
+        return this.state?.cells.get(this.ref) as StateObjectCell<S, StateTransform<T>> | undefined;
+    }
+
+    get obj(): S | undefined {
         return this.state?.cells.get(this.ref)?.obj as S | undefined;
     }
 
-    getData(): S['data'] | undefined {
-        return this.getObj()?.data;
+    get data(): S['data'] | undefined {
+        return this.obj?.data;
+    }
+
+    /** Checks if the object exists. If not throw an error. */
+    checkValid() {
+        if (!this.state) {
+            throw new Error('Unassigned State.');
+        }
+        const cell = this.cell;
+        if (!cell) {
+            throw new Error(`Not created at all. Did you await/then the corresponding state update?`);
+        }
+        if (cell.status === 'ok') return true;
+        if (cell.status === 'error') throw new Error(cell.errorText);
+        throw new Error(`Unresolved. Did you await/then the corresponding state update?`);
+    }
+
+    get isOk() {
+        const cell = this.cell;
+        return cell && cell.status === 'ok';
     }
 
     constructor(public ref: StateTransform.Ref, public state?: State) {
@@ -128,11 +156,6 @@ export class StateObjectSelector<S extends StateObject = StateObject, T extends
 }
 
 export namespace StateObjectSelector {
-    export function is(s: any): s is StateObjectSelector {
-        const _s: StateObjectSelector = s;
-        return !!s && !!_s.getData && !!_s.getObj && !!_s.ref;
-    }
-
     export type Obj<S extends StateObjectSelector> = S extends StateObjectSelector<infer A> ? A : never
     export type Transformer<S extends StateObjectSelector> = S extends StateObjectSelector<any, infer T> ? T : never
 }

+ 13 - 11
src/mol-state/state/builder.ts

@@ -79,15 +79,15 @@ namespace StateBuilder {
         get editInfo() { return this.state.editInfo; }
         get currentTree() { return this.state.tree; }
 
-        to<A extends StateObject>(ref: StateTransform.Ref): To<A>
+        to<A extends StateObject, T extends StateTransformer>(ref: StateTransform.Ref): To<A, T>
         to<C extends StateObjectCell>(cell: C): To<StateObjectCell.Obj<C>, StateObjectCell.Transformer<C>>
         to<S extends StateObjectSelector>(selector: S): To<StateObjectSelector.Obj<S>, StateObjectSelector.Transformer<S>>
         to(refOrCellOrSelector: StateTransform.Ref | StateObjectCell | StateObjectSelector) {
             const ref = typeof refOrCellOrSelector === 'string'
                 ? refOrCellOrSelector
-                : StateObjectSelector.is(refOrCellOrSelector)
-                ? refOrCellOrSelector.ref
-                : refOrCellOrSelector.transform.ref;
+                : StateObjectCell.is(refOrCellOrSelector)
+                ? refOrCellOrSelector.transform.ref
+                : refOrCellOrSelector.ref;
             return new To<StateObject, StateTransformer>(this.state, ref, this);
         }
         toRoot<A extends StateObject>() { return new To<A>(this.state, this.state.tree.root.ref, this); }
@@ -128,8 +128,9 @@ namespace StateBuilder {
          */
         applyOrUpdate<T extends StateTransformer<A, any, any>>(ref: StateTransform.Ref, tr: T, params?: StateTransformer.Params<T>, options?: Partial<StateTransform.Options>): To<StateTransformer.To<T>, T> {
             if (this.state.tree.transforms.has(ref)) {
-                this.root.to(ref).update(params);
-                return this.root.to(ref);
+                const to = this.to<StateTransformer.To<T>, T>(ref);
+                if (params) to.update(params);
+                return to;
             } else {
                 return this.apply(tr, params, { ...options, ref });
             }
@@ -146,8 +147,9 @@ namespace StateBuilder {
                 if (child.done) break;
                 const tr = this.state.tree.transforms.get(child.value);
                 if (tr && StateTransform.hasTags(tr, tags)) {
-                    this.root.to(child.value).updateTagged(params, tagsUnion(tr.tags, tags, options && options.tags));
-                    return this.root.to(child.value);
+                    const to = this.to<StateTransformer.To<T>, T>(child.value);
+                    to.updateTagged(params, tagsUnion(tr.tags, tags, options && options.tags));
+                    return to;
                 }
             }
 
@@ -214,7 +216,7 @@ namespace StateBuilder {
         //     return this.root;
         // }
 
-        private updateTagged<T extends StateTransformer<any, A, any>>(params: any, tags: string | string[] | undefined) {
+        private updateTagged(params: any, tags: string | string[] | undefined) {
             if (this.state.tree.setParams(this.ref, params) || this.state.tree.setTags(this.ref, tags)) {
                 this.editInfo.count++;
                 this.editInfo.lastUpdate = this.ref;
@@ -243,7 +245,7 @@ namespace StateBuilder {
             return this.root;
         }
 
-        to<A extends StateObject>(ref: StateTransform.Ref): To<A>
+        to<A extends StateObject, T extends StateTransformer>(ref: StateTransform.Ref): To<A, T>
         to<C extends StateObjectCell>(cell: C): To<StateObjectCell.Obj<C>, StateObjectCell.Transformer<C>>
         to<S extends StateObjectSelector>(selector: S): To<StateObjectSelector.Obj<S>, StateObjectSelector.Transformer<S>>
         to(ref: StateTransform.Ref | StateObjectCell | StateObjectSelector) { return  this.root.to(ref as any); }
@@ -261,7 +263,7 @@ namespace StateBuilder {
     }
 }
 
-function tagsUnion<T>(...arrays: (string[] | string | undefined)[]): string[] | undefined {
+function tagsUnion(...arrays: (string[] | string | undefined)[]): string[] | undefined {
     let set: Set<string> | undefined = void 0;
     const ret = [];
     for (const xs of arrays) {