Skip to content

refactor(core): decompose @objectql/core into plugin-query and plugin-optimizations#373

Merged
hotlong merged 4 commits intomainfrom
copilot/refactor-objectql-core
Feb 11, 2026
Merged

refactor(core): decompose @objectql/core into plugin-query and plugin-optimizations#373
hotlong merged 4 commits intomainfrom
copilot/refactor-objectql-core

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 11, 2026

Implements the decomposition specified in docs/DESIGN_CORE_REFACTOR.md — extract query and optimization modules from the monolithic @objectql/core into composable RuntimePlugin packages, aligning with the ObjectStack microkernel architecture.

New packages

  • @objectql/plugin-optimizations — 8 optimization modules (OptimizedMetadataRegistry, QueryCompiler, CompiledHookManager, GlobalConnectionPool, OptimizedValidationEngine, LazyMetadataLoader, DependencyGraph, SQLQueryOptimizer) + OptimizationsPlugin
  • @objectql/plugin-queryQueryService, QueryBuilder, QueryAnalyzer, FilterTranslator + QueryPlugin

Core slimming

  • plugin.ts now delegates query registration to QueryPlugin instead of inline instantiation
  • Added kernel-factory.ts with createObjectQLKernel() convenience factory
  • index.ts re-exports all extracted classes with @deprecated JSDoc tags pointing to new packages
  • app.ts, repository.ts, protocol.ts retained for backward API compatibility

Infrastructure

  • package.json — added @objectql/plugin-query and @objectql/plugin-optimizations as workspace deps
  • tsconfig.json — added project references for new packages
  • vitest.config.ts — added aliases for new packages

Kernel bootstrap (target pattern)

import { createObjectQLKernel } from '@objectql/core';
import { QueryPlugin } from '@objectql/plugin-query';
import { OptimizationsPlugin } from '@objectql/plugin-optimizations';

const kernel = createObjectQLKernel({
  plugins: [new QueryPlugin(), new OptimizationsPlugin()],
});
await kernel.start();

All 36 packages build. All 87 test files pass (1845 tests). Zero breaking changes — existing @objectql/core imports continue to resolve.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • fastdl.mongodb.org
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/objectql/objectql/node_modules/.bin/../vitest/vitest.mjs run --reporter=verbose es/.bin/../typescript/bin/tsc get --local 2/dist/node-gyp-bin/node credential.helpenode (dns block)
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/objectql/objectql/node_modules/.bin/../vitest/vitest.mjs run git es/.bin/../typescript/bin/tsc 6c431a5480931cf0fb19950e8c2ceaadcbfb99be:packages/foundation/plugin-optimizations/src/OptimizedVsh r tql/node_modules/.bin/node cat /proc/cpuinfnode git /usr/bin/grep git node�� 6c431a5480931cf0fb19950e8c2ceaadcbfb99be:packages/foundation/plugin-query/src/qu--irreversible-dbash grep les/.bin/sh s/src/plugin.ts git /home/REDACTED/worrm -rf templates && mkdir -p templates && rsync -av --exclude='node_modules' --exclude='dist' --exclude='__tests__' ../../../examples/quickstart/hello-world templates/ && rsync -av --exclude='node_modules' --exclude='dist' --exclude='__test s__' ../../../e (dns block)
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/objectql/objectql/node_modules/.bin/../vitest/vitest.mjs run dirname /hom�� al id" | sort |uniq | wc -l git k/_temp/ghcca-node/node/bin/pnpm cbfb99be:packagebash 6c431a5480931cf0--norc /.bin/sh k/_temp/ghcca-node/node/bin/pnpm run build git modules/@npmcli/run-script/lib/node-gyp-bin/node 6c431a5480931cf0uniq node rgo/bin/git tsc (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel
Copy link
Copy Markdown

vercel bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectql Canceled Canceled Feb 11, 2026 5:24am

Request Review

Copilot AI and others added 2 commits February 11, 2026 04:23
…actoring)

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
version = '4.2.0';
private logger: Logger;

