Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

@objectql/core

⚠️ DEPRECATED: This package is deprecated. Use @objectstack/objectql instead. 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.

Features

  • Plugin Architecture: Built on top of @objectstack/runtime with kernel-based plugin system
  • Unified Query Language: A generic way to query data across different databases (SQL, Mongo, etc.)
  • Repository Pattern: ObjectRepository for 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

Installation

npm install @objectql/core @objectql/types @objectstack/runtime @objectstack/spec

Architecture

ObjectQL 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.

Usage

Basic Setup

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']]
});

Accessing the Kernel

For advanced use cases, you can access the underlying kernel:

const kernel = objectql.getKernel();
// Use kernel methods if needed

Validation System

The validation system allows you to define validation rules in your object metadata and execute them programmatically.

Field-Level Validation

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'
            }
        }
    }
};

Using the Validator Class

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
}

State Machine Validation

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);

Validation in Object Configuration

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'
            }
        ]
    }
};

Validation Features

Supported Validation Types:

  • field - Built-in field validation (required, format, min/max, length, pattern)
  • cross_field - Validate relationships between fields
  • state_machine - Enforce valid state transitions
  • unique - 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
  • >, >=, <, <= - Comparison
  • in, not_in - Array membership
  • contains, not_contains - String containment
  • starts_with, ends_with - String prefix/suffix

Validation Triggers:

  • create - Run on record creation
  • update - Run on record update
  • delete - Run on record deletion

Severity Levels:

  • error - Blocks the operation
  • warning - Shows warning but allows operation
  • info - 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

Shared Metadata

You can pass an existing MetadataRegistry to ObjectQL:

const registry = new MetadataRegistry();
// ... pre-load metadata ...

const objectql = new ObjectQL({
    registry: registry,
    datasources: { ... }
});

API Reference

Validator Class

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

See Also