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.startup = function() {
var path = require("path");
// Install the sqlite3 global namespace
$tw.sqlite3 = {
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");
return;
}
// Compute the database path
var databasePath = path.resolve($tw.boot.wikiPath,"database.sqlite");
// Create and initialise the tiddler store
var SqlTiddlerStore = require("$:/plugins/tiddlywiki/multiwikiserver/sql-tiddler-store.js").SqlTiddlerStore;
$tw.sqlTiddlerStore = new SqlTiddlerStore({});
$tw.sqlTiddlerStore = new SqlTiddlerStore({
databasePath: databasePath
});
$tw.sqlTiddlerStore.createTables();
// Create bags and recipes
$tw.sqlTiddlerStore.saveBag("bag-alpha");
$tw.sqlTiddlerStore.saveBag("bag-beta");
$tw.sqlTiddlerStore.saveBag("bag-gamma");
$tw.sqlTiddlerStore.saveRecipe("recipe-rho",["bag-alpha","bag-beta"]);
$tw.sqlTiddlerStore.saveRecipe("recipe-sigma",["bag-alpha","bag-gamma"]);
$tw.sqlTiddlerStore.createBag("bag-alpha");
$tw.sqlTiddlerStore.createBag("bag-beta");
$tw.sqlTiddlerStore.createBag("bag-gamma");
$tw.sqlTiddlerStore.createRecipe("recipe-rho",["bag-alpha","bag-beta"]);
$tw.sqlTiddlerStore.createRecipe("recipe-sigma",["bag-alpha","bag-gamma"]);
$tw.sqlTiddlerStore.createRecipe("recipe-tau",["bag-alpha"]);
// Save tiddlers
$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");

View File

@ -9,9 +9,16 @@ Functions to perform basic tiddler operations with a sqlite3 database
(function() {
/*
Create a tiddler store. Options include:
databasePath - path to the database file (can be ":memory:" to get a temporary database)
*/
function SqlTiddlerStore(options) {
options = options || {};
var databasePath = options.databasePath || ":memory:";
// 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() {
@ -103,34 +110,51 @@ SqlTiddlerStore.prototype.logTables = function() {
}
};
SqlTiddlerStore.prototype.saveBag = function(bagname) {
SqlTiddlerStore.prototype.createBag = function(bagname) {
// Run the queries
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,
accesscontrol: "[some access control stuff]"
});
};
SqlTiddlerStore.prototype.saveRecipe = function(recipename,bagnames) {
SqlTiddlerStore.prototype.createRecipe = function(recipename,bagnames) {
// Run the queries
this.runStatement(`
-- Insert or replace the recipe with the given name
INSERT OR REPLACE INTO recipes (recipe_name)
-- Create the entry in the recipes table if required
INSERT OR IGNORE INTO recipes (recipe_name)
VALUES ($recipe_name)
`,{
recipe_name: recipename
});
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)
SELECT r.recipe_id, b.bag_id, j.key
FROM (
SELECT * FROM json_each($bag_names)
) AS j
JOIN bags AS b ON b.bag_name = j.value
JOIN recipes AS r ON r.recipe_name = $recipe_name;
SELECT r.recipe_id, b.bag_id, j.key as position
FROM recipes r
JOIN bags b
LEFT JOIN json_each($bag_names) AS j ON j.value = b.bag_name
WHERE r.recipe_name = $recipe_name
`,{
recipe_name: recipename,
bag_names: JSON.stringify(bagnames)

View File

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