Skip to content

Commit f354804

Browse files
authored
Merge pull request #326 from objectstack-ai/copilot/implement-objectql-plugin-registration
2 parents e77b1d6 + 3571d7d commit f354804

File tree

16 files changed

+755
-26
lines changed

16 files changed

+755
-26
lines changed

OBJECTQL_PLUGIN_QUICKSTART.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# ObjectQL Plugin - Quick Reference
2+
3+
## Installation
4+
5+
```bash
6+
npm install @objectstack/runtime
7+
```
8+
9+
## Basic Usage
10+
11+
### Default ObjectQL (Recommended)
12+
13+
```typescript
14+
import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime';
15+
16+
const kernel = new ObjectStackKernel([
17+
new ObjectQLPlugin(),
18+
// ... other plugins
19+
]);
20+
21+
await kernel.start();
22+
```
23+
24+
### Custom ObjectQL Instance
25+
26+
```typescript
27+
import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime';
28+
29+
// Create custom instance
30+
const customQL = new ObjectQL({
31+
env: 'production',
32+
// custom options
33+
});
34+
35+
// Configure as needed
36+
customQL.registerHook('beforeInsert', async (ctx) => {
37+
console.log(`Inserting into ${ctx.object}`);
38+
});
39+
40+
// Use in kernel
41+
const kernel = new ObjectStackKernel([
42+
new ObjectQLPlugin(customQL),
43+
// ... other plugins
44+
]);
45+
46+
await kernel.start();
47+
```
48+
49+
### Backward Compatible (Legacy)
50+
51+
```typescript
52+
// Still works without ObjectQLPlugin, but shows warning
53+
const kernel = new ObjectStackKernel([
54+
// ... plugins
55+
]);
56+
```
57+
58+
## API Reference
59+
60+
### ObjectQLPlugin Constructor
61+
62+
```typescript
63+
new ObjectQLPlugin(ql?: ObjectQL, hostContext?: Record<string, any>)
64+
```
65+
66+
**Parameters:**
67+
- `ql` (optional): Custom ObjectQL instance to use
68+
- `hostContext` (optional): Configuration for new ObjectQL instance (ignored if `ql` provided)
69+
70+
**Note:** If both parameters are provided, `hostContext` is ignored with a warning.
71+
72+
### Examples
73+
74+
```typescript
75+
// Create with default settings
76+
new ObjectQLPlugin()
77+
78+
// Use custom instance
79+
const custom = new ObjectQL({ env: 'prod' });
80+
new ObjectQLPlugin(custom)
81+
82+
// Create with custom context
83+
new ObjectQLPlugin(undefined, { env: 'prod', debug: true })
84+
```
85+
86+
## Migration Guide
87+
88+
### From Hardcoded to Plugin-Based
89+
90+
**Before:**
91+
```typescript
92+
const kernel = new ObjectStackKernel([appConfig, driver]);
93+
```
94+
95+
**After:**
96+
```typescript
97+
const kernel = new ObjectStackKernel([
98+
new ObjectQLPlugin(), // Add this line
99+
appConfig,
100+
driver
101+
]);
102+
```
103+
104+
## Common Patterns
105+
106+
### Testing with Mock ObjectQL
107+
108+
```typescript
109+
import { ObjectQLPlugin } from '@objectstack/runtime';
110+
import { MockObjectQL } from './mocks';
111+
112+
const mockQL = new MockObjectQL();
113+
const kernel = new ObjectStackKernel([
114+
new ObjectQLPlugin(mockQL),
115+
// ... test config
116+
]);
117+
```
118+
119+
### Multiple Environments
120+
121+
```typescript
122+
// Production
123+
const prodQL = new ObjectQL({ env: 'production', cache: true });
124+
const prodKernel = new ObjectStackKernel([
125+
new ObjectQLPlugin(prodQL),
126+
// ... production plugins
127+
]);
128+
129+
// Development
130+
const devKernel = new ObjectStackKernel([
131+
new ObjectQLPlugin(undefined, { env: 'development', debug: true }),
132+
// ... dev plugins
133+
]);
134+
```
135+
136+
### Custom ObjectQL from Separate Project
137+
138+
```typescript
139+
// Your custom implementation
140+
import { MyCustomObjectQL } from '@mycompany/custom-objectql';
141+
142+
const customQL = new MyCustomObjectQL({
143+
specialFeature: true,
144+
// custom options
145+
});
146+
147+
const kernel = new ObjectStackKernel([
148+
new ObjectQLPlugin(customQL),
149+
// ... other plugins
150+
]);
151+
```
152+
153+
## Troubleshooting
154+
155+
### Error: "ObjectQL engine not initialized"
156+
157+
This means the kernel tried to use ObjectQL before it was set up. Make sure:
158+
1. You include `ObjectQLPlugin` in your plugins array, OR
159+
2. The kernel has backward compatibility enabled
160+
161+
### Warning: "No ObjectQL plugin found..."
162+
163+
This is a deprecation warning. Your code will work, but consider migrating to:
164+
165+
```typescript
166+
new ObjectStackKernel([
167+
new ObjectQLPlugin(), // Add this
168+
// ... other plugins
169+
]);
170+
```
171+
172+
### Warning: "Both ql and hostContext provided..."
173+
174+
You passed both a custom ObjectQL instance and host context:
175+
176+
```typescript
177+
// ❌ Don't do this
178+
new ObjectQLPlugin(customQL, { env: 'prod' }) // hostContext ignored
179+
180+
// ✅ Do this instead
181+
new ObjectQLPlugin(customQL) // Use custom instance
182+
183+
// ✅ Or this
184+
new ObjectQLPlugin(undefined, { env: 'prod' }) // Create with context
185+
```
186+
187+
## Advanced
188+
189+
### Type-Based Detection
190+
191+
ObjectQLPlugin uses a `type` field for reliable detection:
192+
193+
```typescript
194+
// Check if a plugin is an ObjectQL plugin
195+
const isObjectQLPlugin = plugin && plugin.type === 'objectql';
196+
```
197+
198+
The plugin sets `type = 'objectql'` which aligns with the manifest schema that supports package types: 'app', 'plugin', 'driver', 'module', 'objectql', 'gateway', 'adapter'.
199+
200+
### Type Safety
201+
202+
The kernel's `ql` property is typed as optional:
203+
204+
```typescript
205+
export class ObjectStackKernel {
206+
public ql?: ObjectQL;
207+
208+
private ensureObjectQL(): ObjectQL {
209+
if (!this.ql) {
210+
throw new Error('ObjectQL engine not initialized');
211+
}
212+
return this.ql;
213+
}
214+
}
215+
```
216+
217+
## Resources
218+
219+
- [Full Documentation](./packages/runtime/README.md)
220+
- [Implementation Summary](./OBJECTQL_PLUGIN_SUMMARY.md)
221+
- [Custom ObjectQL Example](./examples/custom-objectql-example.ts)
222+
223+
## License
224+
225+
Apache-2.0

