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
|