Agent skill

Uql Orm

by rogerpadilla in rogerpadilla/uql

Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite.

MITAuto-check passedDatabases

Install Uql Orm

skills CLI
$ npx skills add rogerpadilla/uql --skill uql-orm -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install rogerpadilla/uql uql-orm --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/rogerpadilla/uql.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/uql-orm .claude/skills/uql-orm && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
uql-orm
GitHub stars
125
Token cost
~3.5k tokens
SKILL.md length
1,614 words
Files
1
Skills in repo
2
Repo updated
First seen
Licence
MIT

At a glance

Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite.

  • A project imports uql-orm
  • SKILL.md covers Setup, Entities, Queries and Connections and transactions, plus 2 more sections
  • Calls npm, npx and bun
  • Defining entities

What it does

Uql Orm is an agent skill from rogerpadilla/uql. Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite. Use when a project imports uql-orm, or when defining entities or triggers, querying, populating relations, writing transactions, raw SQL or migrations with it. UQL is not Prisma, Drizzle, TypeORM or MikroORM: their APIs do not carry over.

Its SKILL.md is about 3.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Databases, covering ORMs and data access. It works with PostgreSQL, Turso, TypeScript and MySQL. The repository describes itself as: JSON-native TypeScript ORM for Bun, Browsers, Edge, Deno, Node, Workers. The licence is MIT.

When your agent uses it

  • A project imports uql-orm
  • Defining entities
  • Populating relations
  • Writing transactions

Example prompts

  • “/uql-orm”

Requirements

  • Node.js

What it can do on your machine

Read from SKILL.md and the folder at commit 85f1ac3. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm
    • npx
    • bun

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • uql-orm.dev

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Uql Orm loads about 3.5k tokens when it runs. Until then it costs about 112 tokens; SKILL.md has 1,614 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~112
When it runs · the whole SKILL.md, loaded when a task matches
~3.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from rogerpadilla/uql at commit 85f1ac3, republished under its MIT licence (© rogerpadilla). 1,614 words, ~3,462 tokens.

