Skip to content

Commit a1dd802

Browse files
committed
优化 Schema 获取和同步功能,添加数据清理逻辑,更新 OpenAPI 规范
1 parent fd2db1f commit a1dd802

File tree

4 files changed

+81
-25
lines changed

4 files changed

+81
-25
lines changed

packages/api/src/index.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@ export function createObjectQLRouter(options: ObjectQLServerOptions): Router {
118118
router.get('/_schema', async (req: Request, res: Response) => {
119119
try {
120120
const configs = objectql.getConfigs();
121-
res.json(configs);
121+
// Clone and strip data
122+
const sanitized = Object.entries(configs).reduce((acc, [key, val]) => {
123+
const { data, ...rest } = val;
124+
acc[key] = rest;
125+
return acc;
126+
}, {} as Record<string, any>);
127+
res.json(sanitized);
122128
} catch (e: any) {
123129
res.status(500).json({ error: e.message });
124130
}
@@ -134,6 +140,18 @@ export function createObjectQLRouter(options: ObjectQLServerOptions): Router {
134140
// assume item has id or name
135141
const key = item.id || item.name || item.code;
136142
if (key) {
143+
const content = { ...item };
144+
// If content has data (e.g. object config inside metadata), strip it
145+
if (content.data && Array.isArray(content.data) && type === 'object') {
146+
delete content.data;
147+
}
148+
// Should we check item.content.data? Metadata wrapper vs content.
149+
// MetadataRegistry stores { content: ... }
150+
// list() returns `m.content`.
151+
// So item IS the object config.
152+
153+
if ((item as any).data) delete (item as any).data;
154+
137155
result[key] = item;
138156
}
139157
}
@@ -150,7 +168,19 @@ export function createObjectQLRouter(options: ObjectQLServerOptions): Router {
150168
if (!item) {
151169
return res.status(404).json({ error: "Metadata not found" });
152170
}
153-
res.json(item);
171+
const copy = { ...item };
172+
if ((copy as any).data) delete (copy as any).data;
173+
res.json(copy);
174+
} catch (e: any) {
175+
res.status(500).json({ error: e.message });
176+
}
177+
});
178+
179+
router.post('/_schema/sync', async (req: Request, res: Response) => {
180+
try {
181+
// Re-run init to sync schema and data
182+
await objectql.init();
183+
res.json({ status: 'ok', message: 'Schema and data synced successfully' });
154184
} catch (e: any) {
155185
res.status(500).json({ error: e.message });
156186
}

packages/api/src/swagger/generator.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,29 @@ export function generateOpenApiSpec(objectql: IObjectQL) {
9999
}
100100
};
101101

102+
paths['/api/_schema/sync'] = {
103+
post: {
104+
summary: "Sync Schema & Data",
105+
tags: ["System"],
106+
responses: {
107+
200: {
108+
description: "Sync result",
109+
content: {
110+
'application/json': {
111+
schema: {
112+
type: 'object',
113+
properties: {
114+
status: { type: 'string' },
115+
message: { type: 'string' }
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
}
123+
};
124+
102125
Object.values(configs).forEach((config) => {
103126
const objectName = config.name;
104127
const schemaName = objectName;

packages/driver-knex/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ export class KnexDriver implements Driver {
265265
console.log(`[KnexDriver] Database '${dbName}' created successfully.`);
266266
} catch (e: any) {
267267
console.error(`[KnexDriver] Failed to create database '${dbName}':`, e.message);
268+
if (e.code === '42501') {
269+
console.error(`[KnexDriver] Hint: The user '${adminConfig.connection.user || 'current user'}' does not have CREATEDB privileges.`);
270+
console.error(`[KnexDriver] Please run: createdb ${dbName}`);
271+
}
268272
throw e;
269273
} finally {
270274
await adminKnex.destroy();

packages/metadata/src/plugins/objectql.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -142,31 +142,30 @@ export function registerObjectQLPlugins(loader: MetadataLoader) {
142142
});
143143

144144
// Data
145-
// loader.use({
146-
// name: 'data',
147-
// glob: ['**/*.data.yml', '**/*.data.yaml'],
148-
// handler: (ctx) => {
149-
// try {
150-
// const content = ctx.content;
151-
// const data = yaml.load(content);
152-
// if (!Array.isArray(data)) return;
145+
loader.use({
146+
name: 'data',
147+
glob: ['**/*.data.yml', '**/*.data.yaml'],
148+
handler: (ctx) => {
149+
try {
150+
const content = ctx.content;
151+
const data = yaml.load(content);
152+
if (!Array.isArray(data)) return;
153153

154-
// const basename = path.basename(ctx.file);
155-
// const objectName = basename.replace(/\.data\.ya?ml$/, '');
154+
const basename = path.basename(ctx.file);
155+
const objectName = basename.replace(/\.data\.ya?ml$/, '');
156156

157-
// const entry = ctx.registry.getEntry('object', objectName);
158-
// if (entry) {
159-
// const config = entry.content as ObjectConfig;
160-
// // We don't want to load data into metadata
161-
// // config.data = data;
162-
// } else {
163-
// // console.warn(`Found data for unknown object '${objectName}' in ${ctx.file}`);
164-
// }
165-
// } catch (e) {
166-
// console.error(`Error loading data from ${ctx.file}:`, e);
167-
// }
168-
// }
169-
// });
157+
const entry = ctx.registry.getEntry('object', objectName);
158+
if (entry) {
159+
const config = entry.content as ObjectConfig;
160+
config.data = data;
161+
} else {
162+
console.warn(`Found data for unknown object '${objectName}' in ${ctx.file}`);
163+
}
164+
} catch (e) {
165+
console.error(`Error loading data from ${ctx.file}:`, e);
166+
}
167+
}
168+
});
170169
}
171170

172171
function registerObject(registry: any, obj: any, file: string, packageName?: string) {

0 commit comments

Comments
 (0)