h-sphere_sql-seal/src/codeblockHandler/CodeblockProcessor.ts

97 lines
3.3 KiB
TypeScript
Raw Normal View History

2025-01-09 12:32:24 +00:00
import { OmnibusRegistrator } from "@hypersphere/omnibus";
import { App, MarkdownPostProcessorContext, MarkdownRenderChild } from "obsidian";
import { SqlSealDatabase } from "src/database/database";
import { Sync } from "src/datamodel/sync";
2025-01-09 12:53:26 +00:00
import { transformQuery } from "src/sql/transformer";
2025-01-09 12:32:24 +00:00
import { parseLanguage, Table } from "src/grammar/newParser";
import { RendererRegistry, RenderReturn } from "src/renderer/rendererRegistry";
import { displayError, displayNotice } from "src/utils/ui";
2025-01-09 12:32:24 +00:00
export class CodeblockProcessor extends MarkdownRenderChild {
registrator: OmnibusRegistrator
renderer: RenderReturn
constructor(
private el: HTMLElement,
private source: string,
private ctx: MarkdownPostProcessorContext,
private rendererRegistry: RendererRegistry,
private db: SqlSealDatabase,
private app: App,
private sync: Sync) {
super(el)
this.registrator = this.sync.getRegistrator()
}
query: string;
async onload() {
try {
const results = parseLanguage(this.source)
if (results.tables) {
await this.registerTables(results.tables)
if (!results.queryPart) {
displayNotice(this.el, `Creating tables: ${results.tables.map(t => t.tableName).join(', ')}`)
return
}
}
this.renderer = this.rendererRegistry.prepareRender(results.intermediateContent)(this.el)
// FIXME: probably should save the one before transform and perform transform every time we execute it.
this.query = results.queryPart
await this.render()
} catch (e) {
displayError(this.el, e.toString())
}
}
onunload() {
this.registrator.offAll()
}
async render() {
try {
const registeredTablesForContext = await this.sync.getTablesMappingForContext(this.ctx.sourcePath)
const tranformedQuery = transformQuery(this.query, registeredTablesForContext)
this.registrator.offAll()
Object.values(registeredTablesForContext).forEach(v => {
this.registrator.on(`change::${v}`, () => {
this.render()
})
this.registrator.on('file::change::'+this.ctx.sourcePath, () => {
sleep(250).then(() => this.render())
})
})
const file = this.app.vault.getFileByPath(this.ctx.sourcePath)
if (!file) {
return
}
const fileCache = this.app.metadataCache.getFileCache(file)
const { data, columns } = await this.db.select(tranformedQuery, fileCache?.frontmatter ?? {})
this.renderer.render({ data, columns })
} catch (e) {
this.renderer.error(e.toString())
}
}
async registerTables(tables: Table[]) {
await Promise.all(tables.map((table) => {
const path = this.app.metadataCache.getFirstLinkpathDest(table.fileName, this.ctx.sourcePath)
if (!path) {
throw new Error(`File does not exist: ${table.fileName} (for ${table.tableName}).`)
}
return this.sync.registerTable({
aliasName: table.tableName,
fileName: path.path,
sourceFile: this.ctx.sourcePath
})
}))
}
}