h-sphere_sql-seal/src/SealFileSync.ts

172 lines
5.7 KiB
TypeScript
Raw Normal View History

import { App, EventRef, Plugin, TAbstractFile, TFile } from "obsidian";
2024-05-01 21:54:41 +00:00
import { SqlSeal } from "./sqlSeal";
import { FieldTypes } from "./utils";
import { TablesManager } from "./dataLoader/collections/tablesManager";
import { sanitise } from "./utils/sanitiseColumn";
2024-05-01 21:54:41 +00:00
function fileData(file: TAbstractFile, frontmatter: Record<string, any>) {
return {
...frontmatter,
2024-11-03 10:05:41 +00:00
tags: undefined,
2024-05-01 21:54:41 +00:00
path: file.path,
name: file.name.replace(/\.[^/.]+$/, ""),
id: file.path
}
}
2024-05-12 19:01:30 +00:00
const extractFrontmatterFromFile = async (file: TFile, plugin: Plugin) => {
const frontmatter = plugin.app.metadataCache.getFileCache(file)?.frontmatter || {}
return Object.fromEntries(
Object.entries(frontmatter)
.map(([v, s]) => ([sanitise(v), s]))
)
2024-05-12 19:01:30 +00:00
}
2024-05-01 21:54:41 +00:00
export class SealFileSync {
private currentSchema: Record<string, FieldTypes> = {}
constructor(
public readonly app: App,
private readonly sqlSeal: SqlSeal,
private readonly plugin: Plugin,
private readonly tableManager: TablesManager
) {
2024-05-12 19:01:30 +00:00
plugin.registerEvent(this.app.vault.on('modify', async (file) => {
if (!(file instanceof TFile)) {
return
}
await sleep(100)
const frontmatter = await extractFrontmatterFromFile(file, plugin)
if (this.hasNewColumns(frontmatter)) {
2024-05-12 19:01:30 +00:00
await sleep(1000)
await this.init()
return
}
// we need to update the row
await this.sqlSeal.db.updateData('files', [fileData(file, frontmatter)])
await this.sqlSeal.db.deleteData('tags', [{ fileId: file.path }], 'fileId')
this.tableManager.getTableSignal('files')(Date.now())
// Wait 1 second before updating tags table
2024-05-12 19:01:30 +00:00
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.tableManager.getTableSignal('tags')(Date.now())
}))
2024-05-12 19:01:30 +00:00
plugin.registerEvent(this.app.vault.on('create', async (file) => {
if (!(file instanceof TFile)) {
return
}
2024-05-12 19:01:30 +00:00
const frontmatter = await extractFrontmatterFromFile(file, plugin)
if (this.hasNewColumns(frontmatter)) {
2024-05-12 19:01:30 +00:00
await sleep(1000)
await this.init()
return
}
// we need to update the row
await this.sqlSeal.db.insertData('files', [fileData(file, frontmatter)])
this.tableManager.getTableSignal('files')(Date.now())
// Wait 1 second before updating tags table
2024-05-12 19:01:30 +00:00
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.tableManager.getTableSignal('tags')(Date.now())
}))
2024-05-12 19:01:30 +00:00
plugin.registerEvent(this.app.vault.on('delete', async (file) => {
if (!(file instanceof TFile)) {
2024-05-01 21:54:41 +00:00
return
}
await this.sqlSeal.db.deleteData('files', [{ id: file.path }])
this.tableManager.getTableSignal('files')(Date.now())
await this.sqlSeal.db.deleteData('tags', [{ fileId: file.path }], 'fileId')
this.tableManager.getTableSignal('tags')(Date.now())
}))
2024-05-12 19:01:30 +00:00
plugin.registerEvent(this.app.vault.on('rename', async (file, oldPath) => {
if (!(file instanceof TFile)) {
return
}
// deleting old one and adding new one
await this.sqlSeal.db.deleteData('files', [{ id: oldPath }])
// delete old tags
await this.sqlSeal.db.deleteData('tags', [{ fileId: oldPath }], 'fileId')
2024-05-12 19:01:30 +00:00
await this.sqlSeal.db.insertData('files', [fileData(file, await extractFrontmatterFromFile(file, this.plugin))])
this.tableManager.getTableSignal('files')(Date.now())
// Wait 1 second before updating tags table
2024-05-12 19:01:30 +00:00
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.tableManager.getTableSignal('tags')(Date.now())
}))
// add Obsidian command to reload SQLSeal file database
this.plugin.addCommand({
id: 'reload-sqlseal',
2024-05-12 19:01:30 +00:00
name: 'Reload vault database',
callback: async () => {
await this.init()
}
2024-05-01 21:54:41 +00:00
})
}
async getFileTags(file: TFile) {
2024-11-03 10:05:41 +00:00
const t = ((this.app.metadataCache.getFileCache(file)?.frontmatter?.tags || []) as string[])
.map(t => ({ tag: t, fileId: file.path }))
2024-11-03 10:05:41 +00:00
return t
}
2024-05-01 21:54:41 +00:00
async init() {
const files = this.app.vault.getMarkdownFiles();
const data = []
const tags: Array<{fileId: string, tag: string }> = []
2024-05-01 21:54:41 +00:00
for (const file of files) {
2024-05-12 19:01:30 +00:00
const frontmatter = await extractFrontmatterFromFile(file, this.plugin)
tags.push(...await this.getFileTags(file))
2024-05-01 21:54:41 +00:00
data.push(fileData(file, frontmatter))
}
const schema = await this.sqlSeal.db.createTableWithData('files', data)
this.currentSchema = schema
if (tags && tags.length) {
await this.sqlSeal.db.createTableWithData('tags', tags)
} else {
await this.sqlSeal.db.createTable('tags', {
'tag': 'TEXT',
'fileId': 'TEXT'
})
}
this.tableManager.getTableSignal('files')(Date.now())
this.tableManager.getTableSignal('tags')(Date.now())
2024-05-01 21:54:41 +00:00
}
hasNewColumns(newFrontmatter: Record<string, any>) {
const currentFields = Object.keys(this.currentSchema)
const newFields = Object.keys(newFrontmatter).filter(f => !currentFields.includes(f))
2024-05-01 21:54:41 +00:00
return newFields.length > 0
2024-05-01 21:54:41 +00:00
}
}