From a335cc05265bd35a780d059b0466c1650583ccda Mon Sep 17 00:00:00 2001 From: Anselm Date: Wed, 19 Jul 2023 17:16:13 +0100 Subject: [PATCH] Structural types for CoMap --- src/cojsonValue.ts | 57 ++++++++++++++++++++++------------------- src/permissions.test.ts | 10 ++++---- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/cojsonValue.ts b/src/cojsonValue.ts index 37f65f353..a9466a17c 100644 --- a/src/cojsonValue.ts +++ b/src/cojsonValue.ts @@ -6,7 +6,7 @@ export type CoValueID = MultiLogID & { }; export type CoValue = - | CoMap + | CoMap<{[key: string]: JsonValue}, JsonValue> | CoList | MultiStream | Static; @@ -30,49 +30,52 @@ export type MapOpPayload = }; export class CoMap< - K extends string, - V extends JsonValue, - Meta extends JsonValue + M extends {[key: string]: JsonValue}, + Meta extends JsonValue, + K extends string = keyof M & string, + V extends JsonValue = M[K], + MM extends {[key: string]: JsonValue} = {[KK in K]: M[KK]} > { - id: CoValueID>; + id: CoValueID>; multiLog: MultiLog; type: "comap" = "comap"; - ops: Map[]>; + ops: {[KK in K]?: MapOp[]}; constructor(multiLog: MultiLog) { - this.id = multiLog.id as CoValueID>; + this.id = multiLog.id as CoValueID>; this.multiLog = multiLog; - this.ops = new Map(); + this.ops = {}; this.fillOpsFromMultilog(); } protected fillOpsFromMultilog() { for (const { txID, changes, madeAt } of this.multiLog.getValidSortedTransactions()) { - for (const [changeIdx, change] of ( - changes as MapOpPayload[] + for (const [changeIdx, changeUntyped] of ( + changes ).entries()) { - let entries = this.ops.get(change.key); + const change = changeUntyped as MapOpPayload + let entries = this.ops[change.key]; if (!entries) { entries = []; - this.ops.set(change.key, entries); + this.ops[change.key] = entries; } entries.push({ txID, madeAt, changeIdx, - ...change, + ...(change as any), }); } } } - keys(): IterableIterator { - return this.ops.keys(); + keys(): K[] { + return Object.keys(this.ops) as K[]; } - get(key: K): V | undefined { - const ops = this.ops.get(key); + get(key: KK): M[KK] | undefined { + const ops = this.ops[key]; if (!ops) { return undefined; } @@ -86,8 +89,8 @@ export class CoMap< } } - getAtTime(key: K, time: number): V | undefined { - const ops = this.ops.get(key); + getAtTime(key: KK, time: number): M[KK] | undefined { + const ops = this.ops[key]; if (!ops) { return undefined; } @@ -118,19 +121,21 @@ export class CoMap< return json; } - edit(changer: (editable: WriteableCoMap) => void): void { - const editable = new WriteableCoMap(this.multiLog); + edit(changer: (editable: WriteableCoMap) => void): void { + const editable = new WriteableCoMap(this.multiLog); changer(editable); } } export class WriteableCoMap< - K extends string, - V extends JsonValue, - Meta extends JsonValue -> extends CoMap { + M extends {[key: string]: JsonValue}, + Meta extends JsonValue, + K extends string = keyof M & string, + V extends JsonValue = M[K], + MM extends {[key: string]: JsonValue} = {[KK in K]: M[KK]} +> extends CoMap { // TODO: change default to private - set(key: K, value: V, privacy: "private" | "trusting" = "trusting"): void { + set(key: KK, value: M[KK], privacy: "private" | "trusting" = "trusting"): void { this.multiLog.makeTransaction([ { op: "insert", diff --git a/src/permissions.test.ts b/src/permissions.test.ts index 9a18cfacc..e2cb6b336 100644 --- a/src/permissions.test.ts +++ b/src/permissions.test.ts @@ -56,20 +56,20 @@ function newTeam() { return { node, team, admin, adminID }; } -function expectTeam(content: CoJsonValue): CoMap { +function expectTeam(content: CoJsonValue): CoMap<{[key: AgentID]: Role}, {}> { if (content.type !== "comap") { throw new Error("Expected map"); } - return content as CoMap; + return content as CoMap<{[key: AgentID]: Role}, {}>; } -function expectMap(content: CoJsonValue): CoMap { +function expectMap(content: CoJsonValue): CoMap<{[key: string]: string}, {}> { if (content.type !== "comap") { throw new Error("Expected map"); } - return content as CoMap; + return content as CoMap<{[key: string]: string}, {}>; } test("Initial admin can add another admin to a team", () => { @@ -304,4 +304,4 @@ test("Readers can not write to an object that is owned by their team", () => { childContent = expectMap(childObjectAsReader.getCurrentContent()); expect(childContent.get("foo")).toBeUndefined(); -}); +}); \ No newline at end of file