Skip to content

Commit 07f2f83

Browse files
committed
Refactor ObjectQL and Plugin architecture; add service registration methods and update dependencies
1 parent e63a7ea commit 07f2f83

File tree

8 files changed

+82
-100
lines changed

8 files changed

+82
-100
lines changed

packages/core/src/kernel.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ export class ObjectKernel {
5050
await handler(...args);
5151
}
5252
},
53+
getServices: () => {
54+
return new Map(this.services);
55+
},
5356
logger: console,
5457
getKernel: () => this,
5558
};

packages/core/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ export interface PluginContext {
2525
*/
2626
getService<T>(name: string): T;
2727

28+
/**
29+
* Get all registered services
30+
*/
31+
getServices(): Map<string, any>;
32+
2833
/**
2934
* Register a hook handler
3035
* @param name - Hook name (e.g., 'kernel:ready', 'data:beforeInsert')

packages/objectql/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"test": "vitest"
1010
},
1111
"dependencies": {
12+
"@objectstack/core": "workspace:*",
1213
"@objectstack/spec": "workspace:*",
1314
"@objectstack/types": "workspace:*"
1415
},
Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import { Plugin, PluginContext } from './plugin'; // Import local minimal context or from core if available?
2-
// Actually ObjectQL probably hasn't added @objectstack/core as dependency yet properly or local imports are preferred.
3-
// Let's use internal types where possible if they exist, OR ensure @objectstack/core is in package.json
4-
// But wait, objectql/src/plugin.ts defines PluginContext locally to avoid circular dep?
5-
// Let's check objectql/package.json
1+
import { Plugin, PluginContext } from '@objectstack/core';
62
import { SchemaRegistry, ObjectQL } from './index';
73

84
/**
@@ -38,40 +34,13 @@ export class AppManifestPlugin implements Plugin {
3834
const sys = this.manifest.manifest || this.manifest;
3935
ctx.logger.log(`[AppManifestPlugin] Loading App Manifest: ${sys.id || sys.name}`);
4036

41-
// Register the app/plugin in the schema registry
42-
SchemaRegistry.registerPlugin(sys);
43-
44-
// Register all objects defined in the manifest
45-
if (this.manifest.objects) {
46-
for (const obj of this.manifest.objects) {
47-
SchemaRegistry.registerObject(obj);
48-
ctx.logger.log(`[AppManifestPlugin] Registered Object: ${obj.name}`);
49-
}
50-
}
37+
// Register the app manifest as a service
38+
const serviceName = `app.${sys.id || sys.name}`;
39+
ctx.registerService(serviceName, this.manifest);
40+
ctx.logger.log(`[AppManifestPlugin] Registered App service: ${serviceName}`);
5141
}
5242

5343
async start(ctx: PluginContext) {
54-
// Seed data if provided
55-
if (this.manifest.data && Array.isArray(this.manifest.data)) {
56-
const sys = this.manifest.manifest || this.manifest;
57-
ctx.logger.log(`[AppManifestPlugin] Seeding data for ${sys.name || sys.id}...`);
58-
59-
const objectql = ctx.getService<ObjectQL>('objectql');
60-
61-
for (const seed of this.manifest.data) {
62-
try {
63-
// Check if data already exists
64-
const existing = await objectql.find(seed.object, { top: 1 });
65-
if (existing.length === 0) {
66-
ctx.logger.log(`[AppManifestPlugin] Inserting ${seed.records.length} records into ${seed.object}`);
67-
for (const record of seed.records) {
68-
await objectql.insert(seed.object, record);
69-
}
70-
}
71-
} catch (e) {
72-
ctx.logger.warn(`[AppManifestPlugin] Failed to seed ${seed.object}`, e);
73-
}
74-
}
75-
}
44+
// Data seeding logic will be handled by the engine when it detects the app
7645
}
7746
}

packages/objectql/src/driver-plugin.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Plugin, PluginContext } from './plugin';
1+
import { Plugin, PluginContext } from '@objectstack/core';
22

33
/**
44
* Driver Plugin
@@ -27,12 +27,10 @@ export class DriverPlugin implements Plugin {
2727
}
2828

2929
async init(ctx: PluginContext) {
30-
// Get ObjectQL service
31-
const objectql = ctx.getService<any>('objectql');
32-
33-
// Register driver
34-
objectql.registerDriver(this.driver);
35-
ctx.logger.log(`[DriverPlugin] Registered driver: ${this.driver.name || 'unknown'}`);
30+
// Register driver as a service instead of directly to objectql
31+
const serviceName = `driver.${this.driver.name || 'unknown'}`;
32+
ctx.registerService(serviceName, this.driver);
33+
ctx.logger.log(`[DriverPlugin] Registered driver service: ${serviceName}`);
3634
}
3735

3836
async start(ctx: PluginContext) {

packages/objectql/src/index.ts

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -50,42 +50,7 @@ export class ObjectQL implements IDataEngine {
5050
async use(manifestPart: any, runtimePart?: any) {
5151
// 1. Validate / Register Manifest
5252
if (manifestPart) {
53-
// 1. Handle Module Imports (commonjs/esm interop)
54-
// If the passed object is a module namespace with a default export, use that.
55-
const manifest = manifestPart.default || manifestPart;
56-
57-
// In a real scenario, we might strictly parse this using Zod
58-
// For now, simple ID check
59-
const id = manifest.id || manifest.name;
60-
if (!id) {
61-
console.warn(`[ObjectQL] Plugin manifest missing ID (keys: ${Object.keys(manifest)})`, manifest);
62-
// Don't return, try to proceed if it looks like an App (Apps might use 'name' instead of 'id')
63-
// return;
64-
}
65-
66-
console.log(`[ObjectQL] Loading Plugin: ${id}`);
67-
SchemaRegistry.registerPlugin(manifest as ObjectStackManifest);
68-
69-
// Register Objects from App/Plugin
70-
if (manifest.objects) {
71-
for (const obj of manifest.objects) {
72-
// Ensure object name is registered globally
73-
SchemaRegistry.registerObject(obj);
74-
console.log(`[ObjectQL] Registered Object: ${obj.name}`);
75-
}
76-
}
77-
78-
// Register contributions
79-
if (manifest.contributes?.kinds) {
80-
for (const kind of manifest.contributes.kinds) {
81-
SchemaRegistry.registerKind(kind);
82-
}
83-
}
84-
85-
// Register Data Seeding (Lazy execution or immediate?)
86-
// We store it in a temporary registry or execute immediately if engine is ready.
87-
// Since `use` is init time, we might need to store it and run later in `seed()`.
88-
// For this MVP, let's attach it to the manifest object in registry so Kernel can find it.
53+
this.registerApp(manifestPart);
8954
}
9055

9156
// 2. Execute Runtime
@@ -128,6 +93,44 @@ export class ObjectQL implements IDataEngine {
12893
}
12994
}
13095

96+
registerApp(manifestPart: any) {
97+
// 1. Handle Module Imports (commonjs/esm interop)
98+
// If the passed object is a module namespace with a default export, use that.
99+
const raw = manifestPart.default || manifestPart;
100+
101+
// Support nested manifest property (Stack Definition)
102+
// We merge the inner manifest metadata (id, version, etc) with the outer container (objects, apps)
103+
const manifest = raw.manifest ? { ...raw, ...raw.manifest } : raw;
104+
105+
// In a real scenario, we might strictly parse this using Zod
106+
// For now, simple ID check
107+
const id = manifest.id || manifest.name;
108+
if (!id) {
109+
console.warn(`[ObjectQL] Plugin manifest missing ID (keys: ${Object.keys(manifest)})`, manifest);
110+
// Don't return, try to proceed if it looks like an App (Apps might use 'name' instead of 'id')
111+
// return;
112+
}
113+
114+
console.log(`[ObjectQL] Loading App: ${id}`);
115+
SchemaRegistry.registerPlugin(manifest as ObjectStackManifest);
116+
117+
// Register Objects from App/Plugin
118+
if (manifest.objects) {
119+
for (const obj of manifest.objects) {
120+
// Ensure object name is registered globally
121+
SchemaRegistry.registerObject(obj);
122+
console.log(`[ObjectQL] Registered Object: ${obj.name}`);
123+
}
124+
}
125+
126+
// Register contributions
127+
if (manifest.contributes?.kinds) {
128+
for (const kind of manifest.contributes.kinds) {
129+
SchemaRegistry.registerKind(kind);
130+
}
131+
}
132+
}
133+
131134
/**
132135
* Register a new storage driver
133136
*/

packages/objectql/src/plugin.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
11
import { ObjectQL } from './index';
22
import { ObjectStackProtocolImplementation } from './protocol';
3-
// IObjectStackProtocol is used for type checking implicitly via ObjectStackProtocolImplementation contract
3+
import { Plugin, PluginContext } from '@objectstack/core';
44

5-
// Minimal Context interface to avoid circular dependency on @objectstack/runtime
6-
export interface PluginContext {
7-
registerService(name: string, service: any): void;
8-
getService<T>(name: string): T;
9-
hook(name: string, handler: any): void;
10-
trigger(name: string, ...args: any[]): Promise<void>;
11-
logger: Console;
12-
[key: string]: any;
13-
}
14-
15-
export interface Plugin {
16-
name: string;
17-
version?: string;
18-
dependencies?: string[];
19-
init?: (ctx: PluginContext) => Promise<void> | void;
20-
start?: (ctx: PluginContext) => Promise<void> | void;
21-
destroy?: () => Promise<void> | void;
22-
}
5+
export type { Plugin, PluginContext };
236

24-
export class ObjectQLPlugin {
7+
export class ObjectQLPlugin implements Plugin {
258
name = 'com.objectstack.engine.objectql';
269
type = 'objectql' as const;
2710
version = '1.0.0';
@@ -58,5 +41,22 @@ export class ObjectQLPlugin {
5841

5942
async start(ctx: PluginContext) {
6043
if(ctx.logger) ctx.logger.log(`[ObjectQLPlugin] ObjectQL engine initialized`);
44+
45+
// Discover features from Kernel Services
46+
if (ctx.getServices && this.ql) {
47+
const services = ctx.getServices();
48+
for (const [name, service] of services.entries()) {
49+
if (name.startsWith('driver.')) {
50+
// Register Driver
51+
this.ql.registerDriver(service);
52+
if(ctx.logger) ctx.logger.log(`[ObjectQLPlugin] Discovered and registered driver service: ${name}`);
53+
}
54+
if (name.startsWith('app.')) {
55+
// Register App
56+
this.ql.registerApp(service); // service is Manifest
57+
if(ctx.logger) ctx.logger.log(`[ObjectQLPlugin] Discovered and registered app service: ${name}`);
58+
}
59+
}
60+
}
6161
}
6262
}

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)