Skip to content

Commit 51ec21f

Browse files
Copilothotlong
andcommitted
feat: Add ObjectQLPlugin for flexible ObjectQL registration
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent d26e5b5 commit 51ec21f

7 files changed

Lines changed: 271 additions & 7 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Example: Custom ObjectQL Instance
3+
*
4+
* This demonstrates how to use a custom ObjectQL instance with the kernel.
5+
* This is useful when you have a separate ObjectQL implementation or need
6+
* custom configuration.
7+
*/
8+
9+
import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime';
10+
import { InMemoryDriver } from '@objectstack/driver-memory';
11+
12+
(async () => {
13+
console.log('🚀 Example: Custom ObjectQL Instance...');
14+
15+
// Create a custom ObjectQL instance with specific configuration
16+
const customQL = new ObjectQL({
17+
env: 'development',
18+
// Add any custom host context here
19+
customFeature: true,
20+
debug: true
21+
});
22+
23+
// You can also pre-configure the ObjectQL instance
24+
// For example, register custom hooks
25+
customQL.registerHook('beforeInsert', async (ctx) => {
26+
console.log(`[Custom Hook] Before inserting into ${ctx.object}`);
27+
});
28+
29+
// Create kernel with the custom ObjectQL instance
30+
const kernel = new ObjectStackKernel([
31+
// Register your custom ObjectQL instance
32+
new ObjectQLPlugin(customQL),
33+
34+
// Add your driver
35+
new InMemoryDriver(),
36+
37+
// Add other plugins and app configs as needed
38+
]);
39+
40+
await kernel.start();
41+
42+
console.log('✅ Kernel started with custom ObjectQL instance');
43+
console.log('ObjectQL instance:', kernel.ql);
44+
})();

examples/host/src/index.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ObjectStackKernel } from '@objectstack/runtime';
1+
import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime';
22
import { InMemoryDriver } from '@objectstack/driver-memory';
33
import { HonoServerPlugin } from '@objectstack/plugin-hono-server';
44

@@ -9,10 +9,17 @@ import BiPluginManifest from '@objectstack/plugin-bi/objectstack.config';
99
(async () => {
1010
console.log('🚀 Booting Kernel...');
1111

12+
// Option 1: Use default ObjectQL via plugin (recommended)
1213
const kernel = new ObjectStackKernel([
14+
// Register ObjectQL engine explicitly via plugin
15+
new ObjectQLPlugin(),
16+
17+
// App manifests
1318
CrmApp,
1419
TodoApp,
1520
BiPluginManifest,
21+
22+
// Database driver
1623
new InMemoryDriver(),
1724

1825
// Load the Hono Server Plugin
@@ -22,5 +29,12 @@ import BiPluginManifest from '@objectstack/plugin-bi/objectstack.config';
2229
})
2330
]);
2431

32+
// Option 2: Use custom ObjectQL instance
33+
// const customQL = new ObjectQL({ env: 'production', customConfig: true });
34+
// const kernel = new ObjectStackKernel([
35+
// new ObjectQLPlugin(customQL),
36+
// ...other plugins
37+
// ]);
38+
2539
await kernel.start();
2640
})();

examples/msw-react-crud/src/mocks/browser.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* and the MSW Plugin which automatically exposes the API.
66
*/
77

