chore: fixing library after reviews

This commit is contained in:
Kacper Kula 2024-05-12 20:01:30 +01:00
parent c6ffe7870c
commit 0b4369e607
10 changed files with 152 additions and 133 deletions

View file

@ -3,4 +3,4 @@
Here are some known issues and resolutions to it
## I have changed my file but the changes are not reflected in files table
Sometimes changes might not be properly added to the `files` table. If this happens, you can call `SQLSeal: Reload Vault Database` command (using `CTRL + P` / `CMD + P` shortcut to activate command window). If this does not help, please report an issue on project page with details.
Sometimes changes might not be properly added to the `files` table. If this happens, you can call `SQLSeal: Reload vault database` command (using `CTRL + P` / `CMD + P` shortcut to activate command window). If this does not help, please report an issue on project page with details.

View file

@ -1,5 +1,5 @@
{
"id": "hypersphere-sqlseal",
"id": "sqlseal",
"name": "SQLSeal",
"version": "0.2.0",
"minAppVersion": "0.15.0",

View file

@ -1,6 +1,5 @@
{
"name": "obsidian-sqlseal",
"name": "sqlseal",
"version": "0.2.0",
"description": "A plugin for Obsidian that allows you to run SQL queries on your notes.",
"main": "main.js",
@ -38,7 +37,6 @@
},
"dependencies": {
"better-sqlite3": "^9.5.0",
"gray-matter": "^4.0.3",
"node-sql-parser": "^5.0.0",
"papaparse": "^5.4.1"
}

View file

@ -8,9 +8,6 @@ dependencies:
better-sqlite3:
specifier: ^9.5.0
version: 9.6.0
gray-matter:
specifier: ^4.0.3
version: 4.0.3
node-sql-parser:
specifier: ^5.0.0
version: 5.1.0
@ -1501,12 +1498,6 @@ packages:
readable-stream: 3.6.2
dev: true
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: false
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
@ -2082,12 +2073,6 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
@ -2130,13 +2115,6 @@ packages:
resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
dev: true
/extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
dependencies:
is-extendable: 0.1.1
dev: false
/extract-zip@2.0.1:
resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
engines: {node: '>= 10.17.0'}
@ -2437,16 +2415,6 @@ packages:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: true
/gray-matter@4.0.3:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
dependencies:
js-yaml: 3.14.1
kind-of: 6.0.3
section-matter: 1.0.0
strip-bom-string: 1.0.0
dev: false
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@ -2591,11 +2559,6 @@ packages:
sprintf-js: 1.1.3
dev: true
/is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
dev: false
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@ -2641,14 +2604,6 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: false
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -2698,11 +2653,6 @@ packages:
json-buffer: 3.0.1
dev: true
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
dev: false
/levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
@ -3380,14 +3330,6 @@ packages:
resolution: {integrity: sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==}
dev: true
/section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
dependencies:
extend-shallow: 2.0.1
kind-of: 6.0.3
dev: false
/semver-compare@1.0.0:
resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==}
requiresBuild: true
@ -3497,10 +3439,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: false
/sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
dev: true
@ -3533,11 +3471,6 @@ packages:
ansi-regex: 5.0.1
dev: true
/strip-bom-string@1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
engines: {node: '>=0.10.0'}
dev: false
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}

View file