constructor(private config: QueryPluginConfig = {}) {
…actory, update re-exports

Phase 3 of core refactoring:
- Simplify plugin.ts to delegate QueryService/QueryAnalyzer to @objectql/plugin-query
- Add kernel-factory.ts with createObjectQLKernel() convenience function
- Update index.ts with @deprecated re-exports from new plugin packages
- Add new plugin packages as workspace dependencies
- Update tsconfig.json with new project references
- Update vitest.config.ts with new package aliases
- Fix version assertion in plugin-integration.test.ts (4.0.2 -> 4.2.0)

All 87 test files pass (1845 tests), build succeeds (36 packages)

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor @objectql/core based on design document refactor(core): decompose @objectql/core into plugin-query and plugin-optimizations Feb 11, 2026
Copilot AI requested a review from hotlong February 11, 2026 04:45
@hotlong hotlong marked this pull request as ready for review February 11, 2026 04:55
Copilot AI review requested due to automatic review settings February 11, 2026 04:55
@hotlong hotlong merged commit 5c7c1b2 into main Feb 11, 2026
2 of 3 checks passed
@hotlong hotlong deleted the copilot/refactor-objectql-core branch February 11, 2026 04:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors @objectql/core into a thinner orchestrator by extracting query and optimization functionality into two new composable RuntimePlugin packages (@objectql/plugin-query and @objectql/plugin-optimizations), aligning the codebase with the ObjectStack microkernel architecture while preserving backward compatibility via re-exports and deprecated APIs.

Changes:

  • Added new workspace packages @objectql/plugin-query and @objectql/plugin-optimizations and wired them into build/test resolution.
  • Updated @objectql/core to delegate query registration to QueryPlugin, added createObjectQLKernel() convenience factory, and re-exported extracted modules with @deprecated tags.
  • Updated workspace/project references and versioning to support the new package layout.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
vitest.config.ts Adds path aliases for the new plugin packages in tests.
pnpm-lock.yaml Adds new workspace importers and dependency links for the new packages.
packages/foundation/plugin-query/tsconfig.json New TS project config for @objectql/plugin-query.
packages/foundation/plugin-query/src/query-service.ts New QueryService implementation (extracted from core).
packages/foundation/plugin-query/src/query-builder.ts New QueryBuilder implementation (extracted from core).
packages/foundation/plugin-query/src/query-analyzer.ts New QueryAnalyzer implementation (extracted from core).
packages/foundation/plugin-query/src/plugin.ts New QueryPlugin that registers QueryService/QueryAnalyzer on the kernel.
packages/foundation/plugin-query/src/index.ts Public exports for @objectql/plugin-query.
packages/foundation/plugin-query/src/filter-translator.ts New FilterTranslator (pass-through translation).
packages/foundation/plugin-query/package.json New package manifest for @objectql/plugin-query.
packages/foundation/plugin-optimizations/tsconfig.json New TS project config for @objectql/plugin-optimizations.
packages/foundation/plugin-optimizations/src/plugin.ts New OptimizationsPlugin that wires optimization services into the kernel.
packages/foundation/plugin-optimizations/src/index.ts Public exports for @objectql/plugin-optimizations.
packages/foundation/plugin-optimizations/src/SQLQueryOptimizer.ts Introduces SQLQueryOptimizer module and exports it.
packages/foundation/plugin-optimizations/src/QueryCompiler.ts Introduces QueryCompiler with LRU caching and exports it.
packages/foundation/plugin-optimizations/src/OptimizedValidationEngine.ts Introduces OptimizedValidationEngine module and exports it.
packages/foundation/plugin-optimizations/src/OptimizedMetadataRegistry.ts Introduces OptimizedMetadataRegistry module and exports it.
packages/foundation/plugin-optimizations/src/LazyMetadataLoader.ts Introduces LazyMetadataLoader module and exports it.
packages/foundation/plugin-optimizations/src/GlobalConnectionPool.ts Introduces GlobalConnectionPool module and exports it.
packages/foundation/plugin-optimizations/src/DependencyGraph.ts Introduces DependencyGraph module and exports it.
packages/foundation/plugin-optimizations/src/CompiledHookManager.ts Introduces CompiledHookManager module and exports it.
packages/foundation/plugin-optimizations/package.json New package manifest for @objectql/plugin-optimizations.
packages/foundation/core/tsconfig.json Adds project references to new plugin packages.
packages/foundation/core/test/plugin-integration.test.ts Updates ObjectQLPlugin version expectation.
packages/foundation/core/src/plugin.ts Delegates query wiring to QueryPlugin instead of inline QueryService/Analyzer.
packages/foundation/core/src/kernel-factory.ts Adds createObjectQLKernel() convenience factory for kernel bootstrapping.
packages/foundation/core/src/index.ts Adds createObjectQLKernel() export and re-exports extracted modules with @deprecated tags.
packages/foundation/core/package.json Adds new plugin packages as workspace dependencies.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

packages/foundation/core/src/index.ts:37

  • QueryAST is a type-only export from @objectql/types, but here it’s being re-exported as a runtime value (export { QueryAST } ...). This can emit a JS re-export that doesn’t exist at runtime and cause consumer import failures. Re-export it as a type-only export (export type { QueryAST } ...) or remove the value re-export.
import { z } from 'zod';
export { QueryAST } from '@objectql/types';
export type DriverInterface = z.infer<typeof Data.DriverInterfaceSchema>;

);
if (index >= 0) {
this.waitQueue.splice(index, 1);
reject(new Error(`Connection pool limit reached for driver: ${driverName}`));
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This timeout rejection uses a plain Error, while the rest of the pool uses ObjectQLError with structured codes. Reject with ObjectQLError (e.g. DRIVER_CONNECTION_FAILED) to keep error handling consistent for callers.

Suggested change
reject(new Error(`Connection pool limit reached for driver: ${driverName}`));
reject(
new ObjectQLError({
code: 'DRIVER_CONNECTION_FAILED',
message: `Connection pool limit reached for driver: ${driverName}`,
})
);

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +12
import { ObjectKernel } from '@objectstack/runtime';
import { ObjectQLPlugin as UpstreamObjectQLPlugin } from '@objectstack/objectql';
import type { Plugin } from '@objectstack/core';

Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plugin is imported from @objectstack/core here, but elsewhere (e.g. app.ts) Plugin is imported from @objectstack/runtime alongside ObjectKernel. Using different Plugin types can create assignability issues for options.plugins. Import Plugin from the same package as ObjectKernel (or use a shared upstream type) to keep the factory’s API consistent.

Suggested change
import { ObjectKernel } from '@objectstack/runtime';
import { ObjectQLPlugin as UpstreamObjectQLPlugin } from '@objectstack/objectql';
import type { Plugin } from '@objectstack/core';
import { ObjectKernel, type Plugin } from '@objectstack/runtime';
import { ObjectQLPlugin as UpstreamObjectQLPlugin } from '@objectstack/objectql';

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +110
// Array item validation
if (schema.items && Array.isArray(data)) {
const itemValidator = this.compileSchema(schema.items);
data.forEach((item, index) => {
const result = itemValidator(item);
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array validation recompiles the item validator on every call (this.compileSchema(schema.items) inside the runtime check). Pre-compile the item validator once during compilation to avoid repeated work and allocations.

Copilot uses AI. Check for mistakes.
Comment on lines +193 to +196
if (bestIndex) {
// Add index hint for MySQL/MariaDB
sql += ` USE INDEX (${bestIndex.name})`;
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This emits a MySQL/MariaDB-specific USE INDEX hint. On PostgreSQL/SQLite/etc this will generate invalid SQL. Consider making dialect an explicit input and only emitting supported hints, or moving this behind a driver-specific implementation.

Copilot uses AI. Check for mistakes.
Comment on lines +497 to +499
// Update average
this.stats.avgExecutionTime =
this.executionTimes.reduce((sum, t) => sum + t, 0) / this.executionTimes.length;
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Average execution time is recomputed by reducing the entire executionTimes array on every query, which becomes O(n²) over time. Track a running sum / incremental average to keep this O(1) per recorded query.

Suggested change
// Update average
this.stats.avgExecutionTime =
this.executionTimes.reduce((sum, t) => sum + t, 0) / this.executionTimes.length;
// Update average in O(1) time using incremental formula
const totalQueries = this.stats.totalQueries;
this.stats.avgExecutionTime =
((this.stats.avgExecutionTime * (totalQueries - 1)) + executionTime) / totalQueries;

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +28
export interface QueryOptions {
/**
* Transaction handle for transactional queries
*/
transaction?: any;

Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transaction is typed as any, which leaks any through the public plugin API. Prefer unknown (matching ObjectQLContext.transactionHandle?: unknown and driver option typing) or a generic transaction handle type.

Copilot uses AI. Check for mistakes.
Comment on lines +238 to +241
*/
clearCache(): void {
this.cache = new LRUCache(1000);
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clearCache() resets the cache capacity to 1000 regardless of the cacheSize provided to the constructor. This changes behavior unexpectedly for non-default sizes. Preserve the original capacity when clearing (e.g. store cacheSize on the instance and reuse it).

Copilot uses AI. Check for mistakes.
Comment on lines +212 to +213
// Simple heuristic: use hash join for large datasets
if (ast.limit && ast.limit < 100) {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Join strategy heuristics check ast.limit, but many QueryAST inputs use top (and you already normalize limit: ast.limit || ast.top). Use the normalized value (or check ast.limit ?? ast.top) so this behaves consistently.

Suggested change
// Simple heuristic: use hash join for large datasets
if (ast.limit && ast.limit < 100) {
// Simple heuristic: use nested loops for small result sets, hash join for larger ones
const limit = ast.limit ?? ast.top;
if (typeof limit === 'number' && limit < 100) {

Copilot uses AI. Check for mistakes.
Comment on lines 86 to 87

constructor(private config: ObjectQLPluginConfig = {}, _ql?: any) {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This write to property 'config' is useless, since another property write always overrides it.

Suggested change
constructor(private config: ObjectQLPluginConfig = {}, _ql?: any) {
private config: ObjectQLPluginConfig;
constructor(config: ObjectQLPluginConfig = {}, _ql?: any) {

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +42
private logger: Logger;

constructor(private config: QueryPluginConfig = {}) {
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This write to property 'config' is useless, since another property write always overrides it.

Suggested change
private logger: Logger;
constructor(private config: QueryPluginConfig = {}) {
private readonly config: QueryPluginConfig;
private logger: Logger;
constructor(config: QueryPluginConfig = {}) {

Copilot uses AI. Check for mistakes.
Copilot AI added a commit that referenced this pull request Feb 11, 2026
…-optimizations decomposition

- tsconfig.json: Add missing TypeScript project references for all new packages
- .changeset/config.json: Add new packages to fixed version group
- README.md: Update Architecture table and Development section
- docs/DESIGN_CORE_REFACTOR.md: Mark as completed (PR #373)
- docs/ROADMAP_NEXT_PHASE.md: Update optimization module paths
- docs/WORK_PLAN_2026_Q1_P2.md: Update Package Matrix and platform versions

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants