@1api/engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/data-service.d.ts +26 -0
- package/dist/data-service.d.ts.map +1 -0
- package/dist/data-service.js +64 -0
- package/dist/data-service.js.map +1 -0
- package/dist/dynamic-sql.d.ts +21 -0
- package/dist/dynamic-sql.d.ts.map +1 -0
- package/dist/dynamic-sql.js +208 -0
- package/dist/dynamic-sql.js.map +1 -0
- package/dist/engine.d.ts +23 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +48 -0
- package/dist/engine.js.map +1 -0
- package/dist/fs-utils.d.ts +8 -0
- package/dist/fs-utils.d.ts.map +1 -0
- package/dist/fs-utils.js +14 -0
- package/dist/fs-utils.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata.d.ts +30 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +129 -0
- package/dist/metadata.js.map +1 -0
- package/dist/schema-ddl.d.ts +9 -0
- package/dist/schema-ddl.d.ts.map +1 -0
- package/dist/schema-ddl.js +47 -0
- package/dist/schema-ddl.js.map +1 -0
- package/dist/schema-reader.d.ts +10 -0
- package/dist/schema-reader.d.ts.map +1 -0
- package/dist/schema-reader.js +98 -0
- package/dist/schema-reader.js.map +1 -0
- package/dist/schema-service.d.ts +25 -0
- package/dist/schema-service.d.ts.map +1 -0
- package/dist/schema-service.js +72 -0
- package/dist/schema-service.js.map +1 -0
- package/dist/system-db.d.ts +24 -0
- package/dist/system-db.d.ts.map +1 -0
- package/dist/system-db.js +16 -0
- package/dist/system-db.js.map +1 -0
- package/dist/test-helpers.d.ts +15 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +37 -0
- package/dist/test-helpers.js.map +1 -0
- package/package.json +61 -0
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {} from 'kysely';
|
|
2
|
+
import {} from '@1api/shared';
|
|
3
|
+
import { readTableSchema } from './schema-reader.js';
|
|
4
|
+
function rowToMeta(row) {
|
|
5
|
+
return {
|
|
6
|
+
id: row.id,
|
|
7
|
+
name: row.name,
|
|
8
|
+
label: row.label,
|
|
9
|
+
primaryKey: row.primary_key,
|
|
10
|
+
fields: JSON.parse(row.fields),
|
|
11
|
+
isPublished: row.is_published === 1,
|
|
12
|
+
isEditable: row.is_editable === 1,
|
|
13
|
+
note: row.note,
|
|
14
|
+
createdAt: row.created_at,
|
|
15
|
+
updatedAt: row.updated_at,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export class MetadataStore {
|
|
19
|
+
systemDb;
|
|
20
|
+
businessRaw;
|
|
21
|
+
cache = new Map(); // 按 name 索引
|
|
22
|
+
constructor(systemDb, businessRaw) {
|
|
23
|
+
this.systemDb = systemDb;
|
|
24
|
+
this.businessRaw = businessRaw;
|
|
25
|
+
}
|
|
26
|
+
/** 预热:启动时加载全部 table_meta 到缓存 */
|
|
27
|
+
async warmup() {
|
|
28
|
+
const rows = await this.systemDb.selectFrom('table_meta').selectAll().execute();
|
|
29
|
+
this.cache.clear();
|
|
30
|
+
for (const r of rows) {
|
|
31
|
+
const meta = rowToMeta(r);
|
|
32
|
+
this.cache.set(meta.name, meta);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async listMetas() {
|
|
36
|
+
return [...this.cache.values()];
|
|
37
|
+
}
|
|
38
|
+
async getMeta(id) {
|
|
39
|
+
for (const m of this.cache.values())
|
|
40
|
+
if (m.id === id)
|
|
41
|
+
return m;
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
async getMetaByName(name) {
|
|
45
|
+
return this.cache.get(name);
|
|
46
|
+
}
|
|
47
|
+
async createMeta(input) {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
const inserted = await this.systemDb
|
|
50
|
+
.insertInto('table_meta')
|
|
51
|
+
.values({
|
|
52
|
+
name: input.name,
|
|
53
|
+
label: input.label,
|
|
54
|
+
primary_key: input.primaryKey,
|
|
55
|
+
fields: JSON.stringify(input.fields),
|
|
56
|
+
is_published: input.isPublished === false ? 0 : 1,
|
|
57
|
+
is_editable: input.isEditable === false ? 0 : 1,
|
|
58
|
+
note: input.note ?? null,
|
|
59
|
+
created_at: now,
|
|
60
|
+
updated_at: now,
|
|
61
|
+
})
|
|
62
|
+
.returningAll()
|
|
63
|
+
.executeTakeFirstOrThrow();
|
|
64
|
+
const meta = rowToMeta(inserted);
|
|
65
|
+
this.cache.set(meta.name, meta);
|
|
66
|
+
return meta;
|
|
67
|
+
}
|
|
68
|
+
async updateMeta(id, patch) {
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
const sets = { updated_at: now };
|
|
71
|
+
if (patch.label !== undefined)
|
|
72
|
+
sets['label'] = patch.label;
|
|
73
|
+
if (patch.note !== undefined)
|
|
74
|
+
sets['note'] = patch.note;
|
|
75
|
+
if (patch.isPublished !== undefined)
|
|
76
|
+
sets['is_published'] = patch.isPublished ? 1 : 0;
|
|
77
|
+
if (patch.isEditable !== undefined)
|
|
78
|
+
sets['is_editable'] = patch.isEditable ? 1 : 0;
|
|
79
|
+
if (patch.fields !== undefined)
|
|
80
|
+
sets['fields'] = JSON.stringify(patch.fields);
|
|
81
|
+
if (patch.primaryKey !== undefined)
|
|
82
|
+
sets['primary_key'] = patch.primaryKey;
|
|
83
|
+
const updated = await this.systemDb
|
|
84
|
+
.updateTable('table_meta')
|
|
85
|
+
.set(sets)
|
|
86
|
+
.where('id', '=', id)
|
|
87
|
+
.returningAll()
|
|
88
|
+
.executeTakeFirst();
|
|
89
|
+
if (updated) {
|
|
90
|
+
const meta = rowToMeta(updated);
|
|
91
|
+
this.cache.set(meta.name, meta);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async deleteMeta(id) {
|
|
95
|
+
const meta = await this.getMeta(id);
|
|
96
|
+
await this.systemDb.deleteFrom('table_meta').where('id', '=', id).execute();
|
|
97
|
+
if (meta)
|
|
98
|
+
this.cache.delete(meta.name);
|
|
99
|
+
}
|
|
100
|
+
/** 重新反射业务库 → diff → 保留用户标记(label/isHidden/isReadonly/enumValues)→ 更新 fields */
|
|
101
|
+
async refreshMeta(id) {
|
|
102
|
+
const current = await this.getMeta(id);
|
|
103
|
+
if (!current)
|
|
104
|
+
throw new Error(`meta ${id} not found`);
|
|
105
|
+
const { fields: reflected, primaryKey } = readTableSchema(this.businessRaw, current.name);
|
|
106
|
+
// 按 name 索引旧字段,保留用户标记
|
|
107
|
+
const oldByName = new Map(current.fields.map((fld) => [fld.name, fld]));
|
|
108
|
+
const merged = reflected.map((rf) => {
|
|
109
|
+
const old = oldByName.get(rf.name);
|
|
110
|
+
if (!old)
|
|
111
|
+
return rf; // 新字段:纯反射结果(label 默认 = name)
|
|
112
|
+
// 保留用户标记,结构用反射最新值
|
|
113
|
+
const mergedField = {
|
|
114
|
+
...rf,
|
|
115
|
+
label: old.label,
|
|
116
|
+
isHidden: old.isHidden,
|
|
117
|
+
isReadonly: old.isReadonly,
|
|
118
|
+
};
|
|
119
|
+
// exactOptionalPropertyTypes:仅在显式提供时挂载 enumValues
|
|
120
|
+
if (old.enumValues !== undefined)
|
|
121
|
+
mergedField.enumValues = old.enumValues;
|
|
122
|
+
return mergedField;
|
|
123
|
+
});
|
|
124
|
+
await this.updateMeta(id, { fields: merged, primaryKey });
|
|
125
|
+
const after = await this.getMeta(id);
|
|
126
|
+
return after;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import { type CreateModelOptions, type FieldMeta, type FieldMetaInput } from '@1api/shared';
|
|
3
|
+
/** FieldMetaInput(建模输入)→ FieldMeta(完整),补齐 sqliteType 与默认标记 */
|
|
4
|
+
export declare function inputToField(input: FieldMetaInput): FieldMeta;
|
|
5
|
+
/** CREATE TABLE(含主键约定 + 可选时间戳),执行后由调用方反射读回 */
|
|
6
|
+
export declare function createTable(db: Database.Database, opts: CreateModelOptions): void;
|
|
7
|
+
/** ALTER TABLE ... ADD COLUMN(标识符双引号包裹,支持非 snake_case) */
|
|
8
|
+
export declare function addColumn(db: Database.Database, tableName: string, field: FieldMeta): void;
|
|
9
|
+
//# sourceMappingURL=schema-ddl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-ddl.d.ts","sourceRoot":"","sources":["../src/schema-ddl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AAEtB,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,SAAS,CAiB7D;AAED,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAkBjF;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAK1F"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { buildCreateColumnSql, jsonTypeToSqliteType, } from '@1api/shared';
|
|
2
|
+
/** FieldMetaInput(建模输入)→ FieldMeta(完整),补齐 sqliteType 与默认标记 */
|
|
3
|
+
export function inputToField(input) {
|
|
4
|
+
const sqliteType = jsonTypeToSqliteType(input.jsonType);
|
|
5
|
+
const field = {
|
|
6
|
+
name: input.name,
|
|
7
|
+
label: input.label ?? input.name,
|
|
8
|
+
sqliteType,
|
|
9
|
+
jsonType: input.jsonType,
|
|
10
|
+
nullable: input.nullable ?? true,
|
|
11
|
+
defaultValue: input.defaultValue ?? null,
|
|
12
|
+
isPrimary: input.isPrimary ?? false,
|
|
13
|
+
isAutoIncrement: input.isAutoIncrement ?? false,
|
|
14
|
+
isHidden: input.isHidden ?? false,
|
|
15
|
+
isReadonly: input.isReadonly ?? false,
|
|
16
|
+
};
|
|
17
|
+
// exactOptionalPropertyTypes:仅在显式提供时挂载 enumValues
|
|
18
|
+
if (input.enumValues !== undefined)
|
|
19
|
+
field.enumValues = input.enumValues;
|
|
20
|
+
return field;
|
|
21
|
+
}
|
|
22
|
+
/** CREATE TABLE(含主键约定 + 可选时间戳),执行后由调用方反射读回 */
|
|
23
|
+
export function createTable(db, opts) {
|
|
24
|
+
const cols = [];
|
|
25
|
+
const hasExplicitPk = opts.fields.some((f) => f.isPrimary);
|
|
26
|
+
// 默认主键:id INTEGER PRIMARY KEY AUTOINCREMENT
|
|
27
|
+
if (!hasExplicitPk) {
|
|
28
|
+
cols.push('"id" INTEGER PRIMARY KEY AUTOINCREMENT');
|
|
29
|
+
}
|
|
30
|
+
for (const input of opts.fields) {
|
|
31
|
+
cols.push(buildCreateColumnSql(inputToField(input)));
|
|
32
|
+
}
|
|
33
|
+
if (opts.autoTimestamps) {
|
|
34
|
+
cols.push('"created_at" INTEGER');
|
|
35
|
+
cols.push('"updated_at" INTEGER');
|
|
36
|
+
}
|
|
37
|
+
const sql = `CREATE TABLE "${opts.name}" (${cols.join(', ')})`;
|
|
38
|
+
db.exec(sql);
|
|
39
|
+
}
|
|
40
|
+
/** ALTER TABLE ... ADD COLUMN(标识符双引号包裹,支持非 snake_case) */
|
|
41
|
+
export function addColumn(db, tableName, field) {
|
|
42
|
+
const colSql = buildCreateColumnSql(field);
|
|
43
|
+
// ADD COLUMN 不支持 PRIMARY KEY/AUTOINCREMENT,剥离
|
|
44
|
+
const colSafe = colSql.replace(/\s+PRIMARY KEY(\s+AUTOINCREMENT)?/i, '');
|
|
45
|
+
db.exec(`ALTER TABLE "${tableName}" ADD COLUMN ${colSafe}`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=schema-ddl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-ddl.js","sourceRoot":"","sources":["../src/schema-ddl.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GAIrB,MAAM,cAAc,CAAC;AAEtB,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,KAAqB;IAChD,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACxD,MAAM,KAAK,GAAc;QACvB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI;QAChC,UAAU;QACV,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,IAAI;QAChC,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,IAAI;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK;QACnC,eAAe,EAAE,KAAK,CAAC,eAAe,IAAI,KAAK;QAC/C,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK;QACjC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK;KACtC,CAAC;IACF,kDAAkD;IAClD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACxE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,WAAW,CAAC,EAAqB,EAAE,IAAwB;IACzE,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3D,4CAA4C;IAC5C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACtD,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,GAAG,GAAG,iBAAiB,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAC/D,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CAAC,EAAqB,EAAE,SAAiB,EAAE,KAAgB;IAClF,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC3C,8CAA8C;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,oCAAoC,EAAE,EAAE,CAAC,CAAC;IACzE,EAAE,CAAC,IAAI,CAAC,gBAAgB,SAAS,gBAAgB,OAAO,EAAE,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import { type FieldMeta } from '@1api/shared';
|
|
3
|
+
/** 列出业务库所有用户表(排除 sqlite_ 内部表) */
|
|
4
|
+
export declare function listTables(db: Database.Database): string[];
|
|
5
|
+
/** 反射单表 → FieldMeta[] + 主键 */
|
|
6
|
+
export declare function readTableSchema(db: Database.Database, tableName: string): {
|
|
7
|
+
fields: FieldMeta[];
|
|
8
|
+
primaryKey: string;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=schema-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-reader.d.ts","sourceRoot":"","sources":["../src/schema-reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAU,KAAK,SAAS,EAAkC,MAAM,cAAc,CAAC;AAatF,iCAAiC;AACjC,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,EAAE,CAK1D;AAuCD,8BAA8B;AAC9B,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,SAAS,EAAE,MAAM,GAChB;IAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CA6B7C"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Errors } from '@1api/shared';
|
|
2
|
+
const DATETIME_NAME_RE = /(^|_)(at|time)$/i;
|
|
3
|
+
/** 列出业务库所有用户表(排除 sqlite_ 内部表) */
|
|
4
|
+
export function listTables(db) {
|
|
5
|
+
const rows = db
|
|
6
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
|
|
7
|
+
.all();
|
|
8
|
+
return rows.map((r) => r.name);
|
|
9
|
+
}
|
|
10
|
+
/** 主键策略:只接受单主键 */
|
|
11
|
+
function resolvePrimaryKey(rows, tableName) {
|
|
12
|
+
const pkRows = rows.filter((r) => r.pk > 0);
|
|
13
|
+
if (pkRows.length === 0)
|
|
14
|
+
throw Errors.tableNoPrimaryKey(tableName);
|
|
15
|
+
if (pkRows.length > 1)
|
|
16
|
+
throw Errors.tableCompositePrimaryKey(tableName);
|
|
17
|
+
return { pkField: pkRows[0].name };
|
|
18
|
+
}
|
|
19
|
+
/** SQLite 原生类型串归一为五类之一 */
|
|
20
|
+
function normalizeSqliteType(raw) {
|
|
21
|
+
const t = raw.toUpperCase();
|
|
22
|
+
if (t === '')
|
|
23
|
+
return 'BLOB'; // 无类型声明 → BLOB 亲和
|
|
24
|
+
if (t.includes('INT'))
|
|
25
|
+
return 'INTEGER';
|
|
26
|
+
if (t.includes('CHAR') || t.includes('CLOB') || t.includes('TEXT'))
|
|
27
|
+
return 'TEXT';
|
|
28
|
+
if (t.includes('BLOB'))
|
|
29
|
+
return 'BLOB';
|
|
30
|
+
if (t.includes('REAL') || t.includes('FLOA') || t.includes('DOUB'))
|
|
31
|
+
return 'REAL';
|
|
32
|
+
return 'NUMERIC';
|
|
33
|
+
}
|
|
34
|
+
/** jsonType 推断(含命名启发式) */
|
|
35
|
+
function inferJsonType(sqliteType, colName, defaultValue) {
|
|
36
|
+
const lower = colName.toLowerCase();
|
|
37
|
+
const isBooleanish = (lower.startsWith('is_') || lower.startsWith('has_')) && sqliteType === 'INTEGER';
|
|
38
|
+
if (isBooleanish && (defaultValue === '0' || defaultValue === '1'))
|
|
39
|
+
return 'boolean';
|
|
40
|
+
if (sqliteType === 'INTEGER')
|
|
41
|
+
return 'integer';
|
|
42
|
+
if (sqliteType === 'REAL' || sqliteType === 'NUMERIC')
|
|
43
|
+
return 'number';
|
|
44
|
+
if (sqliteType === 'BLOB')
|
|
45
|
+
return 'string'; // BLOB 作为 string 读取(不接受输入由上层校验)
|
|
46
|
+
// TEXT
|
|
47
|
+
if (DATETIME_NAME_RE.test(lower))
|
|
48
|
+
return 'datetime';
|
|
49
|
+
return 'string';
|
|
50
|
+
}
|
|
51
|
+
/** 反射单表 → FieldMeta[] + 主键 */
|
|
52
|
+
export function readTableSchema(db, tableName) {
|
|
53
|
+
const rows = db.prepare(`PRAGMA table_info(${JSON.stringify(tableName)})`).all();
|
|
54
|
+
if (rows.length === 0)
|
|
55
|
+
throw Errors.tableNotFound(tableName);
|
|
56
|
+
const { pkField } = resolvePrimaryKey(rows, tableName);
|
|
57
|
+
const fields = rows
|
|
58
|
+
.sort((a, b) => a.cid - b.cid)
|
|
59
|
+
.map((r) => {
|
|
60
|
+
const sqliteType = normalizeSqliteType(r.type);
|
|
61
|
+
const jsonType = inferJsonType(sqliteType, r.name, r.dflt_value);
|
|
62
|
+
const isPrimary = r.name === pkField;
|
|
63
|
+
const lower = r.name.toLowerCase();
|
|
64
|
+
const isReadonly = jsonType === 'datetime' && (lower === 'created_at' || lower === 'updated_at');
|
|
65
|
+
return {
|
|
66
|
+
name: r.name,
|
|
67
|
+
label: r.name,
|
|
68
|
+
sqliteType,
|
|
69
|
+
jsonType,
|
|
70
|
+
nullable: r.notnull === 0,
|
|
71
|
+
defaultValue: parseDefaultValue(r.dflt_value, jsonType),
|
|
72
|
+
isPrimary,
|
|
73
|
+
isAutoIncrement: isPrimary && sqliteType === 'INTEGER',
|
|
74
|
+
isHidden: false,
|
|
75
|
+
isReadonly,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
return { fields, primaryKey: pkField };
|
|
79
|
+
}
|
|
80
|
+
/** 解析 PRAGMA 的 dflt_value 字符串为合适的 JS 值 */
|
|
81
|
+
function parseDefaultValue(raw, jsonType) {
|
|
82
|
+
if (raw === null)
|
|
83
|
+
return null;
|
|
84
|
+
const v = raw;
|
|
85
|
+
if (jsonType === 'boolean')
|
|
86
|
+
return v === '1' ? true : v === '0' ? false : null;
|
|
87
|
+
if (jsonType === 'integer') {
|
|
88
|
+
const n = Number.parseInt(v, 10);
|
|
89
|
+
return Number.isFinite(n) ? n : null;
|
|
90
|
+
}
|
|
91
|
+
if (jsonType === 'number') {
|
|
92
|
+
const n = Number.parseFloat(v);
|
|
93
|
+
return Number.isFinite(n) ? n : null;
|
|
94
|
+
}
|
|
95
|
+
// string / datetime:去掉外层单引号(SQLite 默认值字符串以 'xxx' 形式存储)
|
|
96
|
+
return v.replace(/^'|'$/g, '').replace(/''/g, "'");
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=schema-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-reader.js","sourceRoot":"","sources":["../src/schema-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import { type FieldMetaInput, type TableMeta } from '@1api/shared';
|
|
3
|
+
import { MetadataStore } from './metadata.js';
|
|
4
|
+
export declare class SchemaService {
|
|
5
|
+
private readonly businessRaw;
|
|
6
|
+
private readonly store;
|
|
7
|
+
constructor(businessRaw: Database.Database, store: MetadataStore);
|
|
8
|
+
/** 导入已有表:listTables 确认 → readTableSchema(无/复合主键透传)→ createMeta(label 留空)。表名不强制正则。 */
|
|
9
|
+
importExisting(name: string): Promise<TableMeta>;
|
|
10
|
+
/** 新建模型:name 强制正则 + 非保留字 → createTable → readTableSchema(读回真实结构)→ createMeta */
|
|
11
|
+
createModel(opts: {
|
|
12
|
+
name: string;
|
|
13
|
+
label: string;
|
|
14
|
+
fields: FieldMetaInput[];
|
|
15
|
+
note?: string | null;
|
|
16
|
+
autoTimestamps?: boolean;
|
|
17
|
+
}): Promise<TableMeta>;
|
|
18
|
+
/** 追加字段:field.name 强制正则 → addColumn(DDL)→ refreshMeta */
|
|
19
|
+
addField(table: string, field: FieldMetaInput): Promise<TableMeta>;
|
|
20
|
+
/** 刷新元数据(重新反射 + diff) */
|
|
21
|
+
refresh(table: string): Promise<TableMeta>;
|
|
22
|
+
/** 新建模型/字段用的严格名称校验:正则 + 保留字 */
|
|
23
|
+
private assertCreatableName;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=schema-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-service.d.ts","sourceRoot":"","sources":["../src/schema-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAuC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAGxG,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,WAAW,EAAE,QAAQ,CAAC,QAAQ,EAC9B,KAAK,EAAE,aAAa;IAGvC,qFAAqF;IAC/E,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAStD,gFAAgF;IAC1E,WAAW,CAAC,IAAI,EAAE;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,GAAG,OAAO,CAAC,SAAS,CAAC;IAoBtB,yDAAyD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IAWxE,yBAAyB;IACnB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAMhD,+BAA+B;IAC/B,OAAO,CAAC,mBAAmB;CAO5B"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Errors, isReservedName, isValidName } from '@1api/shared';
|
|
2
|
+
import { addColumn, createTable, inputToField } from './schema-ddl.js';
|
|
3
|
+
import { listTables, readTableSchema } from './schema-reader.js';
|
|
4
|
+
import { MetadataStore } from './metadata.js';
|
|
5
|
+
export class SchemaService {
|
|
6
|
+
businessRaw;
|
|
7
|
+
store;
|
|
8
|
+
constructor(businessRaw, store) {
|
|
9
|
+
this.businessRaw = businessRaw;
|
|
10
|
+
this.store = store;
|
|
11
|
+
}
|
|
12
|
+
/** 导入已有表:listTables 确认 → readTableSchema(无/复合主键透传)→ createMeta(label 留空)。表名不强制正则。 */
|
|
13
|
+
async importExisting(name) {
|
|
14
|
+
const tables = listTables(this.businessRaw);
|
|
15
|
+
if (!tables.includes(name))
|
|
16
|
+
throw Errors.tableNotFound(name);
|
|
17
|
+
if (await this.store.getMetaByName(name))
|
|
18
|
+
throw Errors.tableAlreadyExists(name);
|
|
19
|
+
const { fields, primaryKey } = readTableSchema(this.businessRaw, name); // 主键策略在此抛错并透传
|
|
20
|
+
return this.store.createMeta({ name, label: '', primaryKey, fields });
|
|
21
|
+
}
|
|
22
|
+
/** 新建模型:name 强制正则 + 非保留字 → createTable → readTableSchema(读回真实结构)→ createMeta */
|
|
23
|
+
async createModel(opts) {
|
|
24
|
+
this.assertCreatableName(opts.name);
|
|
25
|
+
if (await this.store.getMetaByName(opts.name))
|
|
26
|
+
throw Errors.tableAlreadyExists(opts.name);
|
|
27
|
+
if (listTables(this.businessRaw).includes(opts.name)) {
|
|
28
|
+
throw Errors.tableAlreadyExists(opts.name);
|
|
29
|
+
}
|
|
30
|
+
createTable(this.businessRaw, opts);
|
|
31
|
+
const { fields, primaryKey } = readTableSchema(this.businessRaw, opts.name); // 读回真实结构
|
|
32
|
+
// exactOptionalPropertyTypes:仅在显式提供时挂载 note
|
|
33
|
+
const createInput = {
|
|
34
|
+
name: opts.name,
|
|
35
|
+
label: opts.label,
|
|
36
|
+
primaryKey,
|
|
37
|
+
fields,
|
|
38
|
+
};
|
|
39
|
+
if (opts.note !== undefined)
|
|
40
|
+
createInput.note = opts.note;
|
|
41
|
+
return this.store.createMeta(createInput);
|
|
42
|
+
}
|
|
43
|
+
/** 追加字段:field.name 强制正则 → addColumn(DDL)→ refreshMeta */
|
|
44
|
+
async addField(table, field) {
|
|
45
|
+
this.assertCreatableName(field.name);
|
|
46
|
+
const meta = await this.store.getMetaByName(table);
|
|
47
|
+
if (!meta)
|
|
48
|
+
throw Errors.tableNotFound(table);
|
|
49
|
+
if (meta.fields.some((f) => f.name === field.name)) {
|
|
50
|
+
throw Errors.validationFail(`字段已存在: ${field.name}`);
|
|
51
|
+
}
|
|
52
|
+
addColumn(this.businessRaw, table, inputToField(field));
|
|
53
|
+
return this.store.refreshMeta(meta.id);
|
|
54
|
+
}
|
|
55
|
+
/** 刷新元数据(重新反射 + diff) */
|
|
56
|
+
async refresh(table) {
|
|
57
|
+
const meta = await this.store.getMetaByName(table);
|
|
58
|
+
if (!meta)
|
|
59
|
+
throw Errors.tableNotFound(table);
|
|
60
|
+
return this.store.refreshMeta(meta.id);
|
|
61
|
+
}
|
|
62
|
+
/** 新建模型/字段用的严格名称校验:正则 + 保留字 */
|
|
63
|
+
assertCreatableName(name) {
|
|
64
|
+
if (!isValidName(name)) {
|
|
65
|
+
// 区分:保留字 vs 非法格式(保留字本身符合小写开头,归 RESERVED_NAME)
|
|
66
|
+
if (isReservedName(name) && /^[a-z]/.test(name))
|
|
67
|
+
throw Errors.reservedName(name);
|
|
68
|
+
throw Errors.invalidName(name);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=schema-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-service.js","sourceRoot":"","sources":["../src/schema-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAuC,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,OAAO,aAAa;IAEL;IACA;IAFnB,YACmB,WAA8B,EAC9B,KAAoB;QADpB,gBAAW,GAAX,WAAW,CAAmB;QAC9B,UAAK,GAAL,KAAK,CAAe;IACpC,CAAC;IAEJ,qFAAqF;IACrF,KAAK,CAAC,cAAc,CAAC,IAAY;QAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAC7D,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;YAAE,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAEhF,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,cAAc;QACtF,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,gFAAgF;IAChF,KAAK,CAAC,WAAW,CAAC,IAMjB;QACC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1F,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,MAAM,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;QACpC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACtF,4CAA4C;QAC5C,MAAM,WAAW,GAA+C;YAC9D,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,UAAU;YACV,MAAM;SACP,CAAC;QACF,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QAC1D,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IAED,yDAAyD;IACzD,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,KAAqB;QACjD,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI;YAAE,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,MAAM,CAAC,cAAc,CAAC,UAAU,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,yBAAyB;IACzB,KAAK,CAAC,OAAO,CAAC,KAAa;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI;YAAE,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,+BAA+B;IACvB,mBAAmB,CAAC,IAAY;QACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,8CAA8C;YAC9C,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YACjF,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Generated } from 'kysely';
|
|
2
|
+
/** table_meta 行(系统库,snake_case) */
|
|
3
|
+
export interface TableMetaRow {
|
|
4
|
+
id: Generated<number>;
|
|
5
|
+
name: string;
|
|
6
|
+
label: string;
|
|
7
|
+
primary_key: string;
|
|
8
|
+
fields: string;
|
|
9
|
+
is_published: number;
|
|
10
|
+
is_editable: number;
|
|
11
|
+
note: string | null;
|
|
12
|
+
created_at: number;
|
|
13
|
+
updated_at: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 系统库类型。Phase 1 只覆盖 table_meta(engine 唯一接入的系统表)。
|
|
17
|
+
* admin / api_token 属鉴权层,Phase 2 扩展。
|
|
18
|
+
*/
|
|
19
|
+
export interface SystemDB {
|
|
20
|
+
table_meta: TableMetaRow;
|
|
21
|
+
}
|
|
22
|
+
/** 系统库建表 SQL(Phase 1 仅 table_meta) */
|
|
23
|
+
export declare const SYSTEM_DB_MIGRATIONS: readonly ["CREATE TABLE IF NOT EXISTS table_meta (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL UNIQUE,\n label TEXT NOT NULL,\n primary_key TEXT NOT NULL,\n fields TEXT NOT NULL,\n is_published INTEGER NOT NULL DEFAULT 1,\n is_editable INTEGER NOT NULL DEFAULT 1,\n note TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )"];
|
|
24
|
+
//# sourceMappingURL=system-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-db.d.ts","sourceRoot":"","sources":["../src/system-db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,mCAAmC;AACnC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED,sCAAsC;AACtC,eAAO,MAAM,oBAAoB,icAavB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** 系统库建表 SQL(Phase 1 仅 table_meta) */
|
|
2
|
+
export const SYSTEM_DB_MIGRATIONS = [
|
|
3
|
+
`CREATE TABLE IF NOT EXISTS table_meta (
|
|
4
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5
|
+
name TEXT NOT NULL UNIQUE,
|
|
6
|
+
label TEXT NOT NULL,
|
|
7
|
+
primary_key TEXT NOT NULL,
|
|
8
|
+
fields TEXT NOT NULL,
|
|
9
|
+
is_published INTEGER NOT NULL DEFAULT 1,
|
|
10
|
+
is_editable INTEGER NOT NULL DEFAULT 1,
|
|
11
|
+
note TEXT,
|
|
12
|
+
created_at INTEGER NOT NULL,
|
|
13
|
+
updated_at INTEGER NOT NULL
|
|
14
|
+
)`,
|
|
15
|
+
];
|
|
16
|
+
//# sourceMappingURL=system-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-db.js","sourceRoot":"","sources":["../src/system-db.ts"],"names":[],"mappings":"AAwBA,sCAAsC;AACtC,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC;;;;;;;;;;;KAWG;CACK,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { Kysely } from 'kysely';
|
|
3
|
+
import type { SystemDB } from './system-db.js';
|
|
4
|
+
export interface TestDbs {
|
|
5
|
+
businessDbPath: string;
|
|
6
|
+
systemDbPath: string;
|
|
7
|
+
businessRaw: Database.Database;
|
|
8
|
+
businessDb: Kysely<Record<string, never>>;
|
|
9
|
+
systemRaw: Database.Database;
|
|
10
|
+
systemDb: Kysely<SystemDB>;
|
|
11
|
+
cleanup: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/** 创建临时业务库 + 系统库(每次唯一路径),返回句柄与 cleanup。 */
|
|
14
|
+
export declare function createTestDbs(): Promise<TestDbs>;
|
|
15
|
+
//# sourceMappingURL=test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.d.ts","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAIA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAiB,MAAM,QAAQ,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1C,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAID,2CAA2C;AAC3C,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CA8BtD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
5
|
+
import Database from 'better-sqlite3';
|
|
6
|
+
import { Kysely, SqliteDialect } from 'kysely';
|
|
7
|
+
let counter = 0;
|
|
8
|
+
/** 创建临时业务库 + 系统库(每次唯一路径),返回句柄与 cleanup。 */
|
|
9
|
+
export async function createTestDbs() {
|
|
10
|
+
const dir = mkdtempSync(join(tmpdir(), `1api-${randomBytes(4).toString('hex')}-`));
|
|
11
|
+
const businessDbPath = join(dir, `biz-${counter}.db`);
|
|
12
|
+
const systemDbPath = join(dir, `sys-${counter}.db`);
|
|
13
|
+
counter += 1;
|
|
14
|
+
const businessRaw = new Database(businessDbPath);
|
|
15
|
+
businessRaw.pragma('journal_mode = WAL');
|
|
16
|
+
const systemRaw = new Database(systemDbPath);
|
|
17
|
+
const businessDb = new Kysely({
|
|
18
|
+
dialect: new SqliteDialect({ database: businessRaw }),
|
|
19
|
+
});
|
|
20
|
+
const systemDb = new Kysely({
|
|
21
|
+
dialect: new SqliteDialect({ database: systemRaw }),
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
businessDbPath,
|
|
25
|
+
systemDbPath,
|
|
26
|
+
businessRaw,
|
|
27
|
+
businessDb,
|
|
28
|
+
systemRaw,
|
|
29
|
+
systemDb,
|
|
30
|
+
cleanup: async () => {
|
|
31
|
+
await businessDb.destroy();
|
|
32
|
+
await systemDb.destroy();
|
|
33
|
+
rmSync(dir, { recursive: true, force: true });
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAa/C,IAAI,OAAO,GAAG,CAAC,CAAC;AAEhB,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACnF,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,OAAO,KAAK,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,OAAO,KAAK,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,CAAC;IAEb,MAAM,WAAW,GAAG,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC;IACjD,WAAW,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;IAE7C,MAAM,UAAU,GAAG,IAAI,MAAM,CAAwB;QACnD,OAAO,EAAE,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;KACtD,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAW;QACpC,OAAO,EAAE,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;KACpD,CAAC,CAAC;IAEH,OAAO;QACL,cAAc;QACd,YAAY;QACZ,WAAW;QACX,UAAU;QACV,SAAS;QACT,QAAQ;QACR,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC;YAC3B,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1api/engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"description": "one-api 纯逻辑数据引擎(元数据驱动 + 动态 SQL,无 HTTP/UI)",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Yourtion <yourtion@gmail.com>",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/yourtion/one-api.git",
|
|
24
|
+
"directory": "packages/engine"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/yourtion/one-api#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/yourtion/one-api/issues"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"one-api",
|
|
32
|
+
"ai-native",
|
|
33
|
+
"database",
|
|
34
|
+
"engine",
|
|
35
|
+
"sqlite",
|
|
36
|
+
"kysely"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"better-sqlite3": "^12.0.0",
|
|
46
|
+
"kysely": "^0.29.0",
|
|
47
|
+
"@1api/shared": "0.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
51
|
+
"@vitest/coverage-v8": "^3",
|
|
52
|
+
"typescript": "^5.8.0",
|
|
53
|
+
"vitest": "^3.0.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc -p tsconfig.json",
|
|
57
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:watch": "vitest"
|
|
60
|
+
}
|
|
61
|
+
}
|