-
Notifications
You must be signed in to change notification settings - Fork 1
feat: Enable plugin-based ObjectQL registration #326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
hotlong
merged 12 commits into
main
from
copilot/implement-objectql-plugin-registration
Jan 27, 2026
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
d26e5b5
Initial plan
Copilot 51ec21f
feat: Add ObjectQLPlugin for flexible ObjectQL registration
Copilot 7d35ed8
docs: Update debug-registry and add implementation summary
Copilot 00321c7
refactor: Address code review feedback - improve type safety and plug…
Copilot fde5d14
polish: Final code review improvements - clarify warnings and type sa…
Copilot 3351379
docs: Add ObjectQL Plugin quick reference guide
Copilot 8f1725c
Initial plan
Copilot 92b0ce4
Add gateway and adapter package types to manifest schema
Copilot 536f086
Merge pull request #328 from objectstack-ai/copilot/extend-type-enum-…
hotlong d488619
refactor: Use type-based detection for ObjectQL plugin instead of symbol
Copilot 79e55c3
删除 OBJECTQL_PLUGIN_SUMMARY.md
hotlong 3571d7d
refactor: Remove unused OBJECTQL_PLUGIN_MARKER symbol
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| # ObjectQL Plugin - Quick Reference | ||
|
|
||
| ## Installation | ||
|
|
||
| ```bash | ||
| npm install @objectstack/runtime | ||
| ``` | ||
|
|
||
| ## Basic Usage | ||
|
|
||
| ### Default ObjectQL (Recommended) | ||
|
|
||
| ```typescript | ||
| import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime'; | ||
|
|
||
| const kernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(), | ||
| // ... other plugins | ||
| ]); | ||
|
|
||
| await kernel.start(); | ||
| ``` | ||
|
|
||
| ### Custom ObjectQL Instance | ||
|
|
||
| ```typescript | ||
| import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime'; | ||
|
|
||
| // Create custom instance | ||
| const customQL = new ObjectQL({ | ||
| env: 'production', | ||
| // custom options | ||
| }); | ||
|
|
||
| // Configure as needed | ||
| customQL.registerHook('beforeInsert', async (ctx) => { | ||
| console.log(`Inserting into ${ctx.object}`); | ||
| }); | ||
|
|
||
| // Use in kernel | ||
| const kernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(customQL), | ||
| // ... other plugins | ||
| ]); | ||
|
|
||
| await kernel.start(); | ||
| ``` | ||
|
|
||
| ### Backward Compatible (Legacy) | ||
|
|
||
| ```typescript | ||
| // Still works without ObjectQLPlugin, but shows warning | ||
| const kernel = new ObjectStackKernel([ | ||
| // ... plugins | ||
| ]); | ||
| ``` | ||
|
|
||
| ## API Reference | ||
|
|
||
| ### ObjectQLPlugin Constructor | ||
|
|
||
| ```typescript | ||
| new ObjectQLPlugin(ql?: ObjectQL, hostContext?: Record<string, any>) | ||
| ``` | ||
|
|
||
| **Parameters:** | ||
| - `ql` (optional): Custom ObjectQL instance to use | ||
| - `hostContext` (optional): Configuration for new ObjectQL instance (ignored if `ql` provided) | ||
|
|
||
| **Note:** If both parameters are provided, `hostContext` is ignored with a warning. | ||
|
|
||
| ### Examples | ||
|
|
||
| ```typescript | ||
| // Create with default settings | ||
| new ObjectQLPlugin() | ||
|
|
||
| // Use custom instance | ||
| const custom = new ObjectQL({ env: 'prod' }); | ||
| new ObjectQLPlugin(custom) | ||
|
|
||
| // Create with custom context | ||
| new ObjectQLPlugin(undefined, { env: 'prod', debug: true }) | ||
| ``` | ||
|
|
||
| ## Migration Guide | ||
|
|
||
| ### From Hardcoded to Plugin-Based | ||
|
|
||
| **Before:** | ||
| ```typescript | ||
| const kernel = new ObjectStackKernel([appConfig, driver]); | ||
| ``` | ||
|
|
||
| **After:** | ||
| ```typescript | ||
| const kernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(), // Add this line | ||
| appConfig, | ||
| driver | ||
| ]); | ||
| ``` | ||
|
|
||
| ## Common Patterns | ||
|
|
||
| ### Testing with Mock ObjectQL | ||
|
|
||
| ```typescript | ||
| import { ObjectQLPlugin } from '@objectstack/runtime'; | ||
| import { MockObjectQL } from './mocks'; | ||
|
|
||
| const mockQL = new MockObjectQL(); | ||
| const kernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(mockQL), | ||
| // ... test config | ||
| ]); | ||
| ``` | ||
|
|
||
| ### Multiple Environments | ||
|
|
||
| ```typescript | ||
| // Production | ||
| const prodQL = new ObjectQL({ env: 'production', cache: true }); | ||
| const prodKernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(prodQL), | ||
| // ... production plugins | ||
| ]); | ||
|
|
||
| // Development | ||
| const devKernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(undefined, { env: 'development', debug: true }), | ||
| // ... dev plugins | ||
| ]); | ||
| ``` | ||
|
|
||
| ### Custom ObjectQL from Separate Project | ||
|
|
||
| ```typescript | ||
| // Your custom implementation | ||
| import { MyCustomObjectQL } from '@mycompany/custom-objectql'; | ||
|
|
||
| const customQL = new MyCustomObjectQL({ | ||
| specialFeature: true, | ||
| // custom options | ||
| }); | ||
|
|
||
| const kernel = new ObjectStackKernel([ | ||
| new ObjectQLPlugin(customQL), | ||
| // ... other plugins | ||
| ]); | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Error: "ObjectQL engine not initialized" | ||
|
|
||
| This means the kernel tried to use ObjectQL before it was set up. Make sure: | ||
| 1. You include `ObjectQLPlugin` in your plugins array, OR | ||
| 2. The kernel has backward compatibility enabled | ||
|
|
||
| ### Warning: "No ObjectQL plugin found..." | ||
|
|
||
| This is a deprecation warning. Your code will work, but consider migrating to: | ||
|
|
||
| ```typescript | ||
| new ObjectStackKernel([ | ||
| new ObjectQLPlugin(), // Add this | ||
| // ... other plugins | ||
| ]); | ||
| ``` | ||
|
|
||
| ### Warning: "Both ql and hostContext provided..." | ||
|
|
||
| You passed both a custom ObjectQL instance and host context: | ||
|
|
||
| ```typescript | ||
| // ❌ Don't do this | ||
| new ObjectQLPlugin(customQL, { env: 'prod' }) // hostContext ignored | ||
|
|
||
| // ✅ Do this instead | ||
| new ObjectQLPlugin(customQL) // Use custom instance | ||
|
|
||
| // ✅ Or this | ||
| new ObjectQLPlugin(undefined, { env: 'prod' }) // Create with context | ||
| ``` | ||
|
|
||
| ## Advanced | ||
|
|
||
| ### Type-Based Detection | ||
|
|
||
| ObjectQLPlugin uses a `type` field for reliable detection: | ||
|
|
||
| ```typescript | ||
| // Check if a plugin is an ObjectQL plugin | ||
| const isObjectQLPlugin = plugin && plugin.type === 'objectql'; | ||
| ``` | ||
|
|
||
| The plugin sets `type = 'objectql'` which aligns with the manifest schema that supports package types: 'app', 'plugin', 'driver', 'module', 'objectql', 'gateway', 'adapter'. | ||
|
|
||
| ### Type Safety | ||
|
|
||
| The kernel's `ql` property is typed as optional: | ||
|
|
||
| ```typescript | ||
| export class ObjectStackKernel { | ||
| public ql?: ObjectQL; | ||
|
|
||
| private ensureObjectQL(): ObjectQL { | ||
| if (!this.ql) { | ||
| throw new Error('ObjectQL engine not initialized'); | ||
| } | ||
| return this.ql; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Resources | ||
|
|
||
| - [Full Documentation](./packages/runtime/README.md) | ||
| - [Implementation Summary](./OBJECTQL_PLUGIN_SUMMARY.md) | ||
| - [Custom ObjectQL Example](./examples/custom-objectql-example.ts) | ||
|
|
||
| ## License | ||
|
|
||
| Apache-2.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /** | ||
| * Example: Custom ObjectQL Instance | ||
| * | ||
| * This demonstrates how to use a custom ObjectQL instance with the kernel. | ||
| * This is useful when you have a separate ObjectQL implementation or need | ||
| * custom configuration. | ||
| */ | ||
|
|
||
| import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime'; | ||
| import { InMemoryDriver } from '@objectstack/driver-memory'; | ||
|
|
||
| (async () => { | ||
| console.log('🚀 Example: Custom ObjectQL Instance...'); | ||
|
|
||
| // Create a custom ObjectQL instance with specific configuration | ||
| const customQL = new ObjectQL({ | ||
| env: 'development', | ||
| // Add any custom host context here | ||
| customFeature: true, | ||
| debug: true | ||
| }); | ||
|
|
||
| // You can also pre-configure the ObjectQL instance | ||
| // For example, register custom hooks | ||
| customQL.registerHook('beforeInsert', async (ctx) => { | ||
| console.log(`[Custom Hook] Before inserting into ${ctx.object}`); | ||
| }); | ||
|
|
||
| // Create kernel with the custom ObjectQL instance | ||
| const kernel = new ObjectStackKernel([ | ||
| // Register your custom ObjectQL instance | ||
| new ObjectQLPlugin(customQL), | ||
|
|
||
| // Add your driver | ||
| new InMemoryDriver(), | ||
|
|
||
| // Add other plugins and app configs as needed | ||
| ]); | ||
|
|
||
| await kernel.start(); | ||
|
|
||
| console.log('✅ Kernel started with custom ObjectQL instance'); | ||
| console.log('ObjectQL instance:', kernel.ql); | ||
| })(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||
| import { ObjectStackKernel } from '@objectstack/runtime'; | ||||||
| import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime'; | ||||||
|
||||||
| import { ObjectStackKernel, ObjectQLPlugin, ObjectQL } from '@objectstack/runtime'; | |
| import { ObjectStackKernel, ObjectQLPlugin } from '@objectstack/runtime'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Copilot Autofix
AI 2 months ago
In general, unused imports should be removed from the import list so that only actually used symbols are imported. This improves readability, avoids misleading future maintainers about dependencies, and can help with tree-shaking and tooling.
The best minimal fix here is to adjust the import statement on line 1 in
examples/host/src/index.tsso that it only importsObjectStackKernelandObjectQLPlugin, removingObjectQL. No other lines need to change, since all references toObjectQLin the file are commented out and do not affect functionality. This preserves all existing behavior while resolving the CodeQL warning.Concretely, in
examples/host/src/index.ts, edit the import on line 1 from:to:
No new methods, definitions, or imports are required.