From 8e68f8c7d087da1c3aa49738048c1a2aac957b13 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Thu, 6 Mar 2025 10:33:23 +0000 Subject: [PATCH 1/5] chore: adding ability to register flags (no effect yet) --- src/main.ts | 8 ++++++++ src/pluginApi/sqlSealApi.ts | 18 ++++++++++++++++++ src/renderer/rendererRegistry.ts | 14 ++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/src/main.ts b/src/main.ts index bff6efb..6df33e4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -208,6 +208,14 @@ export default class SqlSealPlugin extends Plugin { this.cellParserRegistar.unregister(name) } + registerSQLSealFlag(name: string, restType: string) { + this.rendererRegistry.registerFlag(name, restType) + } + + unregisterSQLSealFlag(name: string) { + this.rendererRegistry.unregisterFlag(name) + } + async registerTable(plugin: Plugin, name: string, columns: columns) { const hash = await FilepathHasher.sha256(`${plugin.manifest.name}`) const tableName = `external_table_${hash}_name` diff --git a/src/pluginApi/sqlSealApi.ts b/src/pluginApi/sqlSealApi.ts index 70ee5c3..6896880 100644 --- a/src/pluginApi/sqlSealApi.ts +++ b/src/pluginApi/sqlSealApi.ts @@ -41,9 +41,15 @@ interface RegisteredFunction { fn: CallableFunction } +interface RegisteredFlag { + name: string, + restType: string +} + export class SQLSealApi { private views: Array = [] private functions: Array = [] + private flags: Array = [] constructor(private readonly plugin: Plugin, private sqlSealPlugin: SqlSealPlugin) { plugin.register(() => { @@ -71,6 +77,14 @@ export class SQLSealApi { return this.sqlSealPlugin.registerTable(this.plugin, tableName, columns) } + registerFlag(name: string, restType: string) { + this.flags.push({ + name, + restType + }) + this.sqlSealPlugin.registerSQLSealFlag(name, restType) + } + unregister() { for(const view of this.views) { this.sqlSealPlugin.unregisterSQLSealView(view.name) @@ -80,5 +94,9 @@ export class SQLSealApi { for(const fn of this.functions) { this.sqlSealPlugin.unregisterSQLSealFunction(fn.name) } + + for(const flag of this.flags) { + this.sqlSealPlugin.unregisterSQLSealFlag(flag.name) + } } } diff --git a/src/renderer/rendererRegistry.ts b/src/renderer/rendererRegistry.ts index 9952ff6..98e546c 100644 --- a/src/renderer/rendererRegistry.ts +++ b/src/renderer/rendererRegistry.ts @@ -16,9 +16,15 @@ export interface RendererConfig = Record = new Map() renderersByKey: Map = new Map() + _extraFlags: Array = [] constructor() { } private default = 'grid' @@ -35,6 +41,14 @@ export class RendererRegistry { this.renderersByKey.set(config.rendererKey, config) } + registerFlag(name: string, restType: string) { + this._extraFlags.push({ name, restType }) + } + + unregisterFlag(name: string) { + this._extraFlags = this._extraFlags.filter(f => f.name !== name) + } + unregister(uniqueName: string) { if (!this.renderers.has(uniqueName)) { throw new Error(`Renderer not registered: ${uniqueName}`) From 8b203c1c851db33593dc9e7416b912bea4971599 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Fri, 14 Mar 2025 10:21:35 +0000 Subject: [PATCH 2/5] feat: adding ability to register new flags and exposing them to the renderer --- CHANGELOG.md | 3 + src/codeblockHandler/CodeblockProcessor.ts | 5 +- src/datamodel/sync.ts | 2 - src/editorExtension/syntaxHighlight.ts | 4 +- src/grammar/parser.ts | 98 +++++++++++++--------- src/main.ts | 6 +- src/pluginApi/sqlSealApi.ts | 14 ++-- src/renderer/rendererRegistry.ts | 12 ++- 8 files changed, 82 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7a6139..d3c0c60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Fixes: - Fixed parsing arguments to the `file` function. Now parameters with symbols like `[]*` should work properly (i.e. JSONPath arguments) +Internal: +- Ability for external plugins to register flags + # 0.27.0 (2025-02-17) - Better syntax highlighting! Now it highlights SQL query parts - Support for comments. You can now add comments like `--` and `/* */` to you queries diff --git a/src/codeblockHandler/CodeblockProcessor.ts b/src/codeblockHandler/CodeblockProcessor.ts index 676fb61..57b60b0 100644 --- a/src/codeblockHandler/CodeblockProcessor.ts +++ b/src/codeblockHandler/CodeblockProcessor.ts @@ -47,7 +47,7 @@ export class CodeblockProcessor extends MarkdownRenderChild { } - const results = parseWithDefaults(this.source, this.rendererRegistry.getViewDefinitions(), defaults) + const results = parseWithDefaults(this.source, this.rendererRegistry.getViewDefinitions(), defaults, this.rendererRegistry.flags) // const results = parseLanguage(this.source, this.ctx.sourcePath) if (results.tables) { @@ -59,7 +59,6 @@ export class CodeblockProcessor extends MarkdownRenderChild { } this.flags = results.flags - let rendererEl = this.el if (this.flags.explain) { @@ -116,7 +115,7 @@ export class CodeblockProcessor extends MarkdownRenderChild { } const { data, columns } = await this.db.select(transformedQuery, fileCache?.frontmatter ?? {}) - this.renderer.render({ data, columns }) + this.renderer.render({ data, columns, flags: this.flags }) } catch (e) { this.renderer.error(e.toString()) } diff --git a/src/datamodel/sync.ts b/src/datamodel/sync.ts index 2662f53..3a86f77 100644 --- a/src/datamodel/sync.ts +++ b/src/datamodel/sync.ts @@ -154,7 +154,6 @@ export class Sync { // TODO: THIS PART SHOULD BE REWRITTEN SOONish const existingTableLog = await this.tableMapLog.getByAlias(reg.sourceFile, reg.tableAlias) if (!existingTableLog) { - // console.log(`Registering new mapping ${reg.sourceFile} :: ${reg.tableAlias} -> ${tableName}`) // Create new one await this.tableMapLog.insert({ alias_name: reg.tableAlias, @@ -164,7 +163,6 @@ export class Sync { } else { // Check if it is the same mapping if (existingTableLog.table_name !== tableName) { - // console.log(`Alias ${reg.sourceFile} :: ${reg.tableAlias} changed table, now it should refer to ${tableName})`) await this.tableMapLog.deleteMapping(existingTableLog.id) await this.tableMapLog.insert({ alias_name: reg.tableAlias, diff --git a/src/editorExtension/syntaxHighlight.ts b/src/editorExtension/syntaxHighlight.ts index d1ad92e..e935110 100644 --- a/src/editorExtension/syntaxHighlight.ts +++ b/src/editorExtension/syntaxHighlight.ts @@ -50,8 +50,8 @@ export class SQLSealViewPlugin implements PluginValue { destroy(): void { } - private parseWithGrammar(sql: string): Decorator[] { - const grammar = ohm.grammar(SQLSealLangDefinition(this.renderers.getViewDefinitions(), true)) + private parseWithGrammar(sql: string) { + const grammar = ohm.grammar(SQLSealLangDefinition(this.renderers.getViewDefinitions(), this.renderers.flags, true)); // FIXME: extend grammar with error line. diff --git a/src/grammar/parser.ts b/src/grammar/parser.ts index c9eca13..97e3c9a 100644 --- a/src/grammar/parser.ts +++ b/src/grammar/parser.ts @@ -1,4 +1,5 @@ import * as ohm from 'ohm-js'; +import { Flag } from 'src/renderer/rendererRegistry'; export interface ViewDefinition { name: string, @@ -10,13 +11,20 @@ const viewName = (view: ViewDefinition) => `caseInsensitive<"${view.name}">` -export const SQLSealLangDefinition = (views: ViewDefinition[], enableErrors: boolean = false) => { +export const SQLSealLangDefinition = (views: ViewDefinition[], flags: readonly Flag[] = [], enableErrors: boolean = false) => { const viewsDefinitions = views .map(view => view.singleLine ? `#(${viewName(view)} ${view.argument})` - : `${viewName(view)} ${view.argument}`) + : `${viewName(view)} ${view.argument}`) .join(' | ') + + const flagsDefinitions = flags.map(flag => { + return `caseInsensitive<"${flag.name}"> -- ${flag.key}` + }).join(' \n| ') + + + return String.raw` SQLSealLang { Grammar = (TableExpression | ViewExpression | FlagExpression | blank ${enableErrors ? '| errorLine' : ''})* SelectStmt* @@ -24,6 +32,7 @@ export const SQLSealLangDefinition = (views: ViewDefinition[], enableErrors: boo FlagExpression = caseInsensitive<"REFRESH"> -- refresh | caseInsensitive<"NO REFRESH"> -- norefresh | caseInsensitive<"EXPLAIN"> -- explain + ${flags.length ? '| ExtraFlags -- extraFlags' : ''} TableExpression = tableKeyword identifier "=" TableDefinition TableDefinition = fileOpening NonemptyListOf tableDefinitionClosing -- file | tableOpening alnum+ tableDefinitionClosing -- mdtable @@ -38,6 +47,7 @@ export const SQLSealLangDefinition = (views: ViewDefinition[], enableErrors: boo | (~ ("," | ")") any)+ -- unquoted ViewExpression = ${viewsDefinitions} + ExtraFlags = ${flagsDefinitions} anyObject = "{" (~selectKeyword any)* handlebarsTemplate = (~selectKeyword any)* selectKeyword = caseInsensitive<"WITH"> | caseInsensitive<"SELECT"> @@ -57,36 +67,36 @@ export const SQLSealLangDefinition = (views: ViewDefinition[], enableErrors: boo const generateSemantic = (grammar: ohm.Grammar) => { const s = grammar.createSemantics() - s.addOperation('toObject', { - Grammar: (entries, selectStatement) => { - const res = { - flags: { - }, - renderer: { - name: 'GRID', - options: '' - }, - tables: [] as any[], - query: '' - } - if (entries.children.length) { - entries.children.forEach(c => { - switch (c.ctorName) { - case 'TableExpression': - res.tables.push(c.toObject()) - break; - case 'ViewExpression': - res.renderer = c.toObject() - break - case 'FlagExpression': - res.flags = {...res.flags, ...c.toObject()} - break - } - }) - } - if (selectStatement) { - res.query = selectStatement.sourceString - } + const operations: ohm.ActionDict = { + Grammar: (entries, selectStatement) => { + const res = { + flags: { + }, + renderer: { + name: 'GRID', + options: '' + }, + tables: [] as any[], + query: '' + } + if (entries.children.length) { + entries.children.forEach(c => { + switch (c.ctorName) { + case 'TableExpression': + res.tables.push(c.toObject()) + break; + case 'ViewExpression': + res.renderer = c.toObject() + break + case 'FlagExpression': + res.flags = { ...res.flags, ...c.toObject() } + break + } + }) + } + if (selectStatement) { + res.query = selectStatement.sourceString + } return res }, @@ -128,8 +138,16 @@ const generateSemantic = (grammar: ohm.Grammar) => { listElement_unquoted: (v) => v.sourceString, _terminal() { return this.sourceString - } - }) + } + } + if ((grammar.rules['ExtraFlags'].body as any).ruleName) { + operations.ExtraFlags = (flag) => { + const key = flag.ctorName.substring('ExtraFlags_'.length) + return { [key]: true } + } + } + + s.addOperation('toObject', operations) return s } @@ -153,8 +171,8 @@ export interface ParserResult { tables: Array } -export const parse = (query: string, views: ViewDefinition[]) => { - const grammar = ohm.grammar(SQLSealLangDefinition(views)) +export const parse = (query: string, views: ViewDefinition[], flags: readonly Flag[] = []) => { + const grammar = ohm.grammar(SQLSealLangDefinition(views, flags)) const match = grammar.match(query) if (match.succeeded()) { // Converting @@ -166,12 +184,12 @@ export const parse = (query: string, views: ViewDefinition[]) => { } -export const parseWithDefaults = (query: string, views: ViewDefinition[], defaultvalues: ParserResult): ParserResult => { - const parsed = parse(query, views) +export const parseWithDefaults = (query: string, views: ViewDefinition[], defaultvalues: ParserResult, flags: readonly Flag[] = []): ParserResult => { + const parsed = parse(query, views, flags) return { - flags: {...defaultvalues.flags, ...parsed.flags}, + flags: { ...defaultvalues.flags, ...parsed.flags }, query: parsed.query || defaultvalues.query, - renderer: {...defaultvalues.renderer, ...parsed.renderer}, + renderer: { ...defaultvalues.renderer, ...parsed.renderer }, tables: parsed.tables ?? [] } satisfies ParserResult } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 6df33e4..86e3379 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ import { Menu, Plugin, TAbstractFile, TFile } from 'obsidian'; import { GridRenderer } from './renderer/GridRenderer'; import { MarkdownRenderer } from './renderer/MarkdownRenderer'; import { TableRenderer } from './renderer/TableRenderer'; -import { RendererConfig, RendererRegistry } from './renderer/rendererRegistry'; +import { Flag, RendererConfig, RendererRegistry } from './renderer/rendererRegistry'; import { DEFAULT_SETTINGS, SQLSealSettings, SQLSealSettingsTab } from './settings/SQLSealSettingsTab'; import { SqlSeal } from './sqlSeal'; import { SealFileSync } from './vaultSync/SealFileSync'; @@ -208,8 +208,8 @@ export default class SqlSealPlugin extends Plugin { this.cellParserRegistar.unregister(name) } - registerSQLSealFlag(name: string, restType: string) { - this.rendererRegistry.registerFlag(name, restType) + registerSQLSealFlag(flag: Flag) { + this.rendererRegistry.registerFlag(flag) } unregisterSQLSealFlag(name: string) { diff --git a/src/pluginApi/sqlSealApi.ts b/src/pluginApi/sqlSealApi.ts index 6896880..70f70cf 100644 --- a/src/pluginApi/sqlSealApi.ts +++ b/src/pluginApi/sqlSealApi.ts @@ -41,9 +41,10 @@ interface RegisteredFunction { fn: CallableFunction } -interface RegisteredFlag { +// TODO: use the type from registrator +export interface RegisteredFlag { name: string, - restType: string + key: string } export class SQLSealApi { @@ -77,12 +78,9 @@ export class SQLSealApi { return this.sqlSealPlugin.registerTable(this.plugin, tableName, columns) } - registerFlag(name: string, restType: string) { - this.flags.push({ - name, - restType - }) - this.sqlSealPlugin.registerSQLSealFlag(name, restType) + registerFlag(flag: RegisteredFlag) { + this.flags.push(flag) + this.sqlSealPlugin.registerSQLSealFlag(flag) } unregister() { diff --git a/src/renderer/rendererRegistry.ts b/src/renderer/rendererRegistry.ts index 98e546c..b2294b9 100644 --- a/src/renderer/rendererRegistry.ts +++ b/src/renderer/rendererRegistry.ts @@ -16,9 +16,9 @@ export interface RendererConfig = Record f.name !== name) } + get flags(): Readonly { + return this._extraFlags + } + unregister(uniqueName: string) { if (!this.renderers.has(uniqueName)) { throw new Error(`Renderer not registered: ${uniqueName}`) From ece0df6fde2eb7a6db6b2c5f2d86daa08db4b791 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Fri, 14 Mar 2025 10:22:14 +0000 Subject: [PATCH 3/5] chore: modifying changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3c0c60..174ba79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ Fixes: - Fixed parsing arguments to the `file` function. Now parameters with symbols like `[]*` should work properly (i.e. JSONPath arguments) -Internal: -- Ability for external plugins to register flags +Technical: +- Other plugins can now register flags to allow for extra configuration # 0.27.0 (2025-02-17) - Better syntax highlighting! Now it highlights SQL query parts From 6791ab01fb4bf6e6675969b0000080b188e58f7a Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Thu, 13 Mar 2025 16:18:36 +0000 Subject: [PATCH 4/5] chore: bumping up API version --- src/pluginApi/sqlSealApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pluginApi/sqlSealApi.ts b/src/pluginApi/sqlSealApi.ts index 70f70cf..1140df0 100644 --- a/src/pluginApi/sqlSealApi.ts +++ b/src/pluginApi/sqlSealApi.ts @@ -3,7 +3,7 @@ import SqlSealPlugin from "../main" import { version } from '../../package.json' import { RendererConfig } from "../renderer/rendererRegistry"; -const API_VERSION = 1; +const API_VERSION = 2; export class SQLSealRegisterApi { registeredApis: Array = [] From d1d2231f5e9199df64ccdca7fb8a952edc1ee802 Mon Sep 17 00:00:00 2001 From: Kacper Kula Date: Fri, 14 Mar 2025 10:23:51 +0000 Subject: [PATCH 5/5] chore: fixing issue with typing --- src/editorExtension/syntaxHighlight.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorExtension/syntaxHighlight.ts b/src/editorExtension/syntaxHighlight.ts index e935110..36b885f 100644 --- a/src/editorExtension/syntaxHighlight.ts +++ b/src/editorExtension/syntaxHighlight.ts @@ -50,7 +50,7 @@ export class SQLSealViewPlugin implements PluginValue { destroy(): void { } - private parseWithGrammar(sql: string) { + private parseWithGrammar(sql: string): Decorator[] { const grammar = ohm.grammar(SQLSealLangDefinition(this.renderers.getViewDefinitions(), this.renderers.flags, true)); // FIXME: extend grammar with error line.