UQL ORM
UQL ORM is a fast, type-safe TypeScript Object-Relational Mapper (ORM) designed with a JSON-native query protocol. Currently at version 0.9.0, it aims for universal compatibility, running across Node.js, Bun, Deno, Cloudflare Workers, Electron, React Native, and browsers. It provides a unified API for various SQL and NoSQL databases, including PostgreSQL, MySQL, MariaDB, SQLite, LibSQL, Neon, D1, and MongoDB. Key differentiators include 100% serializable queries, deeply type-safe APIs for intelligent auto-completion, multi-level operators, and robust support for advanced features like semantic search. While still pre-1.0, the project shows active development with frequent updates and a strong focus on performance and developer experience, offering both decorator-based and imperative entity definition styles.
Common errors
-
Decorators not working: Ensure experimentalDecorators and emitDecoratorMetadata are enabled in tsconfig.json
cause TypeScript compiler options are not set for decorator processing.fixAdd `"experimentalDecorators": true` and `"emitDecoratorMetadata": true` to your `tsconfig.json` under `compilerOptions`. -
ESM import issues: UQL is Pure ESM — set your module to NodeNext, ESNext, or Bundler
cause Attempting to import UQL in a CommonJS environment or with incorrect module resolution settings.fixConfigure your project to use ECMAScript Modules (ESM). For TypeScript, set `"module": "NodeNext"` and `"moduleResolution": "NodeNext"` in `tsconfig.json`. For Node.js, ensure `"type": "module"` in `package.json`. -
Connection errors: Double-check database credentials and that your driver package (for example pg, mysql2, or better-sqlite3) is installed and compatible with your runtime.
cause Incorrect database connection string, invalid credentials, or the required database driver package is missing or incompatible.fixVerify all connection parameters (host, port, user, password, database). Ensure you have installed the correct database driver (e.g., `npm install pg` for PostgreSQL) and that its version is compatible with your Node.js runtime and UQL. -
TypeError: Cannot read properties of undefined (reading 'constructor') at Reflect.getMetadata
cause This error often occurs when decorators are used, but `emitDecoratorMetadata` is not enabled, leading to missing type metadata at runtime.fixEnsure `"emitDecoratorMetadata": true` is set in your `tsconfig.json` under `compilerOptions`.
Warnings
- breaking UQL is currently pre-1.0 (v0.9.0), meaning API surfaces may evolve rapidly and introduce breaking changes in minor versions. Always review release notes when upgrading to new 0.x.x versions.
- gotcha If using TypeScript decorators for entity definition (e.g., `@Entity`, `@Field`), your `tsconfig.json` must have `"experimentalDecorators": true` and `"emitDecoratorMetadata": true` enabled. Failure to do so will result in decorators being ignored or runtime errors due to missing metadata.
- gotcha UQL is a Pure ESM (ECMAScript Module) package. Using CommonJS `require()` statements to import UQL modules will lead to import errors. Your project's module resolution must be configured for ESM.
- gotcha Database drivers (e.g., `pg`, `mysql2`, `better-sqlite3`, `mongodb`) are peer dependencies and must be installed separately alongside `uql-orm`. UQL does not bundle these drivers.
- breaking Prior to v0.8.0, entity definitions in UQL were exclusively decorator-based, which required specific TypeScript compiler flags (`experimentalDecorators`). Version 0.8.0 introduced the `defineEntity` API as an alternative, decoupling entity metadata from class definitions and making decorators optional. This was a significant shift for projects constrained by decorator support.
Install
-
npm install uql-orm -
yarn add uql-orm -
pnpm add uql-orm
Imports
- { Entity, Id, Field }
import * as uql from 'uql-orm'; // Then uql.Entity
import { Entity, Id, Field } from 'uql-orm'; - defineEntity
const defineEntity = require('uql-orm').defineEntity;import { defineEntity } from 'uql-orm'; - PgQuerierPool
import { PgQuerierPool } from 'uql-orm';import { PgQuerierPool } from 'uql-orm/postgres'; - type Relation
import { Relation } from 'uql-orm';import { type Relation } from 'uql-orm';
Quickstart
import { Entity, Id, Field } from 'uql-orm';
import { PgQuerierPool } from 'uql-orm/postgres';
// 1. Define your Entity (User.ts)
@Entity()
export class User {
@Id({ type: 'uuid' })
id?: string;
@Field({ unique: true })
email?: string;
@Field()
name?: string;
}
// 2. Set up the Pool and Query (app.ts)
async function runQuery() {
const pool = new PgQuerierPool({
host: process.env.DB_HOST ?? 'localhost',
port: parseInt(process.env.DB_PORT ?? '5432', 10),
database: process.env.DB_NAME ?? 'app_db',
user: process.env.DB_USER ?? 'postgres',
password: process.env.DB_PASSWORD ?? 'password',
});
try {
await pool.withQuerier(async (querier) => {
// Ensure schema is in sync (for development/testing)
// In production, use migrations CLI
await querier.sync(User, { drop: true }); // DANGER: drops table
// Create a user
const newUser = await querier.createOne(User, { email: 'test@example.com', name: 'John Doe' });
console.log('Created user:', newUser);
// Find users
const users = await querier.findMany(User, {
$where: { name: { $istartsWith: 'John' } },
$select: { id: true, email: true },
});
console.log('Found users:', users);
});
} catch (error) {
console.error('Database operation failed:', error);
} finally {
await pool.end(); // Don't forget to release connections
}
}
runQuery();
// tsconfig.json configuration for decorators:
// {
// "compilerOptions": {
// "experimentalDecorators": true,
// "emitDecoratorMetadata": true,
// "moduleResolution": "NodeNext",
// "module": "NodeNext",
// "target": "ES2022"
// }
// }