SilverBullet pivot to become an offline-first PWA (#403)
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
import { assertEquals } from "https://deno.land/std@0.165.0/testing/asserts.ts";
|
||||
import { AsyncSQLite } from "../../plugos/sqlite/async_sqlite.ts";
|
||||
import { ensureTable, pageIndexSyscalls } from "./index.ts";
|
||||
|
||||
const fakeContext = {} as any;
|
||||
|
||||
Deno.test("Page index", async () => {
|
||||
const db = new AsyncSQLite(":memory:");
|
||||
await db.init();
|
||||
await ensureTable(db);
|
||||
const syscalls = pageIndexSyscalls(db);
|
||||
await syscalls["index.set"](fakeContext, "page1", "key1", "value1");
|
||||
assertEquals(
|
||||
"value1",
|
||||
await syscalls["index.get"](fakeContext, "page1", "key1"),
|
||||
);
|
||||
await syscalls["index.set"](fakeContext, "page1", "key1", "value2");
|
||||
assertEquals(
|
||||
"value2",
|
||||
await syscalls["index.get"](fakeContext, "page1", "key1"),
|
||||
);
|
||||
await syscalls["index.set"](fakeContext, "page1", "key2", "value1");
|
||||
assertEquals(
|
||||
[
|
||||
{ key: "key1", page: "page1", value: "value2" },
|
||||
{ key: "key2", page: "page1", value: "value1" },
|
||||
],
|
||||
await syscalls["index.queryPrefix"](fakeContext, ""),
|
||||
);
|
||||
await syscalls["index.delete"](fakeContext, "page1", "key1");
|
||||
assertEquals(
|
||||
[
|
||||
{ key: "key2", page: "page1", value: "value1" },
|
||||
],
|
||||
await syscalls["index.queryPrefix"](fakeContext, ""),
|
||||
);
|
||||
await syscalls["index.batchSet"](fakeContext, "page1", [
|
||||
{ key: "key1", value: "value1" },
|
||||
{ key: "key2", value: "value2" },
|
||||
{ key: "key3", value: "value3" },
|
||||
]);
|
||||
assertEquals(
|
||||
[
|
||||
{ key: "key1", page: "page1", value: "value1" },
|
||||
{ key: "key2", page: "page1", value: "value2" },
|
||||
{ key: "key3", page: "page1", value: "value3" },
|
||||
],
|
||||
await syscalls["index.queryPrefix"](fakeContext, ""),
|
||||
);
|
||||
db.stop();
|
||||
});
|
||||
@@ -1,123 +0,0 @@
|
||||
// import { Knex } from "knex";
|
||||
import { SysCallMapping } from "../../plugos/system.ts";
|
||||
import { Query, queryToSql } from "../../plugos/syscalls/store.sqlite.ts";
|
||||
import { ISQLite } from "../../plugos/sqlite/sqlite_interface.ts";
|
||||
|
||||
type Item = {
|
||||
page: string;
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
export type KV = {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
|
||||
const tableName = "page_index";
|
||||
|
||||
export async function ensureTable(db: ISQLite): Promise<void> {
|
||||
const result = await db.query(
|
||||
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
||||
tableName,
|
||||
);
|
||||
if (result.length === 0) {
|
||||
await db.execute(
|
||||
`CREATE TABLE ${tableName} (key STRING, page STRING, value TEXT, PRIMARY KEY (page, key));`,
|
||||
);
|
||||
await db.execute(
|
||||
`CREATE INDEX ${tableName}_idx ON ${tableName}(key);`,
|
||||
);
|
||||
// console.log(`Created table ${tableName}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function pageIndexSyscalls(db: ISQLite): SysCallMapping {
|
||||
const apiObj: SysCallMapping = {
|
||||
"index.set": async (_ctx, page: string, key: string, value: any) => {
|
||||
await db.execute(
|
||||
`INSERT INTO ${tableName}
|
||||
(page, key, value)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(page, key)
|
||||
DO UPDATE SET value=excluded.value`,
|
||||
page,
|
||||
key,
|
||||
JSON.stringify(value),
|
||||
);
|
||||
},
|
||||
"index.batchSet": async (_ctx, page: string, kvs: KV[]) => {
|
||||
if (kvs.length === 0) {
|
||||
return;
|
||||
}
|
||||
const values = kvs.flatMap((
|
||||
kv,
|
||||
) => [page, kv.key, JSON.stringify(kv.value)]);
|
||||
await db.execute(
|
||||
`INSERT INTO ${tableName}
|
||||
(page, key, value)
|
||||
VALUES ${kvs.map((_) => "(?, ?, ?)").join(",")}
|
||||
ON CONFLICT(key, page)
|
||||
DO UPDATE SET value=excluded.value`,
|
||||
...values,
|
||||
);
|
||||
},
|
||||
"index.delete": async (_ctx, page: string, key: string) => {
|
||||
await db.execute(
|
||||
`DELETE FROM ${tableName} WHERE key = ? AND page = ?`,
|
||||
key,
|
||||
page,
|
||||
);
|
||||
},
|
||||
"index.get": async (_ctx, page: string, key: string) => {
|
||||
const result = await db.query(
|
||||
`SELECT value FROM ${tableName} WHERE key = ? AND page = ?`,
|
||||
key,
|
||||
page,
|
||||
);
|
||||
if (result.length) {
|
||||
return JSON.parse(result[0].value);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
"index.queryPrefix": async (_ctx, prefix: string) => {
|
||||
return (
|
||||
await db.query(
|
||||
`SELECT key, page, value FROM ${tableName} WHERE key LIKE ? ORDER BY key, page ASC`,
|
||||
`${prefix}%`,
|
||||
)
|
||||
).map(({ key, value, page }) => ({
|
||||
key,
|
||||
page,
|
||||
value: JSON.parse(value),
|
||||
}));
|
||||
},
|
||||
"index.query": async (_ctx, query: Query) => {
|
||||
const { sql, params } = queryToSql(query);
|
||||
return (
|
||||
await db.query(`SELECT key, value FROM ${tableName} ${sql}`, ...params)
|
||||
).map(({ key, value, page }: any) => ({
|
||||
key,
|
||||
page,
|
||||
value: JSON.parse(value),
|
||||
}));
|
||||
},
|
||||
"index.clearPageIndexForPage": async (ctx, page: string) => {
|
||||
await apiObj["index.deletePrefixForPage"](ctx, page, "");
|
||||
},
|
||||
"index.deletePrefixForPage": async (_ctx, page: string, prefix: string) => {
|
||||
await db.execute(
|
||||
`DELETE FROM ${tableName} WHERE key LIKE ? AND page = ?`,
|
||||
`${prefix}%`,
|
||||
page,
|
||||
);
|
||||
},
|
||||
"index.clearPageIndex": async () => {
|
||||
await db.execute(
|
||||
`DELETE FROM ${tableName}`,
|
||||
);
|
||||
},
|
||||
};
|
||||
return apiObj;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Plug } from "../../plugos/plug.ts";
|
||||
import { SysCallMapping, System } from "../../plugos/system.ts";
|
||||
|
||||
export function systemSyscalls(
|
||||
plugReloader: () => Promise<void>,
|
||||
system: System<any>,
|
||||
): SysCallMapping {
|
||||
return {
|
||||
"system.invokeFunction": (
|
||||
ctx,
|
||||
// Ignored in this context, always assuming server (this place)
|
||||
_env: string,
|
||||
name: string,
|
||||
...args: any[]
|
||||
) => {
|
||||
if (!ctx.plug) {
|
||||
throw Error("No plug associated with context");
|
||||
}
|
||||
let plug: Plug<any> | undefined = ctx.plug;
|
||||
if (name.indexOf(".") !== -1) {
|
||||
// plug name in the name
|
||||
const [plugName, functionName] = name.split(".");
|
||||
plug = system.loadedPlugs.get(plugName);
|
||||
if (!plug) {
|
||||
throw Error(`Plug ${plugName} not found`);
|
||||
}
|
||||
name = functionName;
|
||||
}
|
||||
return plug.invoke(name, args);
|
||||
},
|
||||
"system.reloadPlugs": () => {
|
||||
return plugReloader();
|
||||
},
|
||||
"system.getEnv": () => {
|
||||
return system.env;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user