From 5a9e437bbd175b36a161e1d96c8ae873dfe6d105 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 22 Apr 2019 03:39:39 -0400 Subject: More --- src/new_fields/Doc.ts | 13 ++++++++++--- src/new_fields/List.ts | 5 +++-- src/new_fields/Schema.ts | 20 ++++++++++++++++---- src/new_fields/Types.ts | 27 +++++++++++++++------------ 4 files changed, 44 insertions(+), 21 deletions(-) (limited to 'src/new_fields') diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 5d18cbb2e..60abccce6 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -4,7 +4,7 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/ import { Utils } from "../Utils"; import { DocServer } from "../client/DocServer"; import { setter, getter, getField } from "./util"; -import { Cast, FieldCtor } from "./Types"; +import { Cast, ToConstructor } from "./Types"; export type FieldId = string; export const HandleUpdate = Symbol("HandleUpdate"); @@ -28,6 +28,7 @@ export const Parent = Symbol("Parent"); export class ObjectField { protected [OnUpdate]?: (diff?: any) => void; private [Parent]?: Doc; + readonly [Id] = ""; } export type Field = number | string | boolean | ObjectField | RefField; @@ -71,7 +72,7 @@ export namespace Doc { const self = doc[Self]; return new Promise(res => getField(self, key, ignoreProto, res)); } - export function GetTAsync(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): Promise { + export function GetTAsync(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): Promise { return new Promise(async res => { const field = await GetAsync(doc, key, ignoreProto); return Cast(field, ctor); @@ -81,9 +82,15 @@ export namespace Doc { const self = doc[Self]; return getField(self, key, ignoreProto); } - export function GetT(doc: Doc, key: string, ctor: FieldCtor, ignoreProto: boolean = false): T | null | undefined { + export function GetT(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): T | null | undefined { return Cast(Get(doc, key, ignoreProto), ctor) as T | null | undefined; } + export async function SetOnPrototype(doc: Doc, key: string, value: Field) { + const proto = await Cast(doc.prototype, Doc); + if (proto) { + proto[key] = value; + } + } export function MakeDelegate(doc: Opt): Opt { if (!doc) { return undefined; diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts index 58b252f7b..f3ec9e2c5 100644 --- a/src/new_fields/List.ts +++ b/src/new_fields/List.ts @@ -6,8 +6,9 @@ import { observable } from "mobx"; @Deserializable("list") class ListImpl extends ObjectField { - constructor() { + constructor(fields: T[] = []) { super(); + this.__fields = fields; const list = new Proxy(this, { set: setter, get: getter, @@ -21,7 +22,7 @@ class ListImpl extends ObjectField { @serializable(alias("fields", list(autoObject()))) @observable - private __fields: (T | null | undefined)[] = []; + private __fields: (T | null | undefined)[]; private [Update] = (diff: any) => { console.log(diff); diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts index 3b7078cb0..59c6db0bd 100644 --- a/src/new_fields/Schema.ts +++ b/src/new_fields/Schema.ts @@ -1,5 +1,7 @@ -import { Interface, ToInterface, Cast, FieldCtor, ToConstructor, HasTail, Head, Tail } from "./Types"; +import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType } from "./Types"; import { Doc, Field, ObjectField } from "./Doc"; +import { URLField } from "./URLField"; +import { List } from "./List"; type AllToInterface = { 1: ToInterface> & AllToInterface>, @@ -10,10 +12,10 @@ export const emptySchema = createSchema({}); export const Document = makeInterface(emptySchema); export type Document = makeInterface<[typeof emptySchema]>; -export type makeInterface = Partial> & U; +export type makeInterface = Partial> & Doc; // export function makeInterface(schemas: T): (doc: U) => All; // export function makeInterface(schema: T): (doc: U) => makeInterface; -export function makeInterface(...schemas: T): (doc: U) => makeInterface { +export function makeInterface(...schemas: T): (doc: Doc) => makeInterface { let schema: Interface = {}; for (const s of schemas) { for (const key in s) { @@ -33,7 +35,10 @@ export function makeInterface(...schemas: return true; } }); - return function (doc: any) { + return function (doc: Doc) { + if (!(doc instanceof Doc)) { + throw new Error("Currently wrapping a schema in another schema isn't supported"); + } const obj = Object.create(proto, { doc: { value: doc, writable: false } }); return obj; }; @@ -59,6 +64,9 @@ export function makeStrictInterface(schema: T): (doc: Doc) }); } return function (doc: any) { + if (!(doc instanceof Doc)) { + throw new Error("Currently wrapping a schema in another schema isn't supported"); + } const obj = Object.create(proto); obj.__doc = doc; return obj; @@ -69,3 +77,7 @@ export function createSchema(schema: T): T & { prototype: T schema.prototype = Doc; return schema as any; } + +export function listSpec>(type: U): ListSpec> { + return { List: type as any };//TODO Types +} \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index f4f66fe5c..fbf002c84 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -1,25 +1,28 @@ import { Field, Opt, FieldWaiting, FieldResult } from "./Doc"; import { List } from "./List"; -export type ToType = +export type ToType | ListSpec> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends ListSpec ? List : // T extends { new(...args: any[]): infer R } ? (R | Promise) : never; + T extends { new(...args: any[]): List } ? never : T extends { new(...args: any[]): infer R } ? R : never; -export type ToConstructor = +export type ToConstructor = T extends string ? "string" : T extends number ? "number" : - T extends boolean ? "boolean" : new (...args: any[]) => T; + T extends boolean ? "boolean" : + T extends List ? ListSpec : + new (...args: any[]) => T; -export type ToInterface = { +export type ToInterface = { [P in keyof T]: ToType; }; -// type ListSpec = { List: FieldCtor> | ListSpec> }; -export type ListSpec = { List: FieldCtor }; +// type ListSpec = { List: ToContructor> | ListSpec> }; +export type ListSpec = { List: ToConstructor }; // type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; @@ -34,11 +37,9 @@ export interface Interface { // [key: string]: ToConstructor | ListSpec; } -export type FieldCtor = T extends List ? ListSpec : ToConstructor; - -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult>; -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType): ToType; -export function Cast>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType): FieldResult> | undefined { +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T): FieldResult>; +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal: ToType): ToType; +export function Cast | ListSpec>(field: Field | FieldWaiting | undefined, ctor: T, defaultVal?: ToType): FieldResult> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) : defaultVal; } @@ -58,7 +59,9 @@ export function Cast>(field: Field | FieldWaiting | u return defaultVal; } -export function FieldValue(field: Opt | Promise>, defaultValue: U): T; +type WithoutList = T extends List ? R[] : T; + +export function FieldValue>(field: Opt | Promise>, defaultValue: U): WithoutList; export function FieldValue(field: Opt | Promise>): Opt; export function FieldValue(field: Opt | Promise>, defaultValue?: T): Opt { return field instanceof Promise ? defaultValue : field; -- cgit v1.2.3-70-g09d2