aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields/Proxy.ts
blob: 38d874a685025694781aef3836512bde6489af72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import { Deserializable } from "../client/util/SerializationHelper";
import { FieldWaiting } from "./Doc";
import { primitive, serializable } from "serializr";
import { observable, action } from "mobx";
import { DocServer } from "../client/DocServer";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
import { Id, Copy, ToScriptString } from "./FieldSymbols";

@Deserializable("proxy")
export class ProxyField<T extends RefField> extends ObjectField {
    constructor();
    constructor(value: T);
    constructor(fieldId: string);
    constructor(value?: T | string) {
        super();
        if (typeof value === "string") {
            this.fieldId = value;
        } else if (value) {
            this.cache = value;
            this.fieldId = value[Id];
        }
    }

    [Copy]() {
        if (this.cache) return new ProxyField<T>(this.cache);
        return new ProxyField<T>(this.fieldId);
    }

    [ToScriptString]() {
        return "invalid";
    }

    @serializable(primitive())
    readonly fieldId: string = "";

    // This getter/setter and nested object thing is 
    // because mobx doesn't play well with observable proxies
    @observable.ref
    private _cache: { readonly field: T | undefined } = { field: undefined };
    private get cache(): T | undefined {
        return this._cache.field;
    }
    private set cache(field: T | undefined) {
        this._cache = { field };
    }

    private failed = false;
    private promise?: Promise<any>;

    value(): T | undefined | FieldWaiting {
        if (this.cache) {
            return this.cache;
        }
        if (this.failed) {
            return undefined;
        }
        if (!this.promise) {
            this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => {
                this.promise = undefined;
                this.cache = field;
                if (field === undefined) this.failed = true;
                return field;
            }));
        }
        return this.promise;
    }
}