Download SKILL.mdSave it as .claude/skills/uql-orm/SKILL.md (or your agent's skills folder).
name
uql-orm
description
Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite. Use when a project imports uql-orm, or when defining entities or triggers, querying, populating relations, writing transactions, raw SQL or migrations with it. UQL is not Prisma, Drizzle, TypeORM or MikroORM: their APIs do not carry over.

UQL

Entities are classes; a query is a JSON object checked key by key against the entity; the same query runs on every database UQL supports. There is no schema file, no generated client, and no query builder.

The full docs are Markdown at https://uql-orm.dev/llms.txt, one page per URL. Read the page for the task before guessing an option: every page listed there is a .md URL.

Setup

sh
npm install uql-orm pg   # or mysql2, mariadb, better-sqlite3, mongodb, @libsql/client, ...

ESM only. Node 24+, Bun, Deno or an edge runtime, TypeScript 5.2+. Decorators are the TC39 standard: never enable experimentalDecorators or emitDecoratorMetadata, never import reflect-metadata. In tsconfig.json, module is nodenext or preserve, and target is a dated one (es2022+), not esnext.

Node's type stripping runs no decorators: on Node, add tsx (npm i -D tsx), which uql-migrate imports uql.config.ts through. Next.js compiles TC39 decorators only through a babel.config.json with @babel/plugin-proposal-decorators at version: '2023-11'. A bundle that minifies class names (Next's server build, or any bundler's minify) needs @Entity({ name: 'todo' }): a table name is the class name otherwise.

ts
// uql.config.ts
import type { Config } from 'uql-orm';
import { PgQuerierPool } from 'uql-orm/postgres';
import { Post, User } from './entities.js';

export const pool = new PgQuerierPool({ connectionString: process.env.DATABASE_URL });

export default { pool, entities: [User, Post] } satisfies Config;

Each driver has its own entry point: uql-orm/postgres, uql-orm/mysql, uql-orm/maria, uql-orm/sqlite, uql-orm/mongo, uql-orm/libsql, uql-orm/turso, uql-orm/neon, uql-orm/d1, uql-orm/pglite, uql-orm/bunSql, uql-orm/mssql, uql-orm/cockroachdb. Build the pool once per process and import it.

Entities

ts
import { Entity, Field, Id, ManyToOne, OneToMany } from 'uql-orm';

@Entity()
export class User {
  @Id({ type: 'uuid', onInsert: () => crypto.randomUUID() })
  id!: string;

  @Field({ type: String, unique: true, nullable: false })
  email!: string;

  @OneToMany({ entity: () => Post, mappedBy: (post) => post.author })
  posts?: Post[];
}

@Entity()
export class Post {
  @Id({ type: Number })
  id!: number;

  @Field({ type: String })
  title?: string | null;

  @Field({ references: () => User })
  authorId?: string | null;

  @ManyToOne({ entity: () => User, references: (post) => post.authorId })
  author?: User;
}
  • Every @Field states its type: String, Number, Boolean, Date, BigInt, or a column type such as 'uuid', 'text', 'jsonb'. A foreign key takes references instead and inherits the target key's type. A Date is an instant, stored in UTC to the millisecond on every engine; precision sets other fractional digits.
  • A column is nullable unless it says nullable: false, and its property must admit null to match: title?: string | null. A property typed without | null on a nullable column is a compile error.
  • Declare a nullable: false column ! (email!: string): reads have it and inserts must name it, except a single-column key and a version, which uql fills. Declare ? whatever an insert may leave out: a nullable, onInsert, defaultValue, eager: false or computed field, and relations.
  • An engine's own column type is a raw constant, columnType: raw`tsvector` , rendered verbatim and carrying its own length/precision: never a bare string.
  • defaultValue is a value of the field's type (a JSON column's document, [] or {}), or SQL the database evaluates per row: one of currentTimestamp, currentDate, currentTime, uuid (not SQLite), uuidv7 (Postgres 18+, MariaDB 11.7+), or raw`...` . A string is always text, 'CURRENT_TIMESTAMP' included. The migration builder takes the same.
  • currentTimestamp is the database clock, UTC to the millisecond on every engine, where a raw CURRENT_TIMESTAMP is not on SQLite, MySQL or SQL Server. Use it for a default, a stamp, onUpdate or $where.
  • Members are named by callbacks, never by strings: mappedBy: (post) => post.author, references: (post) => post.authorId.
  • @ManyToMany({ entity: () => Tag, through: () => PostTag }) names its junction entity.
  • @Index((post) => [post.authorId], { where: { archived: { $ne: true } } }) states a partial index's filter as the predicate the query passes, never as raw: a planner matches the two by shape, so raw that means the same thing leaves the index unused.
  • @Field({ type: Number, version: true }), with [versionKey]?: 'version' on the class, is an optimistic lock: an update must carry the version it read (a compile error otherwise), and one against a row someone else moved on throws UqlOptimisticLockError (kind optimisticLock, HTTP 409). Its updates name one row by its id; save and upsert are refused.
  • @Field({ computed }) is a value the database produces, on a readonly property: SQL over the row, (u) => raw`${u.first} || ' ' || ${u.last}` , or a relation aggregate, (order) => order.items.count(). stored: true makes the SQL a generated column; stored: ['insert', 'update'] makes it a stamp, which a trigger writes on those events whoever writes the row (computed: currentTimestamp), where onUpdate covers only uql's own writes.
  • @Trigger({ on: 'afterUpdate', of: (post) => [post.status], where: { $old: { status: 'draft' } }, run }) is a trigger the database fires. run(newRow, oldRow) returns the body, written with insertInto, upsertInto (as upsertOne takes it), updateTable, deleteFrom and refuse(message) (fails the write), which are typed by the entity written and render on every engine; deferred: true fires an after trigger at commit, on Postgres only; anything else is raw SQL over the rows, per engine where they differ. A trigger's writes skip uql's fills and entity filters, soft delete included. MongoDB has none. Details, SQL Server's per-statement shape included: https://uql-orm.dev/entities/triggers.md
  • defineEntity defines the same entity without decorators: https://uql-orm.dev/entities/imperative.md

Queries

ts
import { User } from './entities.js';
import { pool } from './uql.config.js';

const users = await pool.findMany(User, {
  $select: { id: true, email: true },
  $where: { email: { $endsWith: '@uql-orm.dev' }, $or: [{ id: 'a' }, { id: 'b' }] },
  $populate: { posts: { $select: { title: true }, $sort: { id: 'desc' }, $limit: 5 } },
  $sort: { email: 'asc' },
  $skip: 0,
  $limit: 20,
});
  • The keys are $select, $exclude, $where, $populate, $count, $distinct, $sort, $skip, $limit; $count: { posts: true } tallies a to-many under _count without loading it.
  • $sort takes 'asc'/1 or 'desc'/-1, and 'ascNullsLast', 'ascNullsFirst', 'descNullsFirst' or 'descNullsLast' to say where nulls land, which reads the same on every engine (emulated where there is no NULLS FIRST). Unqualified, each engine keeps its own answer: Postgres sorts nulls last on asc, the rest sort them first.
  • findManyPage(User, { $sort: { createdAt: -1, id: 1 }, $limit: 20, $after }) pages by cursor, so page 1,000 costs what page 1 does, and answers { items, startCursor, endCursor, hasNextPage, hasPrevPage }: pass endCursor as $after, or startCursor as $before to go back. $sort must include the key or a unique nullable: false field, uses the entity's own fields, and takes no $skip. A nullable leading sort key pages correctly but cannot use an index.
  • $where takes a value for equality or an operator map: $eq, $ne, $lt, $lte, $gt, $gte, $in, $nin, $between, $like, $ilike, $regex, $startsWith, $endsWith, $includes, $isNull, $isNotNull. $and, $or, $not and $nor combine clauses.
  • NULL compares the way the engine compares it: on SQL, $ne, $nin, $not and $nor leave out a NULL row, where MongoDB keeps it. Name NULL where you want it, { $or: [{ col: { $ne: 'a' } }, { col: null }] }; ask for NULL with { col: null } and its absence with { col: { $ne: null } }.
  • $text: { $value } in $where searches text on every engine with full-text search, through the entity's @Index(..., { type: 'fulltext', config }), whose columns may carry a weight. $sort: { $text: 'desc' } ranks by relevance, and { $text: { $project: 'score' } } also returns it, typed with WithProjection<E, 'score'>.
  • A result is narrowed to what the query selected and populated: reading an unselected field is a compile error. Name that shape with QueryFindResult<User, 'id' | 'email'> rather than widening the query.
  • $populate loads relations in the same statement. Nothing is lazy: a relation not populated is not there.
  • A query is plain data, so it can be built dynamically, stored, or sent from a browser to uql-orm/http, whose handler serves only the entities its required include names.
  • Methods: findMany, findOne, findOneById, findManyAndCount, findManyPage, findManyStream, count, exists, aggregate, insertOne, insertMany, updateOneById, updateMany, saveOne, saveMany, upsertOne, upsertMany, deleteOneById, deleteMany. Each takes the entity class first.
  • upsertOne(Entity, { email: true }, row, update?): a conflicting row takes update, an update's payload with its operators ({ uses: { $inc: 1 } }), instead of row; a new one inserts row. An empty {} leaves a conflicting row as it is: insert if absent. Cascaded relations write on either branch, a found row's replaced, as updateMany does.
  • updateMany and deleteMany naming no rows - no $where holding a value (an undefined or an empty group holds none), no $limit - throw; { unfiltered: true } means the whole table.
  • An update takes { stock: { $inc: -1 } } to add, or $mul to multiply, in the statement, a NULL counting as 0, so a guard in $where (stock: { $gte: 1 }) makes a decrement race-safe. On SQL the step may be a ref or raw of the field's type ({ total: { $inc: newRow.amount } } in a trigger). JSON fields take $set, $unset, $push, $pull.
  • $lock: true locks the rows a read returns ({ $wait: 'skip' | 'nowait' } says what to do about a row someone else holds) and needs an open transaction; SQLite, libSQL, Turso, D1 and MongoDB have no row lock and refuse it.
  • queryErrorKind(err) names any failure the same on every engine - uniqueViolation, foreignKeyViolation, notNullViolation, checkViolation, optimisticLock, retryable, usage, security - so catch by kind rather than by a driver's code or an instanceof. Every error UQL raises itself is a UqlError.
  • raw() embeds SQL anywhere a value or field goes; pool.all(sql, values) runs a raw SELECT. A field read off refs(Entity) carries its type: on its own as a value it fits only a field of that type.
Show full SKILL.md (286 more words)Show less

Connections and transactions

Every method is on both the pool and a querier. A pool call acquires a connection for that call and releases it. To run several operations on one connection, or atomically, hold a querier:

ts
await pool.transaction(async (querier) => {
  const userId = await querier.insertOne(User, { email: 'ada@uql-orm.dev' });
  await querier.insertOne(Post, { title: 'Hello', authorId: userId });
});

Inside the callback, call querier, never pool: a pool call runs on another connection, outside the transaction. A querier from pool.getQuerier() is yours to release: bind it with await using.

A findManyStream holds its querier until the loop ends, which refuses any other statement meanwhile: inside the loop, run them on another connection; inside a transaction, or on SQLite and PGlite (one shared connection), run them after the loop. That includes an @AfterLoad querying through its querier on a streamed row. A statement binding more values than the engine takes (100 on D1, 2098 on SQL Server) is refused too: split a long $in.

Migrations

npx uql-migrate reads uql.config.ts (bun --bun uql-migrate on Bun):

  • sync applies what the entities imply (development only).
  • generate:entities writes the diff as a migration file to review. It renames a column whose field was renamed and refuses a required column with no default on a table holding rows.
  • up and down apply and revert migrations.
  • generate:from-db writes entity classes from an existing database.
  • drift:check fails when the database no longer matches.
  • sync --dry-run prints only SQL on stdout, to append to a migration file another tool applies: on Cloudflare D1, wrangler's (https://uql-orm.dev/cloudflare-d1.md).

Triggers are part of the diff: uql owns the _uql_-prefixed ones and never touches another.

Where to read more

© rogerpadilla, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/uql-orm of rogerpadilla/uql.

Open the folder on GitHubat commit 85f1ac3

Compare with similar skills

Uql Orm next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Uql Orm compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Uql Orm this skillrogerpadilla/uql125—~3.5kAutomated safety check: PassMIT
Better Drizzlealmeidazs/better-drizzle347—~1.7kAutomated safety check: PassApache-2.0
Prisma Database Setupcurvenote/curvenote1693 repos~1.4kAutomated safety check: PassMIT
Golang Databaseunxed/f42402 repos~2.9kAutomated safety check: PassMIT
Database Expertcin12211/orca-q223—~2.8kAutomated safety check: PassMIT
Prisma 8 Contract-First ORMprisma/orm48k—~3.7kAutomated safety check: NotesApache-2.0

