ObjectQL is a universal, metadata-driven ORM designed for building dynamic business applications. Unlike traditional ORMs where you define schema in class files (like TypeORM entities), ObjectQL uses a Metadata-First approach.
- Metadata-Driven: Define your data models in JSON or YAML. Perfect for low-code platforms where schema changes at runtime.
- Universal Protocol: The query language is a JSON AST, making it easy for frontends or AI agents to generate queries.
- Action & Hook System: Built-in support for "Button Actions" (RPC) and "Triggers" (Hooks), allowing you to model Behavior alongside Data.
Install the core package and a driver (e.g., PostgreSQL or MongoDB).
npm install @objectql/core @objectql/driver-knex knex pg
# or
npm install @objectql/core @objectql/driver-mongo mongodbLet's build a simple To-Do List backend.
In ObjectQL, everything is an "Object" (like a Table or Collection).
ObjectQL uses filename-based identification - the object name is automatically inferred from the filename, making your metadata files cleaner.
# File: todo.object.yml
# Object name "todo" is automatically inferred from filename!
label: To-Do Item
fields:
title:
type: text
label: Task Name
completed:
type: boolean
default: falseNote: You no longer need to specify name: todo - it's inferred from the filename todo.object.yml!
Updated in v0.2: You can now use a simple connection string.
import { ObjectQL } from '@objectql/core';
import * as path from 'path';
async function main() {
const db = new ObjectQL({
// 1. Connection String (Protocol://Path)
// Detects 'sqlite', 'postgres', 'mongodb' automatically
connection: 'sqlite://data.db',
// 2. Schema Source
// Where your *.object.yml files are located
source: ['src/objects'],
// 3. Load Presets (Optional)
// Load standard objects from npm packages
presets: ['@objectql/preset-auth']
});
await db.init();
// ...
// 3. Create Data (CRUD)
// Create a context (representing a user request)
const ctx = db.createContext({});
const todoRepo = ctx.object('todo');
const newTask = await todoRepo.create({
title: 'Learn ObjectQL',
completed: false
});
console.log('Created:', newTask);
// 4. Query Data
const tasks = await todoRepo.find({
filters: [['completed', '=', false]]
});
console.log('Pending Tasks:', tasks);
}
main();ObjectQL shines when you need to add logic.
Triggers logic automatically when data changes.
app.on('beforeCreate', 'todo', async (ctx) => {
if (ctx.doc.title === 'Sleep') {
throw new Error("Cannot sleep yet!");
}
// Auto-tagging
ctx.doc.title = `[Task] ${ctx.doc.title}`;
});Defines a custom operation (RPC) that frontends can call.
// Define protocol
app.registerAction('todo', 'mark_done', async (ctx) => {
const { id } = ctx;
await ctx.object('todo').update(id, { completed: true });
return { message: 'Good job!' };
});
// Invocation
await ctx.object('todo').execute('mark_done', 'id_123', {});- Data Modeling: Learn about all field types (Select, Lookup, Date, etc.)
- SDK Reference: Explore the full API.
- Hooks: Deep dive into the event system.