stfrigerio_sqliteDB/main.ts

140 lines
3.5 KiB
TypeScript
Raw Normal View History

2025-01-29 18:20:48 +00:00
import {
App,
Plugin,
PluginSettingTab,
Setting,
Modal,
Notice,
FileSystemAdapter // <-- Import FileSystemAdapter
} from "obsidian";
import initSqlJs, { Database } from "sql.js";
import { readFileSync, writeFileSync } from "fs";
interface MyWasmDBSettings {
dbFilePath: string;
2025-01-29 17:35:31 +00:00
}
2025-01-29 18:20:48 +00:00
const DEFAULT_SETTINGS: MyWasmDBSettings = {
dbFilePath: "",
};
2025-01-29 17:35:31 +00:00
2025-01-29 18:20:48 +00:00
export default class MyWasmDBPlugin extends Plugin {
settings: MyWasmDBSettings;
private db: Database | null = null;
2025-01-29 17:35:31 +00:00
async onload() {
2025-01-29 18:20:48 +00:00
console.log("Loading MyWasmDBPlugin...");
2025-01-29 17:35:31 +00:00
await this.loadSettings();
this.addCommand({
2025-01-29 18:20:48 +00:00
id: "open-wasm-db",
name: "Open SQLite (WASM) DB and read a table",
callback: async () => {
await this.readDatabase();
},
2025-01-29 17:35:31 +00:00
});
2025-01-29 18:20:48 +00:00
this.addSettingTab(new MyWasmDBSettingTab(this.app, this));
2025-01-29 17:35:31 +00:00
}
onunload() {
2025-01-29 18:20:48 +00:00
console.log("Unloading MyWasmDBPlugin...");
this.db = null;
}
private async readDatabase() {
const { dbFilePath } = this.settings;
if (!dbFilePath) {
new Notice("No DB path set in plugin settings.");
return;
}
try {
// 1) Get the actual base path of the local vault, if we have a FileSystemAdapter
let basePath: string | null = null;
const adapter = this.app.vault.adapter;
if (adapter instanceof FileSystemAdapter) {
basePath = adapter.getBasePath(); // Now we can call getBasePath()
}
if (!basePath) {
new Notice("This plugin only works with a local vault (FileSystemAdapter).");
return;
}
// 2) Load the sql.js WASM module, telling it exactly where to find sql-wasm.wasm
// Suppose we've placed sql-wasm.wasm in the same folder as main.js, i.e.
// <Vault>/.obsidian/plugins/sqliteDB/sql-wasm.wasm
const SQL = await initSqlJs({
locateFile: (file) => {
// "file" will typically be "sql-wasm.wasm"
return `${basePath}/.obsidian/plugins/sqliteDB/${file}`;
},
});
// 3) Read file from disk
const fileBuffer = readFileSync(dbFilePath);
const uint8Array = new Uint8Array(fileBuffer);
// 4) Create the in-memory DB
this.db = new SQL.Database(uint8Array);
// 5) Run a sample query
const result = this.db.exec("SELECT name FROM sqlite_master WHERE type='table' LIMIT 1;");
if (result?.[0]?.values?.[0]?.[0]) {
new Notice(`Found table: ${result[0].values[0][0]}`);
} else {
new Notice("Connected, but found no tables.");
}
2025-01-29 17:35:31 +00:00
2025-01-29 18:20:48 +00:00
/* If you want to write changes back:
this.db.run("CREATE TABLE test (col1 int);");
const data = this.db.export(); // Uint8Array
writeFileSync(dbFilePath, Buffer.from(data));
*/
} catch (err) {
console.error(err);
new Notice("Error reading DB: " + (err as Error).message);
}
2025-01-29 17:35:31 +00:00
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
2025-01-29 18:20:48 +00:00
class MyWasmDBSettingTab extends PluginSettingTab {
plugin: MyWasmDBPlugin;
2025-01-29 17:35:31 +00:00
2025-01-29 18:20:48 +00:00
constructor(app: App, plugin: MyWasmDBPlugin) {
2025-01-29 17:35:31 +00:00
super(app, plugin);
this.plugin = plugin;
}
display(): void {
2025-01-29 18:20:48 +00:00
const { containerEl } = this;
2025-01-29 17:35:31 +00:00
containerEl.empty();
2025-01-29 18:20:48 +00:00
containerEl.createEl("h2", { text: "WASM DB Plugin Settings" });
2025-01-29 17:35:31 +00:00
new Setting(containerEl)
2025-01-29 18:20:48 +00:00
.setName("Database File Path")
.setDesc("Absolute path to the .db file on disk.")
.addText((text) =>
text
.setPlaceholder("C:\\path\\to\\your.db")
.setValue(this.plugin.settings.dbFilePath)
.onChange(async (value) => {
this.plugin.settings.dbFilePath = value;
await this.plugin.saveSettings();
})
);
2025-01-29 17:35:31 +00:00
}
}