Use a persistent disk-based database

This commit is contained in:
Jeremy Ruston 2024-01-05 10:58:07 +00:00
parent e9d3f67c5c
commit 68a89b615d
3 changed files with 55 additions and 24 deletions

View File

@ -19,6 +19,7 @@ exports.before = ["story"];
exports.synchronous = true; exports.synchronous = true;
exports.startup = function() { exports.startup = function() {
var path = require("path");
// Install the sqlite3 global namespace // Install the sqlite3 global namespace
$tw.sqlite3 = { $tw.sqlite3 = {
Database: null Database: null
@ -33,16 +34,21 @@ exports.startup = function() {
logger.alert("The plugin 'tiddlywiki/multiwikiserver' requires the better-sqlite3 npm package to be installed. Run 'npm install' in the root of the TiddlyWiki repository"); logger.alert("The plugin 'tiddlywiki/multiwikiserver' requires the better-sqlite3 npm package to be installed. Run 'npm install' in the root of the TiddlyWiki repository");
return; return;
} }
// Compute the database path
var databasePath = path.resolve($tw.boot.wikiPath,"database.sqlite");
// Create and initialise the tiddler store // Create and initialise the tiddler store
var SqlTiddlerStore = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-store.js").SqlTiddlerStore; var SqlTiddlerStore = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-store.js").SqlTiddlerStore;
$tw.sqlTiddlerStore = new SqlTiddlerStore({}); $tw.sqlTiddlerStore = new SqlTiddlerStore({
databasePath: databasePath
});
$tw.sqlTiddlerStore.createTables(); $tw.sqlTiddlerStore.createTables();
// Create bags and recipes // Create bags and recipes
$tw.sqlTiddlerStore.saveBag("bag-alpha"); $tw.sqlTiddlerStore.createBag("bag-alpha");
$tw.sqlTiddlerStore.saveBag("bag-beta"); $tw.sqlTiddlerStore.createBag("bag-beta");
$tw.sqlTiddlerStore.saveBag("bag-gamma"); $tw.sqlTiddlerStore.createBag("bag-gamma");
$tw.sqlTiddlerStore.saveRecipe("recipe-rho",["bag-alpha","bag-beta"]); $tw.sqlTiddlerStore.createRecipe("recipe-rho",["bag-alpha","bag-beta"]);
$tw.sqlTiddlerStore.saveRecipe("recipe-sigma",["bag-alpha","bag-gamma"]); $tw.sqlTiddlerStore.createRecipe("recipe-sigma",["bag-alpha","bag-gamma"]);
$tw.sqlTiddlerStore.createRecipe("recipe-tau",["bag-alpha"]);
// Save tiddlers // Save tiddlers
$tw.sqlTiddlerStore.saveTiddler({title: "Another Tiddler",text: "I'm in alpha",tags: "one two three"},"bag-alpha"); $tw.sqlTiddlerStore.saveTiddler({title: "Another Tiddler",text: "I'm in alpha",tags: "one two three"},"bag-alpha");
$tw.sqlTiddlerStore.saveTiddler({title: "Hello There",text: "I'm in alpha as well",tags: "one two three"},"bag-alpha"); $tw.sqlTiddlerStore.saveTiddler({title: "Hello There",text: "I'm in alpha as well",tags: "one two three"},"bag-alpha");

View File

@ -9,9 +9,16 @@ Functions to perform basic tiddler operations with a sqlite3 database
(function() { (function() {
/*
Create a tiddler store. Options include:
databasePath - path to the database file (can be ":memory:" to get a temporary database)
*/
function SqlTiddlerStore(options) { function SqlTiddlerStore(options) {
options = options || {};
var databasePath = options.databasePath || ":memory:";
// Create our database // Create our database
this.db = new $tw.sqlite3.Database(":memory:",{verbose: undefined && console.log}); this.db = new $tw.sqlite3.Database(databasePath,{verbose: undefined && console.log});
} }
SqlTiddlerStore.prototype.close = function() { SqlTiddlerStore.prototype.close = function() {
@ -103,34 +110,51 @@ SqlTiddlerStore.prototype.logTables = function() {
} }
}; };
SqlTiddlerStore.prototype.saveBag = function(bagname) { SqlTiddlerStore.prototype.createBag = function(bagname) {
// Run the queries // Run the queries
this.runStatement(` this.runStatement(`
INSERT OR REPLACE INTO bags (bag_name, accesscontrol) VALUES ($bag_name, $accesscontrol) INSERT OR IGNORE INTO bags (bag_name, accesscontrol)
VALUES ($bag_name, '')
`,{
bag_name: bagname
});
this.runStatement(`
UPDATE bags
SET accesscontrol = $accesscontrol
WHERE bag_name = $bag_name
`,{ `,{
bag_name: bagname, bag_name: bagname,
accesscontrol: "[some access control stuff]" accesscontrol: "[some access control stuff]"
}); });
}; };
SqlTiddlerStore.prototype.saveRecipe = function(recipename,bagnames) { SqlTiddlerStore.prototype.createRecipe = function(recipename,bagnames) {
// Run the queries // Run the queries
this.runStatement(` this.runStatement(`
-- Insert or replace the recipe with the given name -- Create the entry in the recipes table if required
INSERT OR REPLACE INTO recipes (recipe_name) INSERT OR IGNORE INTO recipes (recipe_name)
VALUES ($recipe_name) VALUES ($recipe_name)
`,{ `,{
recipe_name: recipename recipe_name: recipename
}); });
this.runStatement(` this.runStatement(`
-- Insert bag names into recipe_bags for the given recipe name -- Delete existing recipe_bags entries for this recipe
DELETE FROM recipe_bags WHERE recipe_id = (SELECT recipe_id FROM recipes WHERE recipe_name = $recipe_name)
`,{
recipe_name: recipename
});
console.log(this.runStatementGetAll(`
SELECT * FROM json_each($bag_names) AS bag
`,{
bag_names: JSON.stringify(bagnames)
}));
this.runStatement(`
INSERT INTO recipe_bags (recipe_id, bag_id, position) INSERT INTO recipe_bags (recipe_id, bag_id, position)
SELECT r.recipe_id, b.bag_id, j.key SELECT r.recipe_id, b.bag_id, j.key as position
FROM ( FROM recipes r
SELECT * FROM json_each($bag_names) JOIN bags b
) AS j LEFT JOIN json_each($bag_names) AS j ON j.value = b.bag_name
JOIN bags AS b ON b.bag_name = j.value WHERE r.recipe_name = $recipe_name
JOIN recipes AS r ON r.recipe_name = $recipe_name;
`,{ `,{
recipe_name: recipename, recipe_name: recipename,
bag_names: JSON.stringify(bagnames) bag_names: JSON.stringify(bagnames)

View File

@ -20,11 +20,12 @@ describe("SQL tiddler store", function() {
const sqlTiddlerStore = new SqlTiddlerStore({}); const sqlTiddlerStore = new SqlTiddlerStore({});
sqlTiddlerStore.createTables(); sqlTiddlerStore.createTables();
// Create bags and recipes // Create bags and recipes
sqlTiddlerStore.saveBag("bag-alpha"); sqlTiddlerStore.createBag("bag-alpha");
sqlTiddlerStore.saveBag("bag-beta"); sqlTiddlerStore.createBag("bag-beta");
sqlTiddlerStore.saveBag("bag-gamma"); sqlTiddlerStore.createBag("bag-gamma");
sqlTiddlerStore.saveRecipe("recipe-rho",["bag-alpha","bag-beta"]); sqlTiddlerStore.createRecipe("recipe-rho",["bag-gamma"]);
sqlTiddlerStore.saveRecipe("recipe-sigma",["bag-alpha","bag-gamma"]); sqlTiddlerStore.createRecipe("recipe-rho",["bag-alpha","bag-beta"]);
sqlTiddlerStore.createRecipe("recipe-sigma",["bag-alpha","bag-gamma"]);
// Tear down // Tear down
afterAll(function() { afterAll(function() {
// Close the database // Close the database