279 lines
7.3 KiB
TypeScript
279 lines
7.3 KiB
TypeScript
import "fake-indexeddb/auto";
|
|
import { IndexedDBKvPrimitives } from "../data/indexeddb_kv_primitives.ts";
|
|
import { DenoKvPrimitives } from "../data/deno_kv_primitives.ts";
|
|
import type { KvPrimitives } from "../data/kv_primitives.ts";
|
|
import { assertEquals, assertThrows } from "@std/assert";
|
|
import { PrefixedKvPrimitives } from "../data/prefixed_kv_primitives.ts";
|
|
import type { Query } from "../../plug-api/types.ts";
|
|
import { DataStore } from "$lib/data/datastore.ts";
|
|
|
|
async function test(db: KvPrimitives) {
|
|
const datastore = new DataStore(new PrefixedKvPrimitives(db, ["ds"]), {
|
|
count: (arr: any[]) => arr.length,
|
|
$query: (_query: Query) => {
|
|
return Promise.resolve([]);
|
|
},
|
|
});
|
|
await datastore.set(["user", "peter"], { name: "Peter" });
|
|
await datastore.set(["user", "hank"], { name: "Hank" });
|
|
let results = await datastore.query({
|
|
prefix: ["user"],
|
|
filter: ["=", ["attr", "name"], ["string", "Peter"]],
|
|
});
|
|
assertEquals(results, [{ key: ["user", "peter"], value: { name: "Peter" } }]);
|
|
|
|
assertEquals(
|
|
[{ key: ["user", "hank"], value: { name: "Hank" } }, {
|
|
key: ["user", "peter"],
|
|
value: { name: "Peter" },
|
|
}],
|
|
await datastore.query({
|
|
prefix: ["user"],
|
|
orderBy: [{ expr: ["attr", "name"], desc: false }],
|
|
}),
|
|
);
|
|
assertEquals(
|
|
[{ key: ["user", "peter"], value: { name: "Peter" } }, {
|
|
key: ["user", "hank"],
|
|
value: { name: "Hank" },
|
|
}],
|
|
await datastore.query({
|
|
prefix: ["user"],
|
|
orderBy: [{ expr: ["attr", "name"], desc: true }],
|
|
}),
|
|
);
|
|
|
|
await datastore.batchSet<any>([
|
|
{ key: ["kv", "name"], value: "Zef" },
|
|
{ key: ["kv", "data"], value: new Uint8Array([1, 2, 3]) },
|
|
{
|
|
key: ["kv", "complicated"],
|
|
value: {
|
|
name: "Frank",
|
|
parents: ["John", "Jane"],
|
|
address: {
|
|
street: "123 Main St",
|
|
city: "San Francisco",
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
assertEquals(await datastore.get(["kv", "name"]), "Zef");
|
|
assertEquals(await datastore.get(["kv", "data"]), new Uint8Array([1, 2, 3]));
|
|
results = await datastore.query({
|
|
prefix: ["kv"],
|
|
filter: ["=~", ["attr", ""], ["regexp", "Z.f", "i"]],
|
|
});
|
|
assertEquals(results, [{ key: ["kv", "name"], value: "Zef" }]);
|
|
results = await datastore.query({
|
|
prefix: ["kv"],
|
|
filter: ["and", ["=", ["attr", "parents"], ["string", "John"]], [
|
|
"=",
|
|
["attr", ["attr", "address"], "city"],
|
|
["string", "San Francisco"],
|
|
]],
|
|
select: [
|
|
{ name: "parents" },
|
|
{
|
|
name: "name",
|
|
expr: ["+", ["attr", "name"], ["string", "!"]],
|
|
},
|
|
{
|
|
name: "parentCount",
|
|
expr: ["call", "count", [["attr", "parents"]]],
|
|
},
|
|
],
|
|
});
|
|
assertEquals(results.length, 1);
|
|
assertEquals(results[0], {
|
|
key: ["kv", "complicated"],
|
|
value: { name: "Frank!", parentCount: 2, parents: ["John", "Jane"] },
|
|
});
|
|
|
|
assertEquals(
|
|
await datastore.query({
|
|
prefix: ["kv"],
|
|
limit: ["number", 1],
|
|
select: [
|
|
{
|
|
name: "random",
|
|
expr: ["query", { querySource: "bla" }],
|
|
},
|
|
],
|
|
}),
|
|
[{ key: ["kv", "complicated"], value: { random: [] } }],
|
|
);
|
|
|
|
// Test object enrichment
|
|
datastore.objectDecorators = [{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
pageDecoration: {
|
|
prefix: ["string", "🧑 "],
|
|
},
|
|
list: ["array", [["number", 2]]],
|
|
},
|
|
}];
|
|
|
|
const simplePage = {
|
|
name: "My Page",
|
|
pageDecoration: {
|
|
hide: true,
|
|
},
|
|
list: [1],
|
|
};
|
|
const enrichedPage = datastore.enrichObject(simplePage);
|
|
assertEquals(enrichedPage.name, "My Page");
|
|
assertEquals(enrichedPage.pageDecoration.hide, true);
|
|
assertEquals(enrichedPage.pageDecoration.prefix, "🧑 ");
|
|
assertEquals(enrichedPage.list, [1, 2]);
|
|
// console.log("Enriched page", enrichedPage);
|
|
|
|
// More complicated case
|
|
datastore.objectDecorators = [
|
|
{ // fullName
|
|
where: ["=", ["attr", "tags"], ["string", "person"]],
|
|
attributes: {
|
|
fullName: ["+", ["+", ["attr", "firstName"], ["string", " "]], [
|
|
"attr",
|
|
"lastName",
|
|
]],
|
|
},
|
|
},
|
|
{
|
|
where: ["=", ["attr", "tags"], ["string", "person"]],
|
|
attributes: {
|
|
pageDecoration: {
|
|
prefix: {
|
|
bla: {
|
|
doh: ["+", ["string", "🧑 "], ["attr", "fullName"]],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// Test extending existing array attributes
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
listAttribute: ["array", [["string", "newValue1"]]],
|
|
nested: {
|
|
listAttribute1: ["array", [["string", "newValue 1"]]],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
listAttribute: ["array", [["string", "newValue2"]]],
|
|
nested: {
|
|
listAttribute1: ["array", [["string", "newValue 2"]]],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
nested: {
|
|
listAttribute1: ["array", [["string", "newValue 3"]]],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
nested: {
|
|
deeper: {
|
|
listAttribute2: ["array", [["string", "newValue 1"]]],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
nested: {
|
|
deeper: {
|
|
listAttribute2: ["array", [["string", "newValue 2"]]],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// Test not being able to override existing attributes
|
|
{
|
|
where: ["boolean", true],
|
|
attributes: {
|
|
lastName: ["string", "Shouldn't be set"],
|
|
},
|
|
},
|
|
{
|
|
where: ["=", ["attr", "tags"], ["string", "person"]],
|
|
attributes: {
|
|
existingObjAttribute: {
|
|
another: ["string", "value"],
|
|
},
|
|
},
|
|
},
|
|
];
|
|
|
|
let obj: Record<string, any> = {
|
|
firstName: "Pete",
|
|
lastName: "Smith",
|
|
pageDecoration: {},
|
|
existingObjAttribute: {
|
|
something: true,
|
|
},
|
|
tags: ["person"],
|
|
};
|
|
const pristineCopy = JSON.parse(JSON.stringify(obj));
|
|
|
|
obj = datastore.enrichObject(obj);
|
|
// console.log("Enrhiched", obj);
|
|
assertEquals(obj.fullName, "Pete Smith");
|
|
assertEquals(obj.lastName, "Smith");
|
|
assertEquals(obj.pageDecoration.prefix.bla.doh, "🧑 Pete Smith");
|
|
assertEquals(obj.existingObjAttribute.something, true);
|
|
assertEquals(obj.existingObjAttribute.another, "value");
|
|
assertEquals(obj.listAttribute, ["newValue1", "newValue2"]);
|
|
assertEquals(obj.nested.listAttribute1, [
|
|
"newValue 1",
|
|
"newValue 2",
|
|
"newValue 3",
|
|
]);
|
|
|
|
// And now let's clean it again
|
|
datastore.cleanEnrichedObject(obj);
|
|
|
|
assertEquals(obj, pristineCopy);
|
|
|
|
// Validate no async functions are called in the object enrichment
|
|
datastore.objectDecorators = [
|
|
{
|
|
where: ["call", "$query", []],
|
|
attributes: {},
|
|
},
|
|
];
|
|
|
|
assertThrows(() => {
|
|
datastore.enrichObject({});
|
|
});
|
|
}
|
|
|
|
Deno.test("Test Deno KV DataStore", async () => {
|
|
const tmpFile = await Deno.makeTempFile();
|
|
const db = new DenoKvPrimitives(await Deno.openKv(tmpFile));
|
|
await test(db);
|
|
db.close();
|
|
await Deno.remove(tmpFile);
|
|
});
|
|
|
|
Deno.test("Test IndexDB DataStore", {
|
|
sanitizeResources: false,
|
|
sanitizeOps: false,
|
|
}, async () => {
|
|
const db = new IndexedDBKvPrimitives("test");
|
|
await db.init();
|
|
await test(db);
|
|
db.close();
|
|
});
|