added codeblock "sql" to query the db

This commit is contained in:
stfrigerio 2025-01-29 20:58:04 +01:00
parent 3706531e70
commit 62bfe308c6
3 changed files with 119 additions and 12 deletions

23
main.ts
View file

@ -8,10 +8,12 @@ import {
FileSystemAdapter,
Editor,
MarkdownView,
MarkdownPostProcessorContext
} from "obsidian";
import { DBService } from "./src/dbService";
import { inspectTableStructure, convertEntriesInNotes } from "./src/commands";
import { pickTableName } from "./src/helpers";
import { pickTableName, processSqlBlock } from "./src/helpers";
import { SqliteDBSettings, DEFAULT_SETTINGS } from "./src/types";
export default class SqliteDBPlugin extends Plugin {
@ -24,14 +26,7 @@ export default class SqliteDBPlugin extends Plugin {
this.dbService = new DBService();
//! i dont think we need this since we do it in each command
// this.addCommand({
// id: "open-db",
// name: "Open Local SQLite DB",
// callback: async () => {
// await this.openDatabase();
// },
// });
await this.openDatabase();
this.addCommand({
id: "inspect-table-structure",
@ -45,7 +40,7 @@ export default class SqliteDBPlugin extends Plugin {
this.addCommand({
id: "dump-table-to-notes",
name: "Dump Table Rows to Notes",
name: "Dump Table to Notes",
callback: async () => {
await this.openDatabase(); // ensure DB is loaded
@ -59,7 +54,13 @@ export default class SqliteDBPlugin extends Plugin {
await convertEntriesInNotes(this.dbService, chosenTable, this.app);
},
});
this.registerMarkdownCodeBlockProcessor(
"sql", // <-- the name of your code block (```sql)
async (source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => {
await processSqlBlock(this.dbService, source, el);
}
);
this.addSettingTab(new SqliteDBSettingTab(this.app, this));
}

View file

@ -1,3 +1,4 @@
import { pickTableName } from "./pickTableName";
import { processSqlBlock } from "./processSqlBlock";
export { pickTableName };
export { pickTableName, processSqlBlock };

View file

@ -0,0 +1,105 @@
import { Notice } from "obsidian";
import { DBService } from "../dbService";
/**
* Processes a code block of the form:
*
* ```sqlite
* table: MyTable
* keyColumn: id
* value: 5
* columns: col1, col2, col3
* ```
*
* - If `columns` is specified, we only select those columns.
* - Otherwise, we select all columns (*).
* - If multiple rows match, we create one table per row.
*/
export async function processSqlBlock(dbService: DBService, source: string, el: HTMLElement) {
const db = dbService.getDB();
if (!db) {
new Notice("No DB loaded. Please open the DB first.");
el.createEl("p", { text: "Database not loaded." });
return;
}
// 1) Parse code block params
const params = parseSqlParams(source);
const { table, keyColumn, value, columns } = params;
if (!table || !keyColumn || !value) {
el.createEl("p", { text: "Missing required parameters (table, keyColumn, value)." });
return;
}
// 2) Build query based on columns
// If columns was provided, we split on commas, else use "*".
let selectCols = "*";
if (columns) {
// e.g. "col1, col2" => "col1, col2"
const colList = columns.split(",").map((c) => c.trim()).join(", ");
selectCols = colList;
}
const query = `SELECT ${selectCols} FROM "${table}" WHERE "${keyColumn}" = ?;`;
const result = db.exec(query, [value]);
if (!result || result.length === 0 || result[0].values.length === 0) {
el.createEl("p", {
text: `No rows found in ${table} where ${keyColumn} = ${value}`,
});
return;
}
// result[0] => { columns: string[], values: any[][] }
const rowObj = result[0];
const columnsReturned = rowObj.columns;
const rows = rowObj.values;
// 3) For each row, create a separate table
rows.forEach((rowValues, rowIndex) => {
// Optional heading
el.createEl("h4", { text: `Row #${rowIndex + 1}` });
// Build the table for this row
const tableEl = el.createEl("table");
columnsReturned.forEach((colName, colIndex) => {
const tr = tableEl.createEl("tr");
tr.createEl("th", { text: colName });
tr.createEl("td", { text: String(rowValues[colIndex] ?? "") });
});
el.createEl("hr");
});
}
/**
* Parses the code block parameters line by line for:
* table: <string>
* keyColumn: <string>
* value: <string>
* columns: <string> (e.g. "col1, col2, col3")
*/
function parseSqlParams(source: string): {
table?: string;
keyColumn?: string;
value?: string;
columns?: string;
} {
const lines = source.split("\n");
const params: any = {};
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
const parts = trimmed.split(":").map((p) => p.trim());
if (parts.length >= 2) {
const key = parts[0];
const val = parts.slice(1).join(":"); // re-join in case there's a colon
if (["table", "keyColumn", "value", "columns"].includes(key)) {
params[key] = val;
}
}
}
return params;
}