Skip to content

Commit 1f4a008

Browse files
Copilothotlong
andcommitted
Refactor core to delegate to kernel managers (partial - types need alignment)
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent cd3a5ba commit 1f4a008

2 files changed

Lines changed: 103 additions & 55 deletions

File tree

packages/foundation/core/src/app.ts

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ import {
2424
import { ObjectStackKernel, type RuntimePlugin } from '@objectstack/runtime';
2525
import { ObjectRepository } from './repository';
2626
import { ObjectQLPlugin } from './plugin';
27-
// import { createDriverFromConnection } from './driver'; // REMOVE THIS
28-
29-
// import { loadRemoteFromUrl } from './remote';
30-
import { executeActionHelper, registerActionHelper, ActionEntry } from './action';
31-
import { registerHookHelper, triggerHookHelper, HookEntry } from './hook';
32-
import { registerObjectHelper, getConfigsHelper } from './object';
3327
import { convertIntrospectedSchemaToObjects } from './util';
3428

3529
/**
@@ -39,11 +33,13 @@ import { convertIntrospectedSchemaToObjects } from './util';
3933
* to provide the plugin architecture.
4034
*/
4135
export class ObjectQL implements IObjectQL {
42-
public metadata: MetadataRegistry;
36+
// Delegate to kernel for metadata, hooks, and actions
37+
public get metadata(): MetadataRegistry {
38+
return this.kernel.metadata;
39+
}
40+
4341
private datasources: Record<string, Driver> = {};
4442
private remotes: string[] = [];
45-
private hooks: Record<string, HookEntry[]> = {};
46-
private actions: Record<string, ActionEntry> = {};
4743

4844
// ObjectStack Kernel Integration
4945
private kernel!: ObjectStackKernel;
@@ -54,9 +50,7 @@ export class ObjectQL implements IObjectQL {
5450

5551
constructor(config: ObjectQLConfig) {
5652
this.config = config;
57-
this.metadata = config.registry || new MetadataRegistry();
5853
this.datasources = config.datasources || {};
59-
// this.remotes = config.remotes || [];
6054

6155
if (config.connection) {
6256
throw new Error("Connection strings are not supported in core directly. Use @objectql/platform-node's createDriverFromConnection or pass a driver instance to 'datasources'.");
@@ -75,42 +69,54 @@ export class ObjectQL implements IObjectQL {
7569
}
7670
}
7771
}
72+
73+
// Create the kernel
74+
this.kernel = new ObjectStackKernel(this.kernelPlugins);
75+
76+
// Register initial metadata if provided
77+
if (config.registry) {
78+
// Copy metadata from provided registry to kernel's registry
79+
for (const type of config.registry.getTypes()) {
80+
for (const item of config.registry.list(type)) {
81+
this.kernel.metadata.register(type, {
82+
type,
83+
id: (item as any).name || (item as any).id,
84+
content: item
85+
});
86+
}
87+
}
88+
}
7889
}
7990

8091
use(plugin: RuntimePlugin) {
8192
this.kernelPlugins.push(plugin);
8293
}
8394

8495
removePackage(name: string) {
85-
this.metadata.unregisterPackage(name);
86-
87-
// Remove hooks
88-
for (const event of Object.keys(this.hooks)) {
89-
this.hooks[event] = this.hooks[event].filter(h => h.packageName !== name);
90-
}
91-
92-
// Remove actions
93-
for (const key of Object.keys(this.actions)) {
94-
if (this.actions[key].packageName === name) {
95-
delete this.actions[key];
96-
}
97-
}
96+
// Delegate to kernel managers
97+
this.kernel.metadata.unregisterPackage(name);
98+
this.kernel.hooks.removePackage(name);
99+
this.kernel.actions.removePackage(name);
98100
}
99101

100102
on(event: HookName, objectName: string, handler: HookHandler, packageName?: string) {
101-
registerHookHelper(this.hooks, event, objectName, handler, packageName);
103+
// Delegate to kernel hook manager
104+
this.kernel.hooks.register(event, objectName, handler, packageName);
102105
}
103106

104107
async triggerHook(event: HookName, objectName: string, ctx: HookContext) {
105-
await triggerHookHelper(this.metadata, this.hooks, event, objectName, ctx);
108+
// Delegate to kernel hook manager
109+
await this.kernel.hooks.trigger(event, objectName, ctx);
106110
}
107111

108112
registerAction(objectName: string, actionName: string, handler: ActionHandler, packageName?: string) {
109-
registerActionHelper(this.actions, objectName, actionName, handler, packageName);
113+
// Delegate to kernel action manager
114+
this.kernel.actions.register(objectName, actionName, handler, packageName);
110115
}
111116

112117
async executeAction(objectName: string, actionName: string, ctx: ActionContext) {
113-
return await executeActionHelper(this.metadata, this.actions, objectName, actionName, ctx);
118+
// Delegate to kernel action manager
119+
return await this.kernel.actions.execute(objectName, actionName, ctx);
114120
}
115121

116122
createContext(options: ObjectQLContextOptions): ObjectQLContext {
@@ -174,19 +180,36 @@ export class ObjectQL implements IObjectQL {
174180
}
175181

176182
registerObject(object: ObjectConfig) {
177-
registerObjectHelper(this.metadata, object);
183+
// Normalize fields
184+
if (object.fields) {
185+
for (const [key, field] of Object.entries(object.fields)) {
186+
if (!field.name) {
187+
field.name = key;
188+
}
189+
}
190+
}
191+
this.kernel.metadata.register('object', {
192+
type: 'object',
193+
id: object.name,
194+
content: object
195+
});
178196
}
179197

180198
unregisterObject(name: string) {
181-
this.metadata.unregister('object', name);
199+
this.kernel.metadata.unregister('object', name);
182200
}
183201

184202
getObject(name: string): ObjectConfig | undefined {
185-
return this.metadata.get<ObjectConfig>('object', name);
203+
return this.kernel.metadata.get<ObjectConfig>('object', name);
186204
}
187205

188206
getConfigs(): Record<string, ObjectConfig> {
189-
return getConfigsHelper(this.metadata);
207+
const result: Record<string, ObjectConfig> = {};
208+
const objects = this.kernel.metadata.list<ObjectConfig>('object');
209+
for (const obj of objects) {
210+
result[obj.name] = obj;
211+
}
212+
return result;
190213
}
191214

192215
datasource(name: string): Driver {
@@ -247,8 +270,8 @@ export class ObjectQL implements IObjectQL {
247270
async init() {
248271
console.log('[ObjectQL] Initializing with ObjectStackKernel...');
249272

250-
// Create the kernel instance with all collected plugins
251-
this.kernel = new ObjectStackKernel(this.kernelPlugins);
273+
// Start the kernel - this will install and start all plugins
274+
await this.kernel.start();
252275

253276
// TEMPORARY: Set driver for backward compatibility during migration
254277
// This allows the kernel mock to delegate to the driver
@@ -258,9 +281,6 @@ export class ObjectQL implements IObjectQL {
258281
(this.kernel as any).setDriver(defaultDriver);
259282
}
260283
}
261-
262-
// Start the kernel - this will install and start all plugins
263-
await this.kernel.start();
264284

265285
// Load In-Memory Objects (Dynamic Layer)
266286
if (this.config.objects) {
@@ -269,7 +289,7 @@ export class ObjectQL implements IObjectQL {
269289
}
270290
}
271291

272-
const objects = this.metadata.list<ObjectConfig>('object');
292+
const objects = this.kernel.metadata.list<ObjectConfig>('object');
273293

274294
// Init Datasources
275295
// Let's pass all objects to all configured drivers.
@@ -287,7 +307,7 @@ export class ObjectQL implements IObjectQL {
287307
}
288308

289309
private async processInitialData() {
290-
const dataEntries = this.metadata.list<any>('data');
310+
const dataEntries = this.kernel.metadata.list<any>('data');
291311
if (dataEntries.length === 0) return;
292312

293313
console.log(`Processing ${dataEntries.length} initial data files...`);

packages/objectstack/runtime/src/metadata.ts

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,40 @@ export interface MetadataItem {
1919
content: any;
2020
/** Package name this metadata belongs to */
2121
packageName?: string;
22+
/** Optional path to the metadata source file */
23+
path?: string;
24+
/** Alternative package name field for compatibility */
25+
package?: string;
2226
}
2327

2428
/**
2529
* Metadata Registry
2630
* Central registry for all metadata in the ObjectStack ecosystem
2731
*/
2832
export class MetadataRegistry {
29-
private items: Map<string, Map<string, MetadataItem>> = new Map();
33+
// Expose store for compatibility
34+
public store: Map<string, Map<string, MetadataItem>> = new Map();
3035
private packages: Map<string, string[]> = new Map();
3136

3237
/**
3338
* Register a metadata item
3439
*/
3540
register(type: string, item: MetadataItem): void {
36-
if (!this.items.has(type)) {
37-
this.items.set(type, new Map());
41+
if (!this.store.has(type)) {
42+
this.store.set(type, new Map());
3843
}
3944

40-
const typeMap = this.items.get(type)!;
45+
const typeMap = this.store.get(type)!;
4146
typeMap.set(item.id, item);
4247

43-
// Track package association
44-
if (item.packageName) {
45-
if (!this.packages.has(item.packageName)) {
46-
this.packages.set(item.packageName, []);
48+
// Track package association (support both packageName and package fields)
49+
const pkgName = item.packageName || item.package;
50+
if (pkgName) {
51+
if (!this.packages.has(pkgName)) {
52+
this.packages.set(pkgName, []);
4753
}
4854
const key = `${type}:${item.id}`;
49-
const packageItems = this.packages.get(item.packageName)!;
55+
const packageItems = this.packages.get(pkgName)!;
5056
if (!packageItems.includes(key)) {
5157
packageItems.push(key);
5258
}
@@ -57,7 +63,7 @@ export class MetadataRegistry {
5763
* Get a specific metadata item
5864
*/
5965
get<T = any>(type: string, id: string): T | undefined {
60-
const typeMap = this.items.get(type);
66+
const typeMap = this.store.get(type);
6167
if (!typeMap) return undefined;
6268

6369
const item = typeMap.get(id);
@@ -68,7 +74,7 @@ export class MetadataRegistry {
6874
* List all items of a specific type
6975
*/
7076
list<T = any>(type: string): T[] {
71-
const typeMap = this.items.get(type);
77+
const typeMap = this.store.get(type);
7278
if (!typeMap) return [];
7379

7480
return Array.from(typeMap.values()).map(item => item.content as T);
@@ -78,26 +84,48 @@ export class MetadataRegistry {
7884
* Check if a metadata item exists
7985
*/
8086
has(type: string, id: string): boolean {
81-
const typeMap = this.items.get(type);
87+
const typeMap = this.store.get(type);
8288
return typeMap?.has(id) ?? false;
8389
}
8490

8591
/**
8692
* Unregister a specific item
8793
*/
8894
unregister(type: string, id: string): void {
89-
const typeMap = this.items.get(type);
95+
const typeMap = this.store.get(type);
9096
if (typeMap) {
9197
typeMap.delete(id);
9298
}
9399
}
94100

101+
/**
102+
* Get the full metadata entry (not just content)
103+
*/
104+
getEntry(type: string, id: string): MetadataItem | undefined {
105+
const typeMap = this.store.get(type);
106+
return typeMap ? typeMap.get(id) : undefined;
107+
}
108+
95109
/**
96110
* Unregister all items from a package
97111
*/
98112
unregisterPackage(packageName: string): void {
99113
const items = this.packages.get(packageName);
100-
if (!items) return;
114+
if (!items) {
115+
// Also try to find by scanning all entries (for compatibility)
116+
for (const [type, typeMap] of this.store.entries()) {
117+
const entriesToDelete: string[] = [];
118+
for (const [id, item] of typeMap.entries()) {
119+
if (item.package === packageName || item.packageName === packageName) {
120+
entriesToDelete.push(id);
121+
}
122+
}
123+
for (const id of entriesToDelete) {
124+
typeMap.delete(id);
125+
}
126+
}
127+
return;
128+
}
101129

102130
for (const key of items) {
103131
const [type, id] = key.split(':');
@@ -111,14 +139,14 @@ export class MetadataRegistry {
111139
* Clear all metadata
112140
*/
113141
clear(): void {
114-
this.items.clear();
142+
this.store.clear();
115143
this.packages.clear();
116144
}
117145

118146
/**
119147
* Get all types
120148
*/
121149
getTypes(): string[] {
122-
return Array.from(this.items.keys());
150+
return Array.from(this.store.keys());
123151
}
124152
}

0 commit comments

Comments
 (0)