94 lines
2.7 KiB
TypeScript
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 };
|
|
}
|