Files
echo/src/lib/sqlite.js

128 lines
3.3 KiB
JavaScript
Raw Normal View History

2025-11-25 17:12:09 +08:00
import { Capacitor } from '@capacitor/core'
import { CapacitorSQLite, SQLiteConnection } from '@capacitor-community/sqlite'
import { defineCustomElements as defineJeep } from 'jeep-sqlite/loader'
const DB_NAME = 'echo_local'
const DB_VERSION = 1
const TRANSACTION_TABLE_SQL = `
CREATE TABLE IF NOT EXISTS transactions (
id TEXT PRIMARY KEY NOT NULL,
amount REAL NOT NULL,
merchant TEXT NOT NULL,
category TEXT DEFAULT 'Uncategorized',
date TEXT NOT NULL,
note TEXT,
sync_status INTEGER DEFAULT 0
);
`
let sqliteConnection
let db
let initialized = false
2025-11-27 10:44:27 +08:00
let jeepLoaderPromise
let jeepElementReadyPromise
const waitFor = (ms = 100) =>
new Promise((resolve) => {
setTimeout(resolve, ms)
})
const ensureStoreReady = async (jeepEl, retries = 5) => {
for (let attempt = 0; attempt < retries; attempt += 1) {
const isOpen = (await jeepEl.isStoreOpen?.()) === true
if (isOpen) return
if (typeof jeepEl.openStore === 'function') {
const opened = await jeepEl.openStore('jeepSqliteStore', 'databases')
if (opened) return
}
await waitFor(200 * (attempt + 1))
}
throw new Error('jeep-sqlite IndexedDB store 未初始化成功')
}
2025-11-25 17:12:09 +08:00
const ensureJeepElement = async () => {
2025-11-27 10:44:27 +08:00
if (!jeepLoaderPromise) {
jeepLoaderPromise = defineJeep(window)
2025-11-25 17:12:09 +08:00
}
2025-11-27 10:44:27 +08:00
await jeepLoaderPromise
if (!jeepElementReadyPromise) {
jeepElementReadyPromise = (async () => {
let jeepEl = document.querySelector('jeep-sqlite')
if (!jeepEl) {
jeepEl = document.createElement('jeep-sqlite')
jeepEl.setAttribute('auto-save', 'true')
document.body.appendChild(jeepEl)
}
jeepEl.setAttribute('wasm-path', '/assets')
await customElements.whenDefined('jeep-sqlite')
await jeepEl.componentOnReady?.()
return jeepEl
})()
2025-11-25 17:12:09 +08:00
}
2025-11-27 10:44:27 +08:00
const element = await jeepElementReadyPromise
await ensureStoreReady(element)
2025-11-25 17:12:09 +08:00
await CapacitorSQLite.initWebStore()
}
const prepareConnection = async () => {
if (!sqliteConnection) {
sqliteConnection = new SQLiteConnection(CapacitorSQLite)
}
if (Capacitor.getPlatform() === 'web') {
await ensureJeepElement()
}
const consistency = await sqliteConnection.checkConnectionsConsistency()
if (!consistency.result) {
await sqliteConnection.closeAllConnections()
}
const isConn = (await sqliteConnection.isConnection(DB_NAME, false)).result
if (isConn) {
db = await sqliteConnection.retrieveConnection(DB_NAME, false)
} else {
db = await sqliteConnection.createConnection(DB_NAME, false, 'no-encryption', DB_VERSION, false)
}
await db.open()
await db.execute(TRANSACTION_TABLE_SQL)
initialized = true
}
export const initSQLite = async () => {
if (!initialized) {
await prepareConnection()
}
return db
}
export const getDb = async () => {
if (!initialized) {
await initSQLite()
}
return db
}
2025-11-27 10:44:27 +08:00
export const saveDbToStore = async () => {
await initSQLite()
if (!sqliteConnection?.saveToStore) return
try {
await sqliteConnection.saveToStore(DB_NAME)
} catch (error) {
console.warn('[sqlite] saveToStore 执行失败,数据将保留在内存中', error)
}
}
2025-11-25 17:12:09 +08:00
export const closeSQLite = async () => {
if (db) {
await db.close()
db = null
}
initialized = false
}
export const databaseName = DB_NAME