aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields
diff options
context:
space:
mode:
Diffstat (limited to 'src/new_fields')
-rw-r--r--src/new_fields/Doc.ts40
-rw-r--r--src/new_fields/Proxy.ts4
-rw-r--r--src/new_fields/ScriptField.ts9
-rw-r--r--src/new_fields/util.ts41
4 files changed, 72 insertions, 22 deletions
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 7f7263cf1..cce4fff5d 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -2,7 +2,7 @@ import { observable, action } from "mobx";
import { serializable, primitive, map, alias, list } from "serializr";
import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper";
import { DocServer } from "../client/DocServer";
-import { setter, getter, getField, updateFunction, deleteProperty } from "./util";
+import { setter, getter, getField, updateFunction, deleteProperty, makeEditable, makeReadOnly } from "./util";
import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types";
import { listSpec } from "./Schema";
import { ObjectField } from "./ObjectField";
@@ -132,6 +132,16 @@ export class Doc extends RefField {
this[fKey] = value;
}
}
+ const unset = diff.$unset;
+ if (unset) {
+ for (const key in unset) {
+ if (!key.startsWith("fields.")) {
+ continue;
+ }
+ const fKey = key.substring(7);
+ delete this[fKey];
+ }
+ }
}
}
@@ -146,6 +156,15 @@ export namespace Doc {
// return Cast(field, ctor);
// });
// }
+ export function MakeReadOnly(): { end(): void } {
+ makeReadOnly();
+ return {
+ end() {
+ makeEditable();
+ }
+ };
+ }
+
export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult {
const self = doc[Self];
return getField(self, key, ignoreProto);
@@ -186,7 +205,8 @@ export namespace Doc {
}
// compare whether documents or their protos match
- export function AreProtosEqual(doc: Doc, other: Doc) {
+ export function AreProtosEqual(doc?: Doc, other?: Doc) {
+ if (!doc || !other) return false;
let r = (doc === other);
let r2 = (doc.proto === other);
let r3 = (other.proto === doc);
@@ -196,7 +216,7 @@ export namespace Doc {
// gets the document's prototype or returns the document if it is a prototype
export function GetProto(doc: Doc) {
- return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : doc.proto!;
+ return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc);
}
export function allKeys(doc: Doc): string[] {
@@ -211,13 +231,21 @@ export namespace Doc {
return Array.from(results);
}
+ export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean) {
+ let list = Cast(target[key], listSpec(Doc));
+ if (list) {
+ let ind = relativeTo ? list.indexOf(relativeTo) : -1;
+ if (ind === -1) list.push(doc);
+ else list.splice(before ? ind : ind + 1, 0, doc);
+ }
+ return true;
+ }
export function MakeAlias(doc: Doc) {
- const alias = new Doc;
if (!GetT(doc, "isPrototype", "boolean", true)) {
- alias.proto = doc.proto;
+ return Doc.MakeCopy(doc);
}
- return alias;
+ return new Doc;
}
export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc {
diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts
index 130ec066e..38d874a68 100644
--- a/src/new_fields/Proxy.ts
+++ b/src/new_fields/Proxy.ts
@@ -48,9 +48,8 @@ export class ProxyField<T extends RefField> extends ObjectField {
private failed = false;
private promise?: Promise<any>;
- value(callback?: ((field: T | undefined) => void)): T | undefined | FieldWaiting {
+ value(): T | undefined | FieldWaiting {
if (this.cache) {
- callback && callback(this.cache);
return this.cache;
}
if (this.failed) {
@@ -64,7 +63,6 @@ export class ProxyField<T extends RefField> extends ObjectField {
return field;
}));
}
- callback && this.promise.then(callback);
return this.promise;
}
}
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 0839a823d..3d56e9374 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -3,7 +3,7 @@ import { CompiledScript, CompileScript } from "../client/util/Scripting";
import { Copy, ToScriptString, Parent, SelfProxy } from "./FieldSymbols";
import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr";
import { Deserializable } from "../client/util/SerializationHelper";
-import { computed } from "mobx";
+import { Doc } from "../new_fields/Doc";
function optional(propSchema: PropSchema) {
return custom(value => {
@@ -23,6 +23,7 @@ const optionsSchema = createSimpleSchema({
requiredType: true,
addReturn: true,
typecheck: true,
+ readonly: true,
params: optional(map(primitive()))
});
@@ -82,9 +83,9 @@ export class ScriptField extends ObjectField {
@Deserializable("computed", deserializeScript)
export class ComputedField extends ScriptField {
- @computed
- get value() {
- const val = this.script.run({ this: this[Parent] });
+ //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc
+ value(doc: Doc) {
+ const val = this.script.run({ this: doc });
if (val.success) {
return val.result;
}
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index a37abb732..cadd8f8d0 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -6,10 +6,13 @@ import { FieldValue } from "./Types";
import { RefField } from "./RefField";
import { ObjectField } from "./ObjectField";
import { action } from "mobx";
-import { Parent, OnUpdate, Update, Id, SelfProxy } from "./FieldSymbols";
+import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
import { ComputedField } from "./ScriptField";
-export const setter = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
+function _readOnlySetter(): never {
+ throw new Error("Documents can't be modified in read-only mode");
+}
+const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
if (SerializationHelper.IsSerializing()) {
target[prop] = value;
return true;
@@ -44,7 +47,8 @@ export const setter = action(function (target: any, prop: string | symbol | numb
} else {
target.__fields[prop] = value;
}
- target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } });
+ if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } });
+ else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } });
UndoManager.AddEvent({
redo: () => receiver[prop] = value,
undo: () => receiver[prop] = curValue
@@ -52,6 +56,20 @@ export const setter = action(function (target: any, prop: string | symbol | numb
return true;
});
+let _setter: (target: any, prop: string | symbol | number, value: any, receiver: any) => boolean = _setterImpl;
+
+export function makeReadOnly() {
+ _setter = _readOnlySetter;
+}
+
+export function makeEditable() {
+ _setter = _setterImpl;
+}
+
+export function setter(target: any, prop: string | symbol | number, value: any, receiver: any): boolean {
+ return _setter(target, prop, value, receiver);
+}
+
export function getter(target: any, prop: string | symbol | number, receiver: any): any {
if (typeof prop === "symbol") {
return target.__fields[prop] || target[prop];
@@ -59,25 +77,30 @@ export function getter(target: any, prop: string | symbol | number, receiver: an
if (SerializationHelper.IsSerializing()) {
return target[prop];
}
- return getField(target, prop);
+ return getFieldImpl(target, prop, receiver);
}
-export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any {
+function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any {
+ receiver = receiver || target[SelfProxy];
const field = target.__fields[prop];
if (field instanceof ProxyField) {
return field.value();
}
if (field instanceof ComputedField) {
- return field.value;
+ return field.value(receiver);
}
if (field === undefined && !ignoreProto && prop !== "proto") {
- const proto = getField(target, "proto", true);
+ const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters
if (proto instanceof Doc) {
- return proto[prop];
+ return getFieldImpl(proto[Self], prop, receiver, ignoreProto);
}
return undefined;
}
return field;
+
+}
+export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any {
+ return getFieldImpl(target, prop, undefined, ignoreProto);
}
export function deleteProperty(target: any, prop: string | number | symbol) {
@@ -85,7 +108,7 @@ export function deleteProperty(target: any, prop: string | number | symbol) {
delete target[prop];
return true;
}
- target[prop] = undefined;
+ target[SelfProxy][prop] = undefined;
return true;
}