diff --git a/cli/plug_run.ts b/cli/plug_run.ts index e6883bd..43db6d1 100644 --- a/cli/plug_run.ts +++ b/cli/plug_run.ts @@ -11,7 +11,7 @@ import { AssetBundle } from "../plugos/asset_bundle/bundle.ts"; import { createSandbox } from "../plugos/environments/deno_sandbox.ts"; import { CronHook } from "../plugos/hooks/cron.ts"; import { EventHook } from "../plugos/hooks/event.ts"; -import { JSONKVStore } from "../plugos/lib/kv_store.json_file.ts"; +import { DenoKVStore } from "../plugos/lib/kv_store.deno_kv.ts"; import assetSyscalls from "../plugos/syscalls/asset.ts"; import { eventSyscalls } from "../plugos/syscalls/event.ts"; import { sandboxFetchSyscalls } from "../plugos/syscalls/fetch.ts"; @@ -44,7 +44,10 @@ export async function runPlug( const cronHook = new CronHook(system); system.addHook(cronHook); - const pageIndexCalls = pageIndexSyscalls("run.db"); + const kvStore = new DenoKVStore(); + await kvStore.init("run.db"); + + const pageIndexCalls = pageIndexSyscalls(kvStore); // TODO: Add endpoint @@ -61,7 +64,6 @@ export async function runPlug( ), pageIndexCalls, ); - const kvStore = new JSONKVStore(); const space = new Space(spacePrimitives, kvStore); // Add syscalls @@ -118,7 +120,7 @@ export async function runPlug( const result = await plug.invoke(funcName, args); await system.unloadAll(); - await pageIndexCalls["index.close"]({} as any); + await kvStore.delete(); return result; } diff --git a/cli/syscalls/index.test.ts b/cli/syscalls/index.test.ts index c478df8..f26c92f 100644 --- a/cli/syscalls/index.test.ts +++ b/cli/syscalls/index.test.ts @@ -1,9 +1,12 @@ +import { DenoKVStore } from "../../plugos/lib/kv_store.deno_kv.ts"; import { assertEquals } from "../../test_deps.ts"; import { pageIndexSyscalls } from "./index.ts"; Deno.test("Test KV index", async () => { const ctx: any = {}; - const calls = pageIndexSyscalls(); + const kv = new DenoKVStore(); + await kv.init("test.db"); + const calls = pageIndexSyscalls(kv); await calls["index.set"](ctx, "page", "test", "value"); assertEquals(await calls["index.get"](ctx, "page", "test"), "value"); await calls["index.delete"](ctx, "page", "test"); @@ -24,11 +27,12 @@ Deno.test("Test KV index", async () => { }, { key: "random", value: "value3" }]); let results = await calls["index.queryPrefix"](ctx, "attr:"); assertEquals(results.length, 4); + console.log("here"); await calls["index.clearPageIndexForPage"](ctx, "page"); results = await calls["index.queryPrefix"](ctx, "attr:"); assertEquals(results.length, 2); await calls["index.clearPageIndex"](ctx); results = await calls["index.queryPrefix"](ctx, ""); assertEquals(results.length, 0); - await calls["index.close"](ctx); + await kv.delete(); }); diff --git a/cli/syscalls/index.ts b/cli/syscalls/index.ts index 3074d02..44b6c52 100644 --- a/cli/syscalls/index.ts +++ b/cli/syscalls/index.ts @@ -1,13 +1,6 @@ -/// - +import { KVStore } from "../../plugos/lib/kv_store.ts"; import type { SysCallMapping } from "../../plugos/system.ts"; -type Item = { - page: string; - key: string; - value: any; -}; - export type KV = { key: string; value: any; @@ -17,57 +10,50 @@ export type KV = { // ["index", page, key] -> value // ["indexByKey", key, page] -> value +const sep = "!"; + /** * Implements the index syscalls using Deno's KV store. * @param dbFile * @returns */ -export function pageIndexSyscalls(dbFile?: string): SysCallMapping { - const kv = Deno.openKv(dbFile); +export function pageIndexSyscalls(kv: KVStore): SysCallMapping { const apiObj: SysCallMapping = { - "index.set": async (_ctx, page: string, key: string, value: any) => { - const res = await (await kv).atomic() - .set(["index", page, key], value) - .set(["indexByKey", key, page], value) - .commit(); - if (!res.ok) { - throw res; - } + "index.set": (_ctx, page: string, key: string, value: any) => { + return kv.batchSet( + [{ + key: `index${sep}${page}${sep}${key}`, + value, + }, { + key: `indexByKey${sep}${key}${sep}${page}`, + value, + }], + ); }, "index.batchSet": async (_ctx, page: string, kvs: KV[]) => { - // await items.bulkPut(kvs); for (const { key, value } of kvs) { await apiObj["index.set"](_ctx, page, key, value); } }, - "index.delete": async (_ctx, page: string, key: string) => { - const res = await (await kv).atomic() - .delete(["index", page, key]) - .delete(["indexByKey", key, page]) - .commit(); - if (!res.ok) { - throw res; - } + "index.delete": (_ctx, page: string, key: string) => { + console.log("delete", page, key); + return kv.batchDelete([ + `index${sep}${page}${sep}${key}`, + `indexByKey${sep}${key}${sep}${page}`, + ]); }, - "index.get": async (_ctx, page: string, key: string) => { - return (await (await kv).get(["index", page, key])).value; + "index.get": (_ctx, page: string, key: string) => { + return kv.get(`index${sep}${page}${sep}${key}`); }, "index.queryPrefix": async (_ctx, prefix: string) => { const results: { key: string; page: string; value: any }[] = []; - for await ( - const result of (await kv).list({ - start: ["indexByKey", prefix], - end: [ - "indexByKey", - prefix.slice(0, -1) + - // This is a hack to get the next character in the ASCII table (e.g. "a" -> "b") - String.fromCharCode(prefix.charCodeAt(prefix.length - 1) + 1), - ], - }) + for ( + const result of await kv.queryPrefix(`indexByKey!${prefix}`) ) { + const [_ns, key, page] = result.key.split(sep); results.push({ - key: result.key[1] as string, - page: result.key[2] as string, + key, + page, value: result.value, }); } @@ -77,27 +63,22 @@ export function pageIndexSyscalls(dbFile?: string): SysCallMapping { await apiObj["index.deletePrefixForPage"](ctx, page, ""); }, "index.deletePrefixForPage": async (_ctx, page: string, prefix: string) => { - for await ( - const result of (await kv).list({ - start: ["index", page, prefix], - end: ["index", page, prefix + "~"], - }) + for ( + const result of await kv.queryPrefix( + `index${sep}${page}${sep}${prefix}`, + ) ) { - await apiObj["index.delete"](_ctx, page, result.key[2]); + console.log("GOt back this key to delete", result.key); + const [_ns, page, key] = result.key.split(sep); + await apiObj["index.delete"](_ctx, page, key); } }, "index.clearPageIndex": async (ctx) => { - for await ( - const result of (await kv).list({ - prefix: ["index"], - }) - ) { - await apiObj["index.delete"](ctx, result.key[1], result.key[2]); + for (const result of await kv.queryPrefix(`index${sep}`)) { + const [_ns, page, key] = result.key.split(sep); + await apiObj["index.delete"](ctx, page, key); } }, - "index.close": async () => { - (await kv).close(); - }, }; return apiObj; } diff --git a/website/Attributes.md b/website/Attributes.md index e2938cc..81aaa52 100644 --- a/website/Attributes.md +++ b/website/Attributes.md @@ -30,10 +30,10 @@ Depending on where these attributes appear, they attach to different things. For Example query: - -|name |lastModified |contentType |size|perm|pageAttribute| -|----------|-------------|-------------|----|--|-----| -|Attributes|1691165890257|text/markdown|1609|rw|hello| + +|name |pageAttribute| +|----------|-----| +|Attributes|hello| This attaches an attribute to an item: @@ -45,7 +45,7 @@ Example query: |name|itemAttribute|page |pos | |----|-----|----------|----| -|Item|hello|Attributes|1079| +|Item|hello|Attributes|1106| This attaches an attribute to a task: @@ -57,5 +57,5 @@ Example query: |name|done |taskAttribute|page |pos | |----|-----|-----|----------|----| -|Task|false|hello|Attributes|1355| +|Task|false|hello|Attributes|1382| diff --git a/website/Getting Started.md b/website/Getting Started.md index 0ca64d6..c89a43c 100644 --- a/website/Getting Started.md +++ b/website/Getting Started.md @@ -20,21 +20,21 @@ Hadn’t we mentioned [[Markdown]] yet? Yeah, that’s the markup language you You will notice this whole page section is wrapped in a strange type of block. This is a SilverBullet specific feature called a [[🔌 Directive]] (in this case `#use`). There are various types of directives, and while we’re not keeping score, likely the coolest ones are [[🔌 Directive/Query|queries]] — so you should definitely look into those. -Don’t believe me, check this out, here’s a list of (max 10) pages in your space ordered by last modified date, it updates (somewhat) dynamically 🤯. Create some new pages and come back here to see that it works: +Don’t believe me, check this out, here’s a list of (max 10) pages in your space ordered by name, it updates (somewhat) dynamically 🤯. Create some new pages and come back here to see that it works: - -|name | -|------------------| -|🔌 Directive/Query| -|Attributes | -|Getting Started | -|🔌 Core/Tags | -|🔌 Github | -|🔌 Mattermost | -|🔌 Git | -|🔌 Ghost | -|🔌 Share | -|Install | + +|name | +|---------------| +|API | +|Attributes | +|Authelia | +|Authentication | +|CHANGELOG | +|Cloud Links | +|Deployments | +|Federation | +|Frontmatter | +|Getting Started| That said, the directive used wrapping this page section is `#use` which uses the content of another page as a template and inlines it. Directives recalculate their bodies in two scenarios: