MySQL & MariaDB
MySQL and MariaDB share a dialect base but are two entry points with two drivers. Pick the one that matches the server you run: the generated SQL differs, and the MySQL dialect emits JSON operators MariaDB does not have.
| Server | Entry point | Driver |
|---|---|---|
| MySQL 8+ | uql-orm/mysql |
mysql2 |
| MariaDB 10.5+ | uql-orm/maria |
mariadb |
| Either, under Bun | uql-orm/bunSql |
built in |
Connect
Section titled “Connect”npm install uql-orm mysql2 # or: mariadbimport { setQuerierPool } from 'uql-orm';import { MySql2QuerierPool } from 'uql-orm/mysql';// MariaDB: import { MariadbQuerierPool } from 'uql-orm/maria';
export const pool = new MySql2QuerierPool({ host: 'localhost', user: 'app', password: process.env.DB_PASSWORD, database: 'app', connectionLimit: 10,});
setQuerierPool(pool);Both take their driver’s own pool config verbatim, connect lazily, and close with pool.end().
Generated ids after a multi-row insert
Section titled “Generated ids after a multi-row insert”The one behavioral difference worth knowing before choosing. MariaDB 10.5+ has INSERT ... RETURNING, so ids come back exact. MySQL has none: the driver reports only the first id and UQL infers the rest by incrementing it.
const ids = await pool.insertMany(User, users);That inference holds under innodb_autoinc_lock_mode 0 or 1. MySQL 8 defaults to mode 2 (interleaved), where a concurrent insert into the same table can interleave with your statement’s allocation and leave the block non-contiguous. On a hot table, set lock mode 1 or insert row by row.
What the dialect does
Section titled “What the dialect does”- Tables are
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; the surrogate key isBIGINT UNSIGNED AUTO_INCREMENT. - Transactions use
START TRANSACTIONwith the isolation level set on the session just before. All four levels work; the default isrepeatable read. - Upserts compile to
INSERT ... ON DUPLICATE KEY UPDATE, orINSERT IGNOREwhen every non-conflict column is a conflict key. Neither takes a conflict target: the server picks the unique index. - Arrays are not native: a
string[]field is stored as JSON and queried with the JSON operators. - JSON paths differ: MySQL uses
->/->>, MariaDB has neither and usesJSON_VALUE()/JSON_EXTRACT(). Emitting the right one is the main reason the entry points are separate. - Bound parameters cap at 65,535, so large
insertManypayloads are chunked for you.
Search
Section titled “Search”$text compiles to MATCH(...) AGAINST(...), which needs a FULLTEXT index over exactly the columns searched, in order:
import { Index } from 'uql-orm';
@Index(['title', 'body'], { type: 'fulltext' })Migrations create it. Without it the server answers “Can’t find FULLTEXT index matching the column list”.
MariaDB 11.7+ has a native VECTOR(n) type with an inline index, so semantic search works with no extension. MySQL has no equivalent.
Both drivers stream natively: mysql2 through its result-set .stream(), mariadb through queryStream.