YellowbrickDialect extends PostgresDialect and reuses the pg$n binding, identifier escaping and every read-path builder.| Property | Value |
|---|---|
| Dialect name | yellowbrick |
| Extends | PostgresDialect |
| Driver | pg |
| Default port | 5432 |
| Cloud SDK | none |
| Local runtime | none — hosted service only |
$ npm install ts-prorm-orm pg$ pnpm add ts-prorm-orm pg$ yarn add ts-prorm-orm pg$ bun add ts-prorm-orm pgpg is the same driver the postgres dialect uses. pg-copy-streams is optional: only the features that need it load it.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'yellowbrick',
host: 'yb.example.com',
database: 'warehouse',
username: 'analyst',
password: process.env.YB_PASSWORD,
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'yellowbrick',
url: 'yellowbrick://analyst:secret@yb.example.com:5432/warehouse',
});host, port, database, username and password before the dialect is built; any of those passed alongside it wins.import { DataTypes } from 'ts-prorm-orm';
const User = db.define('User', {
id: { type: DataTypes.INTEGER(), primaryKey: true },
email: { type: DataTypes.STRING(255), allowNull: false, unique: true },
name: { type: DataTypes.STRING(100) },
});
await db.sync(); // CREATE TABLE — see Generated SQL belowautoIncrement: the engine has no sequence or identity column the dialect will emit, so the application supplies id.import { Op } from 'ts-prorm-orm';
await User.create({ id: 1, email: 'ada@example.com', name: 'Ada' });
const page = await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});query(), captured with the driver stubbed out. The model layer inlines the values.db.sync() for the model in the Quick start:CREATE TABLEawait User.create({ id: 1, email: 'ada@example.com', name: 'Ada' });
await User.update({ name: 'Grace' }, { where: { email: 'ada@example.com' } });
await User.destroy({ where: { id: 1 } });[!WARNING] No upsert
Yellowbrick has no INSERT ... ON CONFLICT and no MERGE (and does not enforce unique keys, so there is no conflict to detect). Upsert as DELETE of the matching keys then INSERT, inside one transaction.
await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});await db.transaction(async (t) => {
await User.create({ id: 2, email: 'grace@example.com', name: 'Grace' }, { transaction: t });
// A nested transaction is a SAVEPOINT; its failure undoes only its own work.
await db
.transaction(async (sp) => {
await User.destroy({ where: { id: 1 }, transaction: sp });
throw new Error('keep the row');
}, { transaction: t })
.catch(() => {});
});STRING → VARCHAR(255), auto-increment INTEGER → refused, BOOLEAN → BOOLEAN, DATE → TIMESTAMP, UUID → UUID, JSON → JSON. The type comparison lines the major engines up side by side.import { YellowbrickDialect } from 'prorm/dialects/yellowbrick';
const dialect = new YellowbrickDialect({
host: 'yb.example.com',
username: 'analyst',
password: process.env.YB_PASSWORD,
database: 'warehouse',
});YellowbrickDialect extends PostgresDialect (postgres) andObject.getOwnPropertyNames(YellowbrickDialect.prototype),| Area | Overridden |
|---|---|
| Connection and execution | listen, notify, query, unlisten |
| DML builders | buildDeleteQuery, buildInsertQuery, buildMergeQuery, buildUpdateQuery, buildUpsertQuery, formatDefaultValue |
| Types | buildColumnSql, canonicalTypeSql, createEnumType, ensureEnumTypes, getDataTypeSql, mapNativeType, unsupportedType |
| DDL and schema | addColumn, addIndex, alterVarcharLength, attachPartition, buildAlterVarcharLengthSql, buildCreateSequenceSql, buildCreateTableAsQuery, buildCreateTableSql, buildPartitionSpec, buildTableConstraintSql, changeColumn, createDomain, createExtension, createGINIndex, createGISTIndex, createIndex, createMaterializedView, createPartition, createPartitionedTable, createPolicy, createSequence, createTable, createTrigger, detachPartition, disableRLS, dropExtension, dropPartition, dropPolicy, dropTrigger, enableRLS, refreshMaterializedView, removeColumn |
| Introspection | getExtensions, hasExtension, hasPolicy, hasTrigger |
| Other | buildLayoutClauses, formatRangeStep, formatRangeValue, indexRefusal, matviewRefusal, partitionRefusal, returningRefusal, rlsRefusal, serialRefusal, upsertRefusal |
buildCreateTableSql appends, in the order Yellowbrick requires:DISTRIBUTE ON (col) / DISTRIBUTE RANDOM / DISTRIBUTE REPLICATESORT ON (col) or CLUSTER ON (col, ...) (up to 4 — mutually exclusive)PARTITION BY (RANGE (...) | HASH (...), ...) (up to 4 columns)dialect.buildCreateTableSql('events', {
id: { type: DataTypes.BIGINT, allowNull: false },
ts: { type: DataTypes.DATE },
}, {
distribute: { on: 'id' },
sortOn: 'ts',
partitions: [
{ type: 'hash', column: 'id', partitions: 64, isNull: true },
{
type: 'range',
column: 'ts',
between: [{ date: '2024-01-01' }, { date: '2024-12-31' }],
each: { interval: '1 month' },
outsideRange: true,
},
],
});{ date } or { timestamp }; steps are numbers or{ interval } — all string values are escaped. Checked before any SQL is sent:SORT ON withCLUSTER ON, more than 4 cluster or partition columns, hash partition countsIS NULL), and partitioning a replicatedbuildCreateTableAsQuery compiles the SELECT from findAll-shaped options,dialect.buildCreateTableAsQuery(
'stats',
{ tableName: 'matches', where: { season: 5 } },
{ distribute: { on: 'season' }, sortOn: 'team' },
);
// CREATE TABLE "stats" AS SELECT * FROM "matches" WHERE "season" = $1
// DISTRIBUTE ON ("season") SORT ON ("team") values: [5]PRIMARY KEY, UNIQUE and FOREIGN KEY are accepted but not enforced;NOT NULL isCHECK constraints do not exist and are refused.ON CONFLICT, no MERGE and no RETURNING.upsert, buildUpsertQuery, buildMergeQuery throw — upsert asDELETE + INSERT in one transaction.returning on insert/update/delete throws.query() appends RETURNING * to every INSERT toquery() sendsSERIAL and no identity column; autoIncrement throws. SequencesSTART WITH:dialect.buildCreateSequenceSql({ name: 'matchid', startWith: 1000 });
// CREATE SEQUENCE "matchid" START WITH 1000nextval('matchid') explicitly. incrementBy, cache, minvalue,maxvalue, cycle and ownedBy are refused rather than ignored.removeColumn throws — there is no DROP COLUMN.changeColumn throws; the one retype Yellowbrick allows is lengthening aVARCHAR: alterVarcharLength('team', 'city', 30) →ALTER TABLE "team" ALTER COLUMN "city" VARCHAR(30).addColumn refuses NOT NULL and autoIncrement.| Model type | Yellowbrick | Note |
|---|---|---|
TEXT | VARCHAR(64000) | TEXT columns cannot be created |
STRING(n) / CHAR(n) | VARCHAR(n) / CHAR(n) | n over 64,000 throws |
DECIMAL(p,s) | DECIMAL(p,s) | p over 38 throws |
INTERVAL, ARRAY, RANGE | throws | not column types |
INET, CIDR | throws | declare 'IPV4' / 'IPV6' as a string type |
HSTORE, VECTOR, PostGIS, CITEXT | throws | no extensions |
anything autoIncrement | throws | no SERIAL |
JSON / JSONB | as PostgreSQL | full JSON support is a Yellowbrick 7.x feature |
| Asked for | What happens |
|---|---|
addIndex, createIndex, GIN/GiST, createTable({ indexes }) | Refused — no CREATE INDEX; use layout |
upsert, buildUpsertQuery, buildMergeQuery | Refused |
returning on any write | Refused |
autoIncrement, SERIAL | Refused |
Sequence options other than START WITH | Refused |
CHECK constraints | Refused |
raw partitionBy, inherit, tablespace | Refused |
removeColumn, changeColumn, NOT NULL addColumn | Refused |
| Triggers, extensions, materialized views, RLS | Refused; has* report none |
createEnumType, createDomain | Refused |
LISTEN / UNLISTEN / NOTIFY | Refused |
| Declarative partition entry points | Refused — partitions are declared on CREATE TABLE |
SAVEPOINT, TRUNCATE, COPY, PL/pgSQL storedON COMMIT).ybload, Yellowbrick's separate client tool, and iscapabilitiesOf() (src/transaction-support.ts),whereSupportOf() (src/query-builders/expression-render.ts),sqlObjectCapabilitiesOf() (src/sql-objects/capabilities.ts) and the| Capability | yellowbrick |
|---|---|
| Transactions atomic | yes |
| Savepoints | yes |
| Isolation | up to SERIALIZABLE |
| Transaction modes | read-only yes; deferrable yes; constraint deferral yes |
| RETURNING | refused — Yellowbrick has no RETURNING clause on INSERT. Read the affected rows back with a SELECT on the same key. |
| Upsert | refused — Yellowbrick has no INSERT ... ON CONFLICT and no MERGE (and does not enforce unique keys, so there is no conflict to detect). Upsert as DELETE of the matching k |
| JSON column | JSON (JSONB → JSONB) |
| Vector column | refused — Yellowbrick does not support pgvector types (it has no extensions) (column type 'VECTOR'). |
| Array column | refused — Yellowbrick does not support array columns (column type 'ARRAY'). |
| WHERE builder | 62 operator keys; $and/$or/$not; $exists: yes; $in subquery: yes; expression operands: yes |
| SQL objects | family unknown: triggers no; procedures no; functions no; materialized views no; sequences no; enums check; RLS no |
| Streaming | queryStream() present; LISTEN present; createExtension() present |
tests/dialects/yellowbrick.test.ts exercises the dialect with a mocked driver, so nothing touches a server.