8-
import { ObjectStackKernel } from '@objectstack/runtime';
8+
import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime';
99
import { InMemoryDriver } from '@objectstack/driver-memory';
1010
import { MSWPlugin } from '@objectstack/plugin-msw';
1111
// import appConfig from '../../objectstack.config';
@@ -24,6 +24,9 @@ export async function startMockServer() {
2424
// We use the data defined in the Todo App config
2525

2626
kernel = new ObjectStackKernel([
27+
// Register ObjectQL engine explicitly
28+
new ObjectQLPlugin(),
29+
2730
// Todo App Config (contains objects and data)
2831
todoConfig,
2932

packages/runtime/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# @objectstack/runtime
2+
3+
ObjectStack Core Runtime & Query Engine
4+
5+
## Overview
6+
7+
The runtime package provides the `ObjectStackKernel` - the central orchestrator for ObjectStack applications. It manages the application lifecycle, plugins, and the ObjectQL data engine.
8+
9+
## Installation
10+
11+
```bash
12+
npm install @objectstack/runtime
13+
```
14+
15+
## Usage
16+
17+
### Basic Setup
18+
19+
```typescript
20+
import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime';
21+
import { InMemoryDriver } from '@objectstack/driver-memory';
22+
23+
const kernel = new ObjectStackKernel([
24+
// Register ObjectQL engine
25+
new ObjectQLPlugin(),
26+
27+
// Add database driver
28+
new InMemoryDriver(),
29+
30+
// Add your app configurations
31+
// appConfig,
32+
]);
33+
34+
await kernel.start();
35+
```
36+
37+
### Custom ObjectQL Instance
38+
39+
If you have a separate ObjectQL implementation or need custom configuration:
40+
41+
```typescript
42+
import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime';
43+
44+
// Create custom ObjectQL instance
45+
const customQL = new ObjectQL({
46+
env: 'production',
47+
customConfig: true
48+
});
49+
50+
// Pre-configure with custom hooks
51+
customQL.registerHook('beforeInsert', async (ctx) => {
52+
console.log(`Inserting into ${ctx.object}`);
53+
});
54+
55+
const kernel = new ObjectStackKernel([
56+
// Use your custom ObjectQL instance
57+
new ObjectQLPlugin(customQL),
58+
59+
// ... other plugins
60+
]);
61+
62+
await kernel.start();
63+
```
64+
65+
### Backward Compatibility
66+
67+
For backward compatibility, the kernel will automatically initialize ObjectQL if no `ObjectQLPlugin` is provided:
68+
69+
```typescript
70+
// This still works, but will show a deprecation warning
71+
const kernel = new ObjectStackKernel([
72+
new InMemoryDriver(),
73+
// ... other plugins
74+
]);
75+
```
76+
77+
## Architecture
78+
79+
### ObjectStackKernel
80+
81+
The kernel is responsible for:
82+
- Orchestrating application lifecycle
83+
- Managing plugins
84+
- Coordinating the ObjectQL engine
85+
- Handling data operations
86+
87+
### ObjectQLPlugin
88+
89+
The `ObjectQLPlugin` provides:
90+
- Explicit ObjectQL engine registration
91+
- Support for custom ObjectQL instances
92+
- Clean separation of concerns
93+
- Better testability
94+
95+
## API Reference
96+
97+
### ObjectStackKernel
98+
99+
#### Constructor
100+
```typescript
101+
constructor(plugins: any[] = [])
102+
```
103+
104+
#### Methods
105+
- `start()`: Initialize and start the kernel
106+
- `find(objectName, query)`: Query data
107+
- `get(objectName, id)`: Get single record
108+
- `create(objectName, data)`: Create record
109+
- `update(objectName, id, data)`: Update record
110+
- `delete(objectName, id)`: Delete record
111+
- `getMetadata(objectName)`: Get object metadata
112+
- `getView(objectName, viewType)`: Get UI view definition
113+
114+
### ObjectQLPlugin
115+
116+
#### Constructor
117+
```typescript
118+
constructor(ql?: ObjectQL, hostContext?: Record<string, any>)
119+
```
120+
121+
#### Parameters
122+
- `ql` (optional): Custom ObjectQL instance
123+
- `hostContext` (optional): Host context configuration
124+
125+
## Examples
126+
127+
See the `examples/` directory for complete examples:
128+
- `examples/host/` - Full server setup with Hono
129+
- `examples/msw-react-crud/` - Browser-based setup with MSW
130+
- `examples/custom-objectql-example.ts` - Custom ObjectQL instance
131+
132+
## Migration Guide
133+
134+
### From Hardcoded ObjectQL to Plugin-Based
135+
136+
**Before:**
137+
```typescript
138+
const kernel = new ObjectStackKernel([appConfig, driver]);
139+
```
140+
141+
**After (Recommended):**
142+
```typescript
143+
const kernel = new ObjectStackKernel([
144+
new ObjectQLPlugin(),
145+
appConfig,
146+
driver
147+
]);
148+
```
149+
150+
**After (Custom Instance):**
151+
```typescript
152+
const customQL = new ObjectQL({ /* config */ });
153+
const kernel = new ObjectStackKernel([
154+
new ObjectQLPlugin(customQL),
155+
appConfig,
156+
driver
157+
]);
158+
```
159+
160+
## License
161+
162+
MIT

packages/runtime/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Export core engine
22
export { ObjectQL, SchemaRegistry } from '@objectstack/objectql';
33
export { ObjectStackKernel } from './kernel';
4+
export { ObjectQLPlugin } from './objectql-plugin';
45
export { ObjectStackRuntimeProtocol } from './protocol';
56

67
export * from './types';

packages/runtime/src/kernel.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,25 @@ import { SchemaRegistry, ObjectQL } from '@objectstack/objectql';
88
* plugins, and the core ObjectQL engine.
99
*/
1010
export class ObjectStackKernel {
11-
public ql: ObjectQL;
11+
public ql!: ObjectQL; // Will be set by ObjectQLPlugin or fallback initialization
1212
private plugins: any[];
1313

1414
constructor(plugins: any[] = []) {
15-
// 1. Initialize Engine with Host Context (Simulated OS services)
16-
this.ql = new ObjectQL({
17-
env: process.env.NODE_ENV || 'development'
18-
});
1915
this.plugins = plugins;
16+
17+
// Check if any plugin provides ObjectQL via install method
18+
// If not, initialize it as a fallback for backward compatibility
19+
const hasObjectQLPlugin = plugins.some(p =>
20+
p && typeof p === 'object' && 'install' in p && p.name?.includes('objectql')
21+
);
22+
23+
if (!hasObjectQLPlugin) {
24+
// Backward compatibility: Initialize ObjectQL directly if no plugin provides it
25+
console.warn('[Kernel] No ObjectQL plugin detected. Using default initialization. Consider using ObjectQLPlugin for explicit registration.');
26+
this.ql = new ObjectQL({
27+
env: process.env.NODE_ENV || 'development'
28+
});
29+
}
2030
}
2131

2232
async start() {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { ObjectQL } from '@objectstack/objectql';
2+
import { RuntimePlugin, RuntimeContext } from '@objectstack/types';
3+
4+
/**
5+
* ObjectQL Engine Plugin
6+
*
7+
* Registers the ObjectQL engine instance with the kernel.
8+
* This allows users to provide their own ObjectQL implementation or configuration.
9+
*/
10+
export class ObjectQLPlugin implements RuntimePlugin {
11+
name = 'com.objectstack.engine.objectql';
12+
13+
private ql: ObjectQL;
14+
15+
constructor(ql?: ObjectQL, hostContext?: Record<string, any>) {
16+
// Allow passing existing ObjectQL instance or create a new one
17+
this.ql = ql || new ObjectQL(hostContext || {
18+
env: process.env.NODE_ENV || 'development'
19+
});
20+
}
21+
22+
/**
23+
* Install the ObjectQL engine into the kernel
24+
*/
25+
async install(ctx: RuntimeContext) {
26+
// Attach the ObjectQL engine to the kernel
27+
(ctx.engine as any).ql = this.ql;
28+
console.log('[ObjectQLPlugin] ObjectQL engine registered');
29+
}
30+
}

0 commit comments

Comments
 (0)