Files
edgeever/scripts/test-restore-deleted-notebook.mjs

156 lines
3.9 KiB
JavaScript

import { strict as assert } from "node:assert";
import { readFileSync } from "node:fs";
import { globSync } from "node:fs";
import { Database } from "bun:sqlite";
import worker from "../apps/api/src/index.ts";
class SqliteD1PreparedStatement {
constructor(db, sql, bindings = []) {
this.db = db;
this.sql = sql;
this.bindings = bindings;
}
bind(...bindings) {
return new SqliteD1PreparedStatement(this.db, this.sql, bindings);
}
async all() {
return {
results: this.db.query(this.sql).all(...this.bindings),
success: true,
meta: {},
};
}
async first() {
return this.db.query(this.sql).get(...this.bindings) ?? null;
}
async run() {
this.db.query(this.sql).run(...this.bindings);
return {
success: true,
meta: {},
};
}
}
class SqliteD1Database {
constructor(db) {
this.db = db;
}
prepare(sql) {
return new SqliteD1PreparedStatement(this.db, sql);
}
async batch(statements) {
const results = [];
this.db.transaction(() => {
for (const statement of statements) {
results.push(this.db.query(statement.sql).run(...statement.bindings));
}
})();
return results;
}
}
const applyMigrations = (db) => {
for (const file of globSync("migrations/*.sql").sort()) {
db.exec(readFileSync(file, "utf8"));
}
};
const createEnv = () => {
const sqlite = new Database(":memory:");
sqlite.exec("PRAGMA foreign_keys = ON");
applyMigrations(sqlite);
return {
sqlite,
env: {
DB: new SqliteD1Database(sqlite),
EDGE_EVER_ALLOW_UNAUTHENTICATED: "true",
RESOURCES: {
delete: async () => undefined,
get: async () => null,
put: async () => undefined,
},
},
};
};
const fetchWorker = async (env, path, init = {}) =>
worker.fetch(
new Request(`https://edgeever.test${path}`, init),
env,
{
waitUntil: () => undefined,
passThroughOnException: () => undefined,
}
);
const assertStatus = async (response, status) => {
if (response.status !== status) {
assert.fail(`Expected status ${status}, got ${response.status}: ${await response.text()}`);
}
};
const { sqlite, env } = createEnv();
sqlite.run(
`INSERT INTO notebooks (id, parent_id, name, slug, icon, color, sort_order)
VALUES ('nb_bug', NULL, 'Bug Notebook', 'bug-notebook', 'notebook', '#000000', 99)`
);
sqlite.run(
`INSERT INTO memos (id, notebook_id, title, excerpt, tags_json, created_by, updated_by)
VALUES ('memo_bug', 'nb_bug', 'Bug Memo', 'Bug', '[]', 'test', 'test')`
);
sqlite.run(
`INSERT INTO memo_contents (memo_id, content_json, content_markdown, content_text, content_hash, revision)
VALUES (
'memo_bug',
'{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Bug"}]}]}',
'Bug',
'Bug',
'hash',
0
)`
);
sqlite.run(
`INSERT INTO memo_search_documents (memo_id, title, content_text, tags)
VALUES ('memo_bug', 'Bug Memo', 'Bug', '')`
);
let response = await fetchWorker(env, "/api/v1/memos/memo_bug", { method: "DELETE" });
await assertStatus(response, 200);
response = await fetchWorker(env, "/api/v1/notebooks/nb_bug", { method: "DELETE" });
await assertStatus(response, 200);
response = await fetchWorker(env, "/api/v1/memos/memo_bug/restore", { method: "POST" });
await assertStatus(response, 200);
const body = await response.json();
assert.equal(body.memo.id, "memo_bug");
assert.equal(body.memo.isDeleted, false);
assert.equal(body.memo.notebookId, "nb_inbox");
const restored = sqlite
.query(
`SELECT m.notebook_id, m.is_deleted, deleted_notebook.is_deleted AS old_notebook_deleted
FROM memos m
INNER JOIN notebooks deleted_notebook ON deleted_notebook.id = 'nb_bug'
WHERE m.id = 'memo_bug'`
)
.get();
assert.deepEqual(restored, {
notebook_id: "nb_inbox",
is_deleted: 0,
old_notebook_deleted: 1,
});
console.log("restore-deleted-notebook regression passed");