mirror of
https://github.com/stfrigerio/sqliteDB.git
synced 2026-07-22 12:00:23 +00:00
135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
import { App, Notice, TFile, TFolder, normalizePath, FileSystemAdapter } from "obsidian";
|
|
import { DBService } from "../dbService";
|
|
import { ColumnPickerModal } from "../components/ColumnPickerModal";
|
|
|
|
/**
|
|
* Convert every row in the given table into a separate note.
|
|
* - Prompts the user to pick a column for filenames.
|
|
* - Creates a folder "<tableName>-dump" at the root of the vault.
|
|
* - For each row, creates a .md file whose name is the chosen column's value.
|
|
* - Inserts frontmatter with key:value pairs for each column.
|
|
*
|
|
* Usage:
|
|
* await convertEntriesInNotes(dbService, "MyTable", this.app);
|
|
*/
|
|
export async function convertEntriesInNotes(dbService: DBService, tableName: string, app: App) {
|
|
const db = dbService.getDB();
|
|
if (!db) {
|
|
new Notice("No DB loaded. Please open the DB first.");
|
|
return;
|
|
}
|
|
|
|
// 1) Get list of columns from the table
|
|
// PRAGMA table_info(tableName) gives columns metadata: cid, name, type, etc.
|
|
const colResult = db.exec(`PRAGMA table_info('${tableName}');`);
|
|
if (!colResult || colResult.length === 0) {
|
|
new Notice(`Could not read columns for table '${tableName}'.`);
|
|
return;
|
|
}
|
|
// colResult[0].values => array of rows, where row = [cid, name, type, ...]
|
|
const columns: string[] = colResult[0].values.map(row => row[1] as string);
|
|
if (!columns.length) {
|
|
new Notice(`No columns found in table '${tableName}'.`);
|
|
return;
|
|
}
|
|
|
|
// 2) Prompt user to pick which column is used for the note filenames
|
|
const pickColumn = async (): Promise<string | null> => {
|
|
return new Promise((resolve) => {
|
|
const modal = new ColumnPickerModal(app, columns, (col) => {
|
|
resolve(col);
|
|
});
|
|
modal.open();
|
|
});
|
|
};
|
|
|
|
const chosenColumn = await pickColumn();
|
|
if (!chosenColumn) {
|
|
new Notice("No column chosen. Aborting.");
|
|
return;
|
|
}
|
|
|
|
// 3) Create or get the folder at the root: "<tableName>-dump"
|
|
let basePath = "";
|
|
if (app.vault.adapter instanceof FileSystemAdapter) {
|
|
basePath = app.vault.adapter.getBasePath();
|
|
} else {
|
|
new Notice("This plugin only works in a local vault.");
|
|
return;
|
|
}
|
|
const folderName = `${tableName}-dump`;
|
|
const targetFolderPath = normalizePath(folderName);
|
|
|
|
// Check if folder already exists; if not, create it
|
|
let folder = app.vault.getAbstractFileByPath(targetFolderPath);
|
|
if (!folder) {
|
|
folder = await app.vault.createFolder(targetFolderPath);
|
|
} else if (!(folder instanceof TFolder)) {
|
|
new Notice(`A file named "${folderName}" already exists and is not a folder.`);
|
|
return;
|
|
}
|
|
|
|
// 4) Query *all* rows from the table
|
|
const allRowsResult = db.exec(`SELECT * FROM "${tableName}";`);
|
|
if (!allRowsResult || allRowsResult.length === 0) {
|
|
new Notice(`No rows found in table "${tableName}".`);
|
|
return;
|
|
}
|
|
|
|
const rowObj = allRowsResult[0]; // { columns: string[], values: any[][] }
|
|
const allCols = rowObj.columns; // e.g. ["id", "title", "content", ...]
|
|
const rows = rowObj.values; // array of arrays
|
|
|
|
// 5) Figure out which index corresponds to the "chosenColumn"
|
|
const columnIndex = allCols.indexOf(chosenColumn);
|
|
if (columnIndex < 0) {
|
|
new Notice(`Chosen column '${chosenColumn}' not found in table.`);
|
|
return;
|
|
}
|
|
|
|
// 6) Loop each row, create a note
|
|
let createdCount = 0;
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row = rows[i];
|
|
// The chosen column's value for the filename
|
|
let rawFileName = String(row[columnIndex]) || `Untitled_${i}`;
|
|
let safeFileName = sanitizeFilename(rawFileName) || `Untitled_${i}`;
|
|
let notePath = `${targetFolderPath}/${safeFileName}.md`;
|
|
|
|
// If file already exists, append a suffix
|
|
let suffix = 1;
|
|
while (app.vault.getAbstractFileByPath(notePath)) {
|
|
suffix++;
|
|
notePath = `${targetFolderPath}/${safeFileName}_${suffix}.md`;
|
|
}
|
|
|
|
// Build frontmatter with all columns
|
|
const frontmatterLines = ["---"];
|
|
for (let c = 0; c < allCols.length; c++) {
|
|
const colName = allCols[c];
|
|
const val = row[c] == null ? "" : String(row[c]);
|
|
// Escape special newlines or quotes if you want
|
|
frontmatterLines.push(`${colName}: ${val.replace(/\n/g, "\\n")}`);
|
|
}
|
|
frontmatterLines.push("---\n");
|
|
|
|
const fileContent = frontmatterLines.join("\n");
|
|
|
|
try {
|
|
await app.vault.create(notePath, fileContent);
|
|
createdCount++;
|
|
} catch (err) {
|
|
console.error(`Failed to create file at ${notePath}:`, err);
|
|
}
|
|
}
|
|
|
|
new Notice(`Created ${createdCount} notes in folder "${folderName}".`);
|
|
}
|
|
|
|
/**
|
|
* A quick utility to remove forbidden filename characters on Windows, etc.
|
|
*/
|
|
function sanitizeFilename(name: string): string {
|
|
// Replace slashes, backslashes, colons, etc.
|
|
return name.replace(/[\\\/:*?"<>|]/g, "_").trim();
|
|
}
|