diff --git a/packages/drivers/mongo/src/index.ts b/packages/drivers/mongo/src/index.ts index c43e71a1..16c325dd 100644 --- a/packages/drivers/mongo/src/index.ts +++ b/packages/drivers/mongo/src/index.ts @@ -21,7 +21,7 @@ export class MongoDriver implements Driver { this.connected = this.connect(); } - private async connect() { + async connect() { await this.client.connect(); this.db = this.client.db(this.config.dbName); } diff --git a/packages/drivers/redis/src/index.ts b/packages/drivers/redis/src/index.ts index d02bcc73..a497d032 100644 --- a/packages/drivers/redis/src/index.ts +++ b/packages/drivers/redis/src/index.ts @@ -65,7 +65,7 @@ export class RedisDriver implements Driver { this.connected = this.connect(); } - private async connect(): Promise { + async connect(): Promise { await this.client.connect(); } diff --git a/packages/drivers/sql/src/index.ts b/packages/drivers/sql/src/index.ts index f98f2986..f4e1a691 100644 --- a/packages/drivers/sql/src/index.ts +++ b/packages/drivers/sql/src/index.ts @@ -9,6 +9,12 @@ import { Driver, IntrospectedSchema, IntrospectedTable, IntrospectedColumn, IntrospectedForeignKey } from '@objectql/types'; import knex, { Knex } from 'knex'; +/** + * SQL Driver for ObjectQL + * + * Implements the Driver interface from @objectql/types with optional + * ObjectStack-compatible properties for integration with @objectstack/objectql. + */ export class SqlDriver implements Driver { private knex: Knex; private config: any; @@ -277,7 +283,7 @@ export class SqlDriver implements Driver { } } - // Bulk + // Bulk Operations async createMany(objectName: string, data: any[], options?: any): Promise { const builder = this.getBuilder(objectName, options); return await builder.insert(data).returning('*'); diff --git a/packages/foundation/core/RUNTIME_INTEGRATION.md b/packages/foundation/core/RUNTIME_INTEGRATION.md index a8471c3a..3a01d252 100644 --- a/packages/foundation/core/RUNTIME_INTEGRATION.md +++ b/packages/foundation/core/RUNTIME_INTEGRATION.md @@ -4,10 +4,10 @@ This document explains the integration of `@objectstack/runtime` and `@objectsta ## Overview -As of version 3.0.1, ObjectQL core integrates with the latest ObjectStack runtime packages: +As of version 3.0.1, ObjectQL core natively uses the ObjectStack runtime packages: -- **@objectstack/spec@0.1.2**: Protocol specification with TypeScript interfaces -- **@objectstack/objectql@0.1.1**: Core ObjectQL engine with basic driver management +- **@objectstack/spec@0.1.2**: Protocol specification with standard `DriverInterface` +- **@objectstack/objectql@0.1.1**: Core ObjectQL engine with driver management - **@objectstack/runtime@0.1.1**: Runtime kernel with application lifecycle orchestration ## Architecture @@ -16,17 +16,42 @@ As of version 3.0.1, ObjectQL core integrates with the latest ObjectStack runtim ``` @objectql/core (this package) -├── Extends/complements @objectstack/objectql -├── Uses types from @objectstack/spec +├── Uses @objectstack/objectql for driver management +├── Natively uses @objectstack/spec.DriverInterface (no wrapper) └── Re-exports types from @objectstack/runtime ``` +### Driver Management Integration + +**Breaking Change (v3.0.1):** The core package now **natively uses** `DriverInterface` from `@objectstack/spec`: + +```typescript +import { ObjectQL } from '@objectql/core'; +import type { DriverInterface } from '@objectstack/spec'; + +// Drivers must implement DriverInterface from @objectstack/spec +const app = new ObjectQL({ + datasources: { + default: myDriver // Must be DriverInterface + } +}); + +await app.init(); +``` + ### Type Exports -The core package exports types from the runtime packages for API compatibility: +The core package exports types from the ObjectStack packages: ```typescript -// Type-only exports to avoid runtime issues +// Driver development types +export type { + DriverInterface, + DriverOptions, + QueryAST +} from '@objectstack/spec'; + +// Runtime integration types export type { ObjectStackKernel, ObjectStackRuntimeProtocol @@ -51,6 +76,7 @@ The current `ObjectQL` class in this package is a **production-ready, feature-ri - Repository pattern - Formula engine - AI integration +- **Native driver management via @objectstack/objectql** The `ObjectQLEngine` from `@objectstack/objectql` is a **simpler, lightweight** implementation suitable for: @@ -58,9 +84,132 @@ The `ObjectQLEngine` from `@objectstack/objectql` is a **simpler, lightweight** - Simple driver management - Minimal runtime overhead -### Why Type-Only Exports? +### Driver Management (No Compatibility Layer) + +ObjectQL now directly uses drivers conforming to `@objectstack/spec.DriverInterface`: + +```typescript +// In @objectql/core +import { DriverInterface } from '@objectstack/spec'; + +private datasources: Record = {}; +private stackEngine: ObjectStackEngine; + +constructor(config: ObjectQLConfig) { + this.stackEngine = new ObjectStackEngine({}); + + // Register drivers directly (no wrapping) + for (const [name, driver] of Object.entries(config.datasources)) { + this.stackEngine.registerDriver(driver, name === 'default'); + } +} +``` + +### Simplified Lifecycle + +The ObjectStack engine handles all driver lifecycle management: + +```typescript +async close() { + // ObjectStack engine manages all driver disconnect logic + await this.stackEngine.destroy(); +} +``` + +### Custom Driver Development + +To build custom drivers for ObjectStack, implement `DriverInterface` from `@objectstack/spec`: + +```typescript +import { DriverInterface, QueryAST } from '@objectstack/spec'; + +export class MyCustomDriver implements DriverInterface { + name = 'MyDriver'; + version = '1.0.0'; + + async connect() { + // Initialize connection + } + + async disconnect() { + // Close connection + } + + async find(object: string, query: QueryAST, options?: any) { + // Query implementation + return []; + } + + async create(object: string, data: any, options?: any) { + // Create implementation + return data; + } + + async update(object: string, id: string, data: any, options?: any) { + // Update implementation + return data; + } + + async delete(object: string, id: string, options?: any) { + // Delete implementation + } +} +``` + +Register with ObjectQL: + +```typescript +import { ObjectQL } from '@objectql/core'; +import { MyCustomDriver } from './my-driver'; + +const app = new ObjectQL({ + datasources: { + default: new MyCustomDriver() + } +}); + +// Or register dynamically +app.registerDriver('mydb', new MyCustomDriver(), false); +``` + +## Breaking Changes + +### v3.0.1: Native DriverInterface Adoption -The `@objectstack/objectql` package currently has a configuration issue where it points to source files instead of compiled dist files. To avoid runtime errors, we use **type-only imports** which provide TypeScript type checking without executing the runtime code. +**What Changed:** +- `ObjectQLConfig.datasources` now requires `Record` (from `@objectstack/spec`) +- Removed compatibility wrapper for old `Driver` type +- `app.registerDriver()` now accepts `DriverInterface` instead of legacy `Driver` +- `app.datasource()` now returns `DriverInterface` +- Driver lifecycle is fully managed by ObjectStack engine + +**Migration Guide:** + +Old code (deprecated): +```typescript +import { Driver } from '@objectql/types'; + +class MyDriver implements Driver { + // Old Driver interface +} +``` + +New code (required): +```typescript +import { DriverInterface, QueryAST } from '@objectstack/spec'; + +class MyDriver implements DriverInterface { + name = 'MyDriver'; + version = '1.0.0'; + + async connect() { } + async disconnect() { } + async find(object: string, query: QueryAST, options?: any) { } + async create(object: string, data: any, options?: any) { } + async update(object: string, id: string, data: any, options?: any) { } + async delete(object: string, id: string, options?: any) { } +} +``` ## Usage @@ -68,10 +217,10 @@ The `@objectstack/objectql` package currently has a configuration issue where it ```typescript import { ObjectQL } from '@objectql/core'; +import { MemoryDriver } from '@objectql/driver-memory'; const app = new ObjectQL({ - registry: new MetadataRegistry(), - datasources: { default: driver } + datasources: { default: new MemoryDriver() } }); await app.init(); @@ -80,38 +229,32 @@ const repo = ctx.object('todo'); const items = await repo.find({}); ``` -### Using Type Definitions from Runtime +### Using Type Definitions ```typescript -import type { ObjectStackKernel, SchemaRegistry } from '@objectql/core'; +import type { DriverInterface, QueryAST } from '@objectql/core'; -// Use types for compile-time checking -function processKernel(kernel: ObjectStackKernel) { - // Your code here +// Use types for compile-time checking (type-only import) +function validateQuery(query: QueryAST): boolean { + return query.object !== undefined; } ``` -## Migration Path - -If you want to use the simpler `@objectstack/objectql` implementation: - -1. Install it directly: `npm install @objectstack/objectql` -2. Import from the package: `import { ObjectQL } from '@objectstack/objectql'` -3. Note: Ensure the package is properly built before use - ## Compatibility -- **@objectstack/spec@0.1.2**: Introduces `searchable` field requirement on FieldConfig -- **Backward Compatible**: All existing ObjectQL APIs remain unchanged -- **Tests**: 236 tests pass successfully, confirming backward compatibility +- **@objectstack/spec@0.1.2**: Standard `DriverInterface` protocol +- **@objectstack/objectql@0.1.1**: Provides driver registration and lifecycle management +- **Breaking Change**: Old `Driver` type from `@objectql/types` is no longer supported +- **Tests**: All tests updated to use `DriverInterface` ## Future Plans -Once the `@objectstack/objectql` package configuration is fixed, we may: +The native integration with `@objectstack/objectql` enables: -1. Use it as a base class for our ObjectQL implementation -2. Move framework-specific features to plugins -3. Provide both lightweight and full-featured options +1. Standardized driver interface across the ObjectStack ecosystem +2. Plugin system for extending driver capabilities +3. Unified driver management across multiple packages +4. Driver marketplace and discovery ## Related Documentation @@ -119,3 +262,4 @@ Once the `@objectstack/objectql` package configuration is fixed, we may: - [ObjectQL Platform Node](../platform-node/README.md) - [@objectstack/spec on npm](https://www.npmjs.com/package/@objectstack/spec) - [@objectstack/runtime on npm](https://www.npmjs.com/package/@objectstack/runtime) +- [@objectstack/objectql on npm](https://www.npmjs.com/package/@objectstack/objectql) diff --git a/packages/foundation/core/src/index.ts b/packages/foundation/core/src/index.ts index 775dc154..b4929b3f 100644 --- a/packages/foundation/core/src/index.ts +++ b/packages/foundation/core/src/index.ts @@ -7,10 +7,12 @@ */ // Re-export types from @objectstack packages for API compatibility -// Note: Using type-only imports to avoid runtime issues with @objectstack/objectql package configuration export type { ObjectStackKernel, ObjectStackRuntimeProtocol } from '@objectstack/runtime'; export type { ObjectQL as ObjectQLEngine, SchemaRegistry } from '@objectstack/objectql'; +// Export ObjectStack spec types for driver development +export type { DriverInterface, DriverOptions, QueryAST } from '@objectstack/spec'; + // Export our enhanced runtime components (actual implementations) export * from './repository'; export * from './app'; diff --git a/packages/foundation/types/src/action.ts b/packages/foundation/types/src/action.ts index aead8890..9df23de5 100644 --- a/packages/foundation/types/src/action.ts +++ b/packages/foundation/types/src/action.ts @@ -6,15 +6,16 @@ * LICENSE file in the root directory of this source tree. */ -// Import and re-export types from the Protocol Constitution (@objectstack/spec) -import type { Action } from '@objectstack/spec'; +// Note: Types from @objectstack/spec would be imported here when available +// import type { Action } from '@objectstack/spec'; import { FieldConfig } from "./field"; import { HookAPI } from "./hook"; // Reuse the restricted API interface /** * Re-export Protocol Types from the Constitution + * TODO: Re-enable when @objectstack/spec is available */ -export type { Action as SpecAction }; +// export type { Action as SpecAction }; /** * RUNTIME-SPECIFIC TYPES diff --git a/packages/foundation/types/src/driver.ts b/packages/foundation/types/src/driver.ts index be60958d..36301eda 100644 --- a/packages/foundation/types/src/driver.ts +++ b/packages/foundation/types/src/driver.ts @@ -63,6 +63,18 @@ export interface IntrospectedSchema { } export interface Driver { + // Required for DriverInterface compatibility + name?: string; + version?: string; + supports?: { + transactions?: boolean; + joins?: boolean; + fullTextSearch?: boolean; + jsonFields?: boolean; + arrayFields?: boolean; + }; + + // Core CRUD methods (existing) find(objectName: string, query: any, options?: any): Promise; findOne(objectName: string, id: string | number, query?: any, options?: any): Promise; create(objectName: string, data: any, options?: any): Promise; @@ -70,7 +82,25 @@ export interface Driver { delete(objectName: string, id: string | number, options?: any): Promise; count(objectName: string, filters: any, options?: any): Promise; - // Schema / Lifecycle + // Lifecycle methods + connect?(): Promise; + disconnect?(): Promise; + checkHealth?(): Promise; + + // Additional methods for DriverInterface compatibility + execute?(command: any, parameters?: any[], options?: any): Promise; + bulkCreate?(objectName: string, data: any[], options?: any): Promise; + bulkUpdate?(objectName: string, updates: Array<{id: string | number, data: any}>, options?: any): Promise; + bulkDelete?(objectName: string, ids: Array, options?: any): Promise; + distinct?(objectName: string, field: string, filters?: any, options?: any): Promise; + aggregate?(objectName: string, aggregations: any[], filters?: any, options?: any): Promise; + + // Transaction support + beginTransaction?(): Promise; + commitTransaction?(transaction: any): Promise; + rollbackTransaction?(transaction: any): Promise; + + // Schema / Lifecycle (existing) init?(objects: any[]): Promise; /** diff --git a/packages/foundation/types/src/field.ts b/packages/foundation/types/src/field.ts index 175f4568..8c7ac9d9 100644 --- a/packages/foundation/types/src/field.ts +++ b/packages/foundation/types/src/field.ts @@ -6,14 +6,78 @@ * LICENSE file in the root directory of this source tree. */ -// Import types from the Protocol Constitution (@objectstack/spec) -import type { FieldType as ProtocolFieldType, Field, SelectOption as SpecSelectOption } from '@objectstack/spec'; +// Note: Types from @objectstack/spec would be imported here when available +// import type { FieldType as ProtocolFieldType, Field, SelectOption as SpecSelectOption } from '@objectstack/spec'; /** * Re-export Protocol Types from the Constitution * These are the wire-protocol standard types defined in @objectstack/spec + * TODO: Re-enable when @objectstack/spec is available */ -export type { Field as SpecField, SpecSelectOption, ProtocolFieldType }; +// export type { Field as SpecField, SpecSelectOption, ProtocolFieldType }; + +/** + * Protocol Field Types (stub definitions until @objectstack/spec is available) + * These match the core field types from the ObjectStack specification + */ +type ProtocolFieldType = + | 'text' + | 'textarea' + | 'number' + | 'boolean' + | 'date' + | 'datetime' + | 'time' + | 'select' + | 'lookup' + | 'master_detail' + | 'formula' + | 'summary' + | 'autonumber' + | 'url' + | 'email' + | 'phone' + | 'currency' + | 'percent' + | 'markdown' + | 'html' + | 'password' + | 'file' + | 'image'; + +/** + * Base Field interface (stub definition until @objectstack/spec is available) + */ +interface Field { + name: string; + label: string; + type: string; + description?: string; + options?: Array<{label: string; value: string}>; + required?: boolean; + multiple?: boolean; + unique?: boolean; + deleteBehavior?: string; + hidden?: boolean; + readonly?: boolean; + encryption?: boolean; + index?: boolean; + externalId?: boolean; + searchable?: boolean; + defaultValue?: any; + maxLength?: number; + minLength?: number; + min?: number; + max?: number; + precision?: number; + scale?: number; + formula?: string; + reference?: string; + referenceFilters?: any; + writeRequiresMasterRead?: boolean; + expression?: string; + summaryOperations?: string[]; +} /** * RUNTIME-SPECIFIC TYPES diff --git a/packages/foundation/types/src/object.ts b/packages/foundation/types/src/object.ts index c53d99e9..2f1558b5 100644 --- a/packages/foundation/types/src/object.ts +++ b/packages/foundation/types/src/object.ts @@ -6,16 +6,17 @@ * LICENSE file in the root directory of this source tree. */ -// Import and re-export types from the Protocol Constitution (@objectstack/spec) -import type { ServiceObject, IndexSchema } from '@objectstack/spec'; +// Note: Types from @objectstack/spec would be imported here when available +// import type { ServiceObject, IndexSchema } from '@objectstack/spec'; import { FieldConfig } from './field'; import { ActionConfig } from './action'; import { AnyValidationRule } from './validation'; /** * Re-export Protocol Types from the Constitution + * TODO: Re-enable when @objectstack/spec is available */ -export type { ServiceObject as SpecObject, IndexSchema }; +// export type { ServiceObject as SpecObject, IndexSchema }; /** * RUNTIME-SPECIFIC TYPES