Similar skills

  • Better Drizzle

    almeidazs/better-drizzle

    Write, review, and debug code that uses better-drizzle, the typed repository layer over Drizzle ORM 1.x (better(db), client.users.findMany, paginate, cursor, upsertMany, relation include/connect…

    347 GitHub stars~1.7k tokensUpdated 2 days ago
    DatabasesAuto-check passed
  • Prisma Database Setup

    curvenote/curvenote

    Guides for configuring Prisma with different database providers (PostgreSQL, MySQL, SQLite, MongoDB, etc.).

    169 GitHub starsUsed in 3 repos~1.4k tokens
    DatabasesAuto-check passed
  • Comprehensive guide for Go database access — parameterized queries, struct scanning, NULLable columns, transactions, isolation levels, SELECT FOR UPDATE, connection pool, batch processing, context…

    240 GitHub starsUsed in 2 repos~2.9k tokens
    DatabasesAuto-check passed
  • Database Expert

    cin12211/orca-q

    Database performance optimization, schema design, query analysis, and connection management across PostgreSQL, MySQL, MongoDB, and SQLite with ORM integration.

    223 GitHub stars~2.8k tokensUpdated 16 days ago
    DatabasesAuto-check passed
  • Official

    Routes Prisma 8 tasks such as contracts, migrations, queries and upgrades to the right reference files for projects on the contract-first @prisma/orm packages.

    48k GitHub stars~3.7k tokensUpdated yesterday
    DatabasesAuto-check: notes
  • Matlab Use Database

    matlab/matlab-agentic-toolkit

    Reads from, writes to, and manages relational databases using MATLAB Database Toolbox.

    1.1k GitHub stars~3.1k tokensUpdated 7 days ago
    DatabasesAuto-check passed

More from rogerpadilla/uql

  • Release

    rogerpadilla/uql

    Cut and publish a uql release - review the change, changelog entry, commit, version bump and tag, GitHub Release, npm publish, docs site.

    125 GitHub stars~842 tokensUpdated yesterday
    Auto-check passed

Categories

Questions about Uql Orm

What does Uql Orm do?

Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite. Uql Orm is an agent skill from rogerpadilla/uql. Write code with UQL (the uql-orm package), the TypeScript ORM whose queries are plain JSON objects, on PostgreSQL, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, MongoDB, Turso, Neon, D1 and PGlite.

When should I use Uql Orm?

Uql Orm fits situations like: A project imports uql-orm; defining entities; populating relations; writing transactions.

How do I install Uql Orm in Claude Code?

Run `npx skills add rogerpadilla/uql --skill uql-orm -a claude-code`. Or copy the skill folder (skills/uql-orm in rogerpadilla/uql) into .claude/skills/uql-orm in your project. Claude Code loads it when a task matches its description.

How do I install Uql Orm in Codex?

Run `npx skills add rogerpadilla/uql --skill uql-orm -a codex`. Or copy the skill folder (skills/uql-orm in rogerpadilla/uql) into .agents/skills/uql-orm in your project. Codex loads it when a task matches its description.

Can I use Uql Orm in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add rogerpadilla/uql --skill uql-orm -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/uql-orm, .gemini/skills/uql-orm, .github/skills/uql-orm and .opencode/skills/uql-orm in your project.

What does Uql Orm need to run?

Going by SKILL.md and its folder, Uql Orm needs the command-line tools its instructions call (npm, npx and bun). Our summary lists: Node.js.

Does Uql Orm access the network?

SKILL.md names 1 domain. As links in the text: uql-orm.dev. This is read from the text; nothing was executed.

Is Uql Orm safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Uql Orm use?

Uql Orm is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Uql Orm use?

About 3.5k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Uql Orm?

Skills that share tags, products or a category with Uql Orm: Better Drizzle (almeidazs/better-drizzle, 347 stars), Prisma Database Setup (curvenote/curvenote, 169 stars), Golang Database (unxed/f4, 240 stars) and Database Expert (cin12211/orca-q, 223 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Uql Orm?

rogerpadilla (a GitHub user) maintains it in rogerpadilla/uql, which has 125 GitHub stars. The repository holds 2 skills in this directory. The repository was last updated on October 6, 2026.

Source: rogerpadilla/uql on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.