From 87d2796d46013bb7cc947bbcff1049f50b6fde7b Mon Sep 17 00:00:00 2001 From: Bob Webb Date: Wed, 22 Jan 2025 11:10:14 +0100 Subject: [PATCH] add a basic test, fix some bugs in runtime --- packages/core/src/Canvas.ts | 2 +- packages/core/src/runtime/AbstractRuntime.ts | 4 +- packages/core/src/runtime/FunctionRuntime.ts | 10 +++++ packages/core/test/canvas.test.ts | 43 +++++++++++++++++--- packages/modeldb/src/types.ts | 1 + 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/packages/core/src/Canvas.ts b/packages/core/src/Canvas.ts index 42bdad50f..8380c34d5 100644 --- a/packages/core/src/Canvas.ts +++ b/packages/core/src/Canvas.ts @@ -4,7 +4,7 @@ import { logger } from "@libp2p/logger" import type pg from "pg" import { Signature, Action, Session, Message, Snapshot, SessionSigner, SignerCache } from "@canvas-js/interfaces" -import { AbstractModelDB, Model, ModelSchema, Effect } from "@canvas-js/modeldb" +import { AbstractModelDB, Model, ModelSchema, Effect, ContractModelSchema } from "@canvas-js/modeldb" import { SIWESigner } from "@canvas-js/chain-ethereum" import { AbstractGossipLog, GossipLogEvents, SignedMessage } from "@canvas-js/gossiplog" import type { ServiceMap, NetworkConfig } from "@canvas-js/gossiplog/libp2p" diff --git a/packages/core/src/runtime/AbstractRuntime.ts b/packages/core/src/runtime/AbstractRuntime.ts index b652828c4..770eca0e3 100644 --- a/packages/core/src/runtime/AbstractRuntime.ts +++ b/packages/core/src/runtime/AbstractRuntime.ts @@ -140,7 +140,8 @@ export abstract class AbstractRuntime { // create the two tables // operations outputSchema[`${modelName}:operations`] = { - $primary: "record_id/message_id", + $primary: "operation_id", + operation_id: "string", record_id: "string", message_id: "string", operations: "json", @@ -321,6 +322,7 @@ export abstract class AbstractRuntime { operation: "set", value: { record_id: key, + operation_id: `${key}/${executionContext.id}`, message_id: executionContext.id, operations, }, diff --git a/packages/core/src/runtime/FunctionRuntime.ts b/packages/core/src/runtime/FunctionRuntime.ts index 5e0bf1a01..f3faf0eb9 100644 --- a/packages/core/src/runtime/FunctionRuntime.ts +++ b/packages/core/src/runtime/FunctionRuntime.ts @@ -213,6 +213,10 @@ export class FunctionRuntime extends AbstractRuntim }, yjsInsert: async (model: string, key: string, index: number, content: string) => { assert(this.#context !== null, "expected this.#context !== null") + + if (this.#context.operations[model] === undefined) { + this.#context.operations[model] = {} + } if (this.#context.operations[model][key] === undefined) { this.#context.operations[model][key] = [] } @@ -224,6 +228,9 @@ export class FunctionRuntime extends AbstractRuntim }, yjsDelete: async (model: string, key: string, index: number, length: number) => { assert(this.#context !== null, "expected this.#context !== null") + if (this.#context.operations[model] === undefined) { + this.#context.operations[model] = {} + } if (this.#context.operations[model][key] === undefined) { this.#context.operations[model][key] = [] } @@ -241,6 +248,9 @@ export class FunctionRuntime extends AbstractRuntim formattingAttributes: Record, ) => { assert(this.#context !== null, "expected this.#context !== null") + if (this.#context.operations[model] === undefined) { + this.#context.operations[model] = {} + } if (this.#context.operations[model][key] === undefined) { this.#context.operations[model][key] = [] } diff --git a/packages/core/test/canvas.test.ts b/packages/core/test/canvas.test.ts index ae53cad87..75784260e 100644 --- a/packages/core/test/canvas.test.ts +++ b/packages/core/test/canvas.test.ts @@ -188,10 +188,10 @@ test("accept a manually encoded session/action with a legacy-style object arg", contract: { actions: { createMessage(db, arg) { - t.deepEqual(arg, { objectArg: '1' }) - } + t.deepEqual(arg, { objectArg: "1" }) + }, }, - models: {} + models: {}, }, topic: "com.example.app", reset: true, @@ -219,8 +219,8 @@ test("accept a manually encoded session/action with a legacy-style object arg", type: "action", did: sessionMessage.payload.did, name: "createMessage", - args: { objectArg: '1' }, - context: { timestamp: 0 } + args: { objectArg: "1" }, + context: { timestamp: 0 }, }, } const actionSignature = await session.signer.sign(actionMessage) @@ -499,3 +499,36 @@ test("open custom modeldb tables", async (t) => { await app.db.set("widgets", { id, name: "foobar" }) t.deepEqual(await app.db.get("widgets", id), { id, name: "foobar" }) }) + +test("create a contract with a yjs text table", async (t) => { + const app = await Canvas.initialize({ + contract: { + models: { + // @ts-ignore + posts: { id: "primary", content: "yjs-text" }, + }, + actions: { + createPost: (db, { key, index, content }: { key: string; index: number; content: string }) => { + db.yjsInsert("posts", key, index, content) + }, + }, + }, + + topic: "com.example.app", + schema: { widgets: { id: "primary", name: "string" } }, + }) + + t.teardown(() => app.stop()) + + await app.actions.createPost({ key: "post_1", index: 0, content: "hello world" }) + + const operations = await app.db.query("posts:operations") + const state = await app.db.query("posts:state") + + t.is(operations.length, 1) + t.is(state.length, 1) + + t.is(operations[0].record_id, "post_1") + t.is(state[0].id, "post_1") + t.is(state[0].content[0].insert, "hello world") +}) diff --git a/packages/modeldb/src/types.ts b/packages/modeldb/src/types.ts index f3ae39f3e..dfc814d41 100644 --- a/packages/modeldb/src/types.ts +++ b/packages/modeldb/src/types.ts @@ -21,6 +21,7 @@ export type PropertyType = export type IndexInit = string export type ModelSchema = Record> +export type ContractModelSchema = { [key: string]: "yjs-text" } // These are more structured representations of the schema defined by ModelSchema that are easier // to work with at runtime