Files
MetonaSqlark/src/integrations/vue.ts
T

94 lines
2.7 KiB
TypeScript

// @ts-nocheck
/**
* metona-sqlark Vue Integration (v0.2.5)
* @module integrations/vue
*
* 轻量 Vue composables,需要 vue 作为 peer dependency。
*
* @example
* import { useSqlarkQuery, useSqlarkTable } from 'metona-sqlark/vue';
* import { db } from './db';
*
* const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
*/
import { MetonaSqlark } from '../core';
import { ref, watch, onMounted, onUnmounted, type Ref } from 'vue';
/** useSqlarkQuery: 执行 SQL 查询 */
export function useSqlarkQuery(
db: MetonaSqlark,
sql: string,
deps: Ref<unknown>[] = [],
): { data: Ref<Record<string, unknown>[]>; loading: Ref<boolean>; error: Ref<Error | null>; refresh: () => void } {
const data = ref<Record<string, unknown>[]>([]) as Ref<Record<string, unknown>[]>;
const loading = ref(true);
const error = ref<Error | null>(null) as Ref<Error | null>;
const execute = async () => {
loading.value = true;
try {
data.value = await db.query(sql) as Record<string, unknown>[];
error.value = null;
} catch (e) {
error.value = e as Error;
} finally {
loading.value = false;
}
};
onMounted(execute);
watch([() => sql, ...deps], execute);
return { data, loading, error, refresh: execute };
}
/** 表名合法性校验(防 SQL 注入) */
function validateTableName(name: string): string {
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
throw new Error(`Invalid table name: "${name}"`);
}
return name;
}
/** useSqlarkTable: 快速获取表数据 */
export function useSqlarkTable(
db: MetonaSqlark,
tableName: string,
): { data: Ref<Record<string, unknown>[]>; loading: Ref<boolean>; refresh: () => void } {
const { data, loading, refresh } = useSqlarkQuery(db, `SELECT * FROM ${validateTableName(tableName)}`);
return { data, loading, refresh };
}
/** useSqlarkDatabase: 创建/管理数据库实例 */
export function useSqlarkDatabase(config: import('../constants').DatabaseConfig): {
db: Ref<MetonaSqlark | null>;
ready: Ref<boolean>;
error: Ref<Error | null>;
} {
const db = ref<MetonaSqlark | null>(null) as Ref<MetonaSqlark | null>;
const ready = ref(false);
const error = ref<Error | null>(null) as Ref<Error | null>;
onMounted(async () => {
try {
const instance = new MetonaSqlark(config);
await instance.init();
db.value = instance;
ready.value = true;
} catch (e) {
error.value = e as Error;
}
});
// v0.7.3: 组件卸载时关闭数据库 —— 此前实例永不 close(连接/锁/后端句柄泄漏)
onUnmounted(() => {
const instance = db.value;
if (instance) {
instance.close().catch(() => { /* 关闭失败不阻塞卸载 */ });
}
});
return { db, ready, error };
}