content/docs/references/system/manifest/Manifest.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: Manifest Schema Reference
99
| :--- | :--- | :--- | :--- |
1010
| **id** | `string` || Unique package identifier (reverse domain style) |
1111
| **version** | `string` || Package version (semantic versioning) |
12-
| **type** | `Enum<'app' \| 'plugin' \| 'driver' \| 'module'>` || Type of package |
12+
| **type** | `Enum<'app' \| 'plugin' \| 'driver' \| 'module' \| 'objectql' \| 'gateway' \| 'adapter'>` || Type of package |
1313
| **name** | `string` || Human-readable package name |
1414
| **description** | `string` | optional | Package description |
1515
| **permissions** | `string[]` | optional | Array of required permission strings |
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/debug-registry.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
import { ObjectStackKernel } from '@objectstack/runtime';
2+
import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime';
33
import { SchemaRegistry, ObjectQL } from '@objectstack/objectql';
44
import { InMemoryDriver } from '@objectstack/driver-memory';
55

@@ -11,6 +11,7 @@ import TodoApp from '@objectstack/example-todo/objectstack.config';
1111
console.log('Objects inside App:', TodoApp.objects?.map((o: any) => o.name));
1212

1313
const kernel = new ObjectStackKernel([
14+
new ObjectQLPlugin(),
1415
TodoApp,
1516
new InMemoryDriver()
1617
]);

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

0 commit comments

Comments
 (0)