@ -1,16 +1,5 @@
import { App, EventRef, Plugin, TAbstractFile, TFile } from "obsidian";
import GrayMatter from "gray-matter";
import { SqlSeal } from "./sqlSeal";
import { delay } from "./utils";
async function extractFrontmatterFromFile(file: TAbstractFile) {
const content = await this.app.vault.read(file);
const gm = GrayMatter(content)
return gm.data
}
function fileData(file: TAbstractFile, frontmatter: Record<string, any>) {
return {
@ -21,18 +10,21 @@ function fileData(file: TAbstractFile, frontmatter: Record<string, any>) {
}
}
const extractFrontmatterFromFile = async (file: TFile, plugin: Plugin) => {
return plugin.app.metadataCache.getFileCache(file)?.frontmatter || {}
}
export class SealFileSync {
private currentSchema: Record<string, 'TEXT' | 'INTEGER' | 'REAL'> = {}
private refs: Array<EventRef> = []
constructor(public readonly app: App, private readonly sqlSeal: SqlSeal, private readonly plugin: Plugin) {
this.refs.push(this.app.vault.on('modify', async (file) => {
plugin.registerEvent(this.app.vault.on('modify', async (file) => {
if (!(file instanceof TFile)) {
return
}
const frontmatter = await extractFrontmatterFromFile(file)
const frontmatter = extractFrontmatterFromFile(file, plugin)
if (this.hasNewColumns(frontmatter)) {
await delay(1000)
await sleep(1000)
await this.init()
return
@ -45,20 +37,20 @@ export class SealFileSync {
// Wait 1 second before updating tags table
await delay(1000)
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.sqlSeal.observer.fireObservers('table:tags')
}))
this.refs.push(this.app.vault.on('create', async (file) => {
plugin.registerEvent(this.app.vault.on('create', async (file) => {
if (!(file instanceof TFile)) {
return
}
const frontmatter = await extractFrontmatterFromFile(file)
const frontmatter = await extractFrontmatterFromFile(file, plugin)
if (this.hasNewColumns(frontmatter)) {
await delay(1000)
await sleep(1000)
await this.init()
return
@ -70,12 +62,12 @@ export class SealFileSync {
this.sqlSeal.observer.fireObservers('table:files')
// Wait 1 second before updating tags table
await delay(1000)
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.sqlSeal.observer.fireObservers('table:tags')
}))
this.refs.push(this.app.vault.on('delete', async (file) => {
plugin.registerEvent(this.app.vault.on('delete', async (file) => {
if (!(file instanceof TFile)) {
return
}
@ -87,7 +79,7 @@ export class SealFileSync {
this.sqlSeal.observer.fireObservers('table:tags')
}))
this.refs.push(this.app.vault.on('rename', async (file, oldPath) => {
plugin.registerEvent(this.app.vault.on('rename', async (file, oldPath) => {
if (!(file instanceof TFile)) {
return
}
@ -98,11 +90,11 @@ export class SealFileSync {
// delete old tags
await this.sqlSeal.db.deleteData('tags', [{ fileId: oldPath }], 'fileId')
await this.sqlSeal.db.insertData('files', [fileData(file, await extractFrontmatterFromFile(file))])
await this.sqlSeal.db.insertData('files', [fileData(file, await extractFrontmatterFromFile(file, this.plugin))])
this.sqlSeal.observer.fireObservers('table:files')
// Wait 1 second before updating tags table
await delay(1000)
await sleep(1000)
await this.sqlSeal.db.insertData('tags', await this.getFileTags(file))
this.sqlSeal.observer.fireObservers('table:tags')
@ -111,17 +103,13 @@ export class SealFileSync {
// add Obsidian command to reload SQLSeal file database
this.plugin.addCommand({
id: 'reload-sqlseal',
name: 'Reload Vault Database',
name: 'Reload vault database',
callback: async () => {
await this.init()
}
})
}
destroy() {
this.refs.forEach(ref => this.app.vault.offref(ref))
}
async getFileTags(file: TFile) {
return (this.app.metadataCache.getFileCache(file)?.tags || [])
.map(t => t.tag)
@ -135,7 +123,7 @@ export class SealFileSync {
const tags: Array<{fileId: string, tag: string }> = []
for (const file of files) {
const frontmatter = await extractFrontmatterFromFile(file)
const frontmatter = await extractFrontmatterFromFile(file, this.plugin)
tags.push(...await this.getFileTags(file))
data.push(fileData(file, frontmatter))
}

View file

@ -1,10 +1,10 @@
import Database from "better-sqlite3"
import { App } from "obsidian"
import { App, normalizePath } from "obsidian"
import path from 'path'
import Papa from 'papaparse'
import { prefixedIfNotGlobal } from "./sqlReparseTables"
import fs from 'fs'
import { delay, fetchBlobData } from "./utils"
import { fetchBlobData } from "./utils"
function isNumeric(str: string) {
if (typeof str != "string") return false // we only process strings!
@ -81,19 +81,21 @@ export class SqlSealDatabase {
this.connectingPromiseResolve = resolve
})
//@ts-ignore
const dbPath = path.resolve(this.app.vault.adapter.basePath, this.app.vault.configDir, "plugins/sqlseal/better_sqlite3.node")
const dbPath = normalizePath(this.app.vault.adapter.basePath + '/' + this.app.vault.configDir + '/sqlseal.db')
// const dbPath = path.resolve(this.app.vault.adapter.basePath, this.app.vault.configDir, "plugins/sqlseal/better_sqlite3.node")
// check if file "better_sqlite3.node" exists in the plugin folder, if not, download it from github release
if (!fs.existsSync(dbPath)) {
const url = 'https://github.com/h-sphere/sql-seal/releases/download/0.2.0/better_sqlite3.node' // my github release url
// if (!fs.existsSync(dbPath)) {
// const url = 'https://github.com/h-sphere/sql-seal/releases/download/0.2.0/better_sqlite3.node' // my github release url
await fetchBlobData(url, dbPath)
}
// await fetchBlobData(url, dbPath)
// }
await delay(500)
// await sleep(500)
//@ts-ignore
const defaultDbPath = path.resolve(this.app.vault.adapter.basePath, this.app.vault.configDir, "sqlseal.db")
this.db = new Database(defaultDbPath, { verbose: this.verbose ? console.log : undefined })
// //@ts-ignore
// const defaultDbPath = path.resolve(this.app.vault.adapter.basePath, this.app.vault.configDir, "sqlseal.db")
this.db = new Database(dbPath, { verbose: this.verbose ? console.log : undefined })
this.isConnected = true
this.connectingPromiseResolve()

View file

@ -1,10 +1,118 @@
import * as crypto from 'crypto';
export const hashString = (path: string) => {
const hash = crypto.createHash('sha256')
hash.update(path)
return hash.digest('hex')
export function hashString(inputString: string): string {
// Function to convert a number to alphanumeric character
function toAlphanumeric(num: number): string {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
return chars[num % chars.length];
}
// Function to generate SHA-256 hash
function sha256(input: string): string {
// Simple SHA-256 implementation
function sha256Internal(input: string): string {
function rightRotate(value: number, shift: number): number {
return (value >>> shift) | (value << (32 - shift));
}
function toHexString(num: number): string {
let hex = '';
for (let i = 0; i < 8; i++) {
hex += ((num >>> (24 - i * 4)) & 0xf).toString(16);
}
return hex;
}
const words: number[] = [];
for (let i = 0; i < input.length * 8; i += 8) {
words[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (24 - i % 32);
}
words[input.length >> 2] |= 0x80 << (24 - (input.length % 4) * 8);
words[((input.length + 64 >> 9) << 4) + 15] = input.length * 8;
let a = 0x6a09e667;
let b = 0xbb67ae85;
let c = 0x3c6ef372;
let d = 0xa54ff53a;
let e = 0x510e527f;
let f = 0x9b05688c;
let g = 0x1f83d9ab;
let h = 0x5be0cd19;
for (let i = 0; i < words.length; i += 16) {
let aa = a;
let bb = b;
let cc = c;
let dd = d;
let ee = e;
let ff = f;
let gg = g;
let hh = h;
for (let j = 0; j < 64; j++) {
let T1 = hh + ((ee & ff) | (~ee & gg)) + words[i + j] + K[j];
T1 = T1 | 0;
let T2 = rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25);
T2 = T2 | 0;
let T3 = (e & f) ^ (~e & g);
T3 = T3 | 0;
let T4 = h + T1 + T2 + T3 + H[j];
T4 = T4 | 0;
h = g;
g = f;
f = e;
e = d + T4;
e = e | 0;
d = c;
c = b;
b = a;
a = T4 + T1;
a = a | 0;
}
a = a + aa;
b = b + bb;
c = c + cc;
d = d + dd;
e = e + ee;
f = f + ff;
g = g + gg;
h = h + hh;
}
return toHexString(a) + toHexString(b) + toHexString(c) + toHexString(d) +
toHexString(e) + toHexString(f) + toHexString(g) + toHexString(h);
}
// Convert the SHA-256 hash to alphanumeric characters
function hashToAlphanumeric(hash: string): string {
return hash.replace(/[^\w]/g, '');
}
return hashToAlphanumeric(sha256Internal(input));
}
// Constants for SHA-256
const K = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
const H = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
return sha256(inputString);
}
export const generatePrefix = (prefix: string, tableName: string) => {
return `TTT${prefix}_${tableName}`
}

View file

@ -25,14 +25,12 @@ export class SqlSealSettingsTab extends PluginSettingTab {
containerEl.empty();
containerEl.createEl('h2', { text: 'My Plugin Settings' });
new Setting(containerEl)
.setName('Rows')
.setDesc('Configure your rows')
.addButton((button: ButtonComponent) => {
button
.setButtonText('Add Row')
.setButtonText('Add row')
.onClick(async () => {
this.plugin.settings.rows.push({ name: '', type: 'File', dynamicField: '' });
await this.plugin.saveSettings();
@ -74,10 +72,10 @@ export class SqlSealSettingsTab extends PluginSettingTab {
if (row.type === 'File') {
new Setting(rowContainer)
.setName('File Selector')
.setName('File selector')
.addText(text => {
text
.setPlaceholder('Select File')
.setPlaceholder('Select file')
.setValue(row.dynamicField)
.onChange(async (value) => {
this.plugin.settings.rows[index].dynamicField = value;

View file

@ -1,4 +1,3 @@
import GrayMatter from "gray-matter";
import { SqlSealDatabase } from "./database";
import { displayData, displayError, displayInfo, displayLoader } from "./ui";
import { App, MarkdownPostProcessorContext } from "obsidian";
@ -36,11 +35,7 @@ export class SqlSeal {
if (!file) {
return null
}
const data = await this.app.vault.cachedRead(file)
const gm = GrayMatter(data)
const frontmatter = gm.data
return frontmatter
return this.app.metadataCache.getFileCache(file)?.frontmatter
}
@ -99,7 +94,6 @@ export class SqlSeal {
displayLoader(el)
// await delay(1000)
await renderSelect()
}

View file

@ -48,6 +48,4 @@ export const fetchBlobData = async (url: string, filePath: string) => {
reject(`Error writing to ${filePath}: ${err}`)
});
})
};
export const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
};