⚠️ DEPRECATED: This package is deprecated. Use@objectstack/objectqlinstead. See the Migration Guide for step-by-step instructions.
The core ORM and runtime engine for ObjectQL. All core functionality (ObjectQL engine, SchemaRegistry, createObjectQLKernel, utilities) is now available directly from @objectstack/objectql.
The ObjectQLPlugin (orchestrator composing sub-plugins like ValidatorPlugin, FormulaPlugin, QueryPlugin) remains in this package as it is specific to the @objectql ecosystem.
- ✅ Plugin Architecture: Built on top of
@objectstack/runtimewith kernel-based plugin system - ✅ Unified Query Language: A generic way to query data across different databases (SQL, Mongo, etc.)
- ✅ Repository Pattern:
ObjectRepositoryfor managing object records - ✅ Driver Agnostic: Abstraction layer for database drivers
- ✅ Dynamic Schema: Loads object definitions from metadata
- ✅ Hooks & Actions: Runtime logic injection - fully implemented
- ✅ Validation Engine: Metadata-driven validation with field-level, cross-field, and state machine rules
- ✅ Formula Engine: Computed fields with dynamic formulas
- ✅ AI Integration: Built-in AI agent capabilities for code generation
npm install @objectql/core @objectql/types @objectstack/runtime @objectstack/specObjectQL now wraps the ObjectKernel from @objectstack/runtime, providing:
- Kernel-based lifecycle management: Initialization, startup, and shutdown
- Plugin system: Extensible architecture with
ObjectQLPlugin - Enhanced features: Repository, Validator, Formula, and AI capabilities as plugins
See RUNTIME_INTEGRATION.md for detailed architecture documentation.
import { ObjectQL } from '@objectql/core';
// Import a driver, e.g., @objectql/driver-sql
const objectql = new ObjectQL({
datasources: {
default: new MyDriver({ ... })
}
});
await objectql.init(); // Initializes the kernel and all plugins
// Use context for operations
const ctx = objectql.createContext({ userId: 'u-1' });
const projects = await ctx.object('project').find({
filters: [['status', '=', 'active']]
});For advanced use cases, you can access the underlying kernel:
const kernel = objectql.getKernel();
// Use kernel methods if neededThe validation system allows you to define validation rules in your object metadata and execute them programmatically.
Define validation rules directly in field configuration:
import { ObjectConfig } from '@objectql/types';
const projectObject: ObjectConfig = {
name: 'project',
fields: {
email: {
type: 'email',
required: true,
validation: {
format: 'email',
message: 'Please enter a valid email address'
}
},
budget: {
type: 'currency',
validation: {
min: 0,
max: 10000000,
message: 'Budget must be between 0 and 10,000,000'
}
},
name: {
type: 'text',
required: true,
validation: {
min_length: 3,
max_length: 100,
pattern: '^[a-zA-Z0-9\\s]+$',
message: 'Name must be 3-100 alphanumeric characters'
}
}
}
};Execute validation rules programmatically:
import { Validator } from '@objectql/core';
import { ValidationContext, CrossFieldValidationRule } from '@objectql/types';
// Create validator with optional language configuration
const validator = new Validator({
language: 'en',
languageFallback: ['en', 'zh-CN']
});
// Define cross-field validation rules
const rules: CrossFieldValidationRule[] = [
{
name: 'valid_date_range',
type: 'cross_field',
rule: {
field: 'end_date',
operator: '>=',
compare_to: 'start_date' // Cross-field comparison
},
message: 'End date must be on or after start date',
error_code: 'INVALID_DATE_RANGE'
}
];
// Validate a record
const context: ValidationContext = {
record: {
start_date: '2024-01-01',
end_date: '2024-12-31'
},
operation: 'create'
};
const result = await validator.validate(rules, context);
if (!result.valid) {
console.log('Validation errors:', result.errors);
// Output: Array of ValidationRuleResult objects
}Enforce valid state transitions:
import { StateMachineValidationRule } from '@objectql/types';
const statusRule: StateMachineValidationRule = {
name: 'status_transition',
type: 'state_machine',
field: 'status',
transitions: {
planning: {
allowed_next: ['active', 'cancelled']
},
active: {
allowed_next: ['on_hold', 'completed', 'cancelled']
},
completed: {
allowed_next: [],
is_terminal: true
}
},
message: 'Invalid status transition from {{old_status}} to {{new_status}}',
error_code: 'INVALID_STATE_TRANSITION'
};
// Validate on update
const updateContext: ValidationContext = {
record: { status: 'completed' },
previousRecord: { status: 'active' },
operation: 'update'
};
const result = await validator.validate([statusRule], updateContext);Add validation rules to your object metadata:
const projectConfig: ObjectConfig = {
name: 'project',
fields: {
// ... field definitions
},
validation: {
ai_context: {
intent: 'Ensure project data integrity',
validation_strategy: 'Fail fast with clear error messages'
},
rules: [
{
name: 'valid_date_range',
type: 'cross_field',
rule: {
field: 'end_date',
operator: '>=',
compare_to: 'start_date'
},
message: 'End date must be on or after start date',
error_code: 'INVALID_DATE_RANGE'
},
{
name: 'status_transition',
type: 'state_machine',
field: 'status',
transitions: {
planning: { allowed_next: ['active', 'cancelled'] },
active: { allowed_next: ['completed', 'cancelled'] }
},
message: 'Invalid status transition'
}
]
}
};Supported Validation Types:
field- Built-in field validation (required, format, min/max, length, pattern)cross_field- Validate relationships between fieldsstate_machine- Enforce valid state transitionsunique- Uniqueness validation (stub - requires database integration)business_rule- Complex business rules (stub - requires expression evaluation)custom- Custom validation logic (stub - requires safe function execution)dependency- Related record validation (stub - requires database integration)
Comparison Operators:
=,!=- Equality/inequality>,>=,<,<=- Comparisonin,not_in- Array membershipcontains,not_contains- String containmentstarts_with,ends_with- String prefix/suffix
Validation Triggers:
create- Run on record creationupdate- Run on record updatedelete- Run on record deletion
Severity Levels:
error- Blocks the operationwarning- Shows warning but allows operationinfo- Informational message
Advanced Features:
- Field-specific triggers (validate only when specific fields change)
- Conditional validation with
apply_when - Template message formatting with
{{field}}placeholders - Internationalization support with language fallback
- AI context for documentation and LLM understanding
You can pass an existing MetadataRegistry to ObjectQL:
const registry = new MetadataRegistry();
// ... pre-load metadata ...
const objectql = new ObjectQL({
registry: registry,
datasources: { ... }
});Constructor:
new Validator(options?: ValidatorOptions)Options:
language?: string- Preferred language for validation messages (default: 'en')languageFallback?: string[]- Fallback languages (default: ['en', 'zh-CN'])
Methods:
-
validate(rules: AnyValidationRule[], context: ValidationContext): Promise<ValidationResult>- Executes validation rules against a record
- Returns validation result with errors, warnings, and info messages
-
validateField(fieldName: string, fieldConfig: FieldConfig, value: any, context: ValidationContext): Promise<ValidationRuleResult[]>- Validates a single field value
- Returns array of validation results
- @objectql/types - Type definitions including validation types
- Validation Specification - Complete validation metadata specification