dolt SQL dialect.doltdoltdolt sql-server speaks the MySQL protocol and implementsDoltDialect extends MySQLDialect and reuses mysql2,? placeholders and every CRUD builder.| Property | Value |
|---|---|
| Dialect name | dolt |
| Extends | MySQLDialect (mysql) |
| Driver | mysql2 |
| Cloud SDK | none |
| Default port | 3306 |
| Local runtime | self-hosted; no image in this repo |
CALL DOLT_COMMIT('-a', '-m', 'msg')). That shape invites hand-builtescape().$ npm install ts-prorm-orm mysql2$ pnpm add ts-prorm-orm mysql2$ yarn add ts-prorm-orm mysql2$ bun add ts-prorm-orm mysql2mysql2 is the same driver the mysql dialect uses.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'dolt',
host: 'localhost',
database: 'mydb',
username: 'root',
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'dolt',
url: 'dolt://root@localhost:3306/mydb',
});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, autoIncrement: true },
email: { type: DataTypes.STRING(255), allowNull: false, unique: true },
name: { type: DataTypes.STRING(100) },
});
await db.sync(); // CREATE TABLE — see Generated SQL belowimport { Op } from 'ts-prorm-orm';
await User.create({ 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({ email: 'ada@example.com', name: 'Ada' });
await User.update({ name: 'Grace' }, { where: { email: 'ada@example.com' } });
await User.destroy({ where: { id: 1 } });await User.upsert({ id: 1, email: 'ada@example.com', name: 'Ada Lovelace' });upsert() also reads the row by primary key before and after the write, to return the instance.await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});[!NOTE] No JSON operator in the WHERE builder DataTypes.JSON()maps toJSON, but this dialect's WHERE builder refusesOp.containson it: Cannot render WHERE condition at meta.contains' is not implemented by its WHERE builder. The statement was not sent, because running it without the condition would match rows it should not.
await db.transaction(async (t) => {
await User.create({ 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 → INT, BOOLEAN → TINYINT(1), DATE → DATETIME, UUID → CHAR(36), JSON → JSON. The type comparison lines the major engines up side by side.Prorm (the class is not exported from the package root):import { Prorm } from 'ts-prorm-orm';
const d = new Prorm({
dialect: 'dolt',
host: '127.0.0.1',
// port defaults to 3306
username: 'root',
database: 'mydb', // or 'mydb/feature' — a revision database
});
await d.connect();mysql2.DoltDialect extends MySQLDialect (mysql) andObject.getOwnPropertyNames(DoltDialect.prototype),| Area | Overridden |
|---|---|
| Connection and execution | startTransaction |
| DML builders | buildDeleteBranchSql, buildDeleteTagSql, buildMergeSql, buildSelectQuery |
| DDL and schema | add, buildAddSql, buildCreateBranchSql, buildRenameBranchSql, buildSchemaDiffQuery, buildTableFunctionQuery, createBranch, createPartition, dropPartition |
| Introspection | assertRevision, checkout, hashOf |
| Other | buildAbortMergeSql, buildCheckoutSql, buildCherryPickSql, buildCommitSql, buildCopyBranchSql, buildDiffQuery, buildDiffStatQuery, buildDiffSummaryQuery, buildHashOfSql, buildHistoryQuery, buildLogQuery, buildResetSql, buildRevertSql, buildStatusQuery, buildTagSql, callProcedure, commit, deleteBranch, diff, formatAuthor, log, merge, quoteRevisionTable, rangeArgs, reset |
d.buildCommitSql({ message: 'Add users', all: true, author: { name: 'Ann', email: 'ann@x.io' } });
// CALL DOLT_COMMIT('-a', '-m', 'Add users', '--author', 'Ann <ann@x.io>')
d.buildAddSql('all'); // CALL DOLT_ADD('-A')
d.buildAddSql(['t1', 't2']); // CALL DOLT_ADD('t1', 't2')
d.buildCreateBranchSql('feature', 'main~2'); // CALL DOLT_BRANCH('feature', 'main~2')
d.buildCopyBranchSql('main', 'feature1'); // CALL DOLT_BRANCH('-c', 'main', 'feature1')
d.buildRenameBranchSql('old', 'new'); // CALL DOLT_BRANCH('-m', 'old', 'new')
d.buildDeleteBranchSql('b', { force: true }); // CALL DOLT_BRANCH('-D', 'b')
d.buildMergeSql('feature', { noFastForward: true, message: 'Merge feature' });
// CALL DOLT_MERGE('feature', '--no-ff', '-m', 'Merge feature')
d.buildAbortMergeSql(); // CALL DOLT_MERGE('--abort')
d.buildResetSql({ mode: 'hard', target: 'HEAD~1' }); // CALL DOLT_RESET('--hard', 'HEAD~1')
d.buildResetSql({ tables: ['t'] }); // CALL DOLT_RESET('t')
d.buildTagSql('v1.0', { ref: 'main', message: 'release' });
// CALL DOLT_TAG('-m', 'release', 'v1.0', 'main')
d.buildRevertSql('HEAD~2'); // CALL DOLT_REVERT('HEAD~2')
d.buildCherryPickSql('feature~1'); // CALL DOLT_CHERRY_PICK('feature~1')
d.buildHashOfSql('main'); // SELECT HASHOF('main') AS `hash`| Commit option | Flag |
|---|---|
message (required) | -m |
all | -a (modified tables) |
allTables | -A (including new tables) |
author ('Name <email>' or { name, email }) | --author |
allowEmpty / skipEmpty (exclusive) | --allow-empty / --skip-empty |
amend | --amend |
force | -f |
commit, add, createBranch, deleteBranch, merge, reset,hashOf.checkout() refusesDOLT_CHECKOUT switches the branch of the current session. This dialectmysql2 pool, so a checkout would move one pooled connection andcheckout() therefore throws.buildCheckoutSql(branch, { create?, force? }) still exists for a callerdatabase: 'mydb/feature', ord.quoteRevisionTable('mydb', 'feature', 'users') →`mydb/feature`.`users`.AS OFd.buildSelectQuery({ tableName: 'users', where: { id: 1 }, asOf: 'main~3' });
// { sql: "SELECT * FROM `users` AS OF 'main~3' WHERE `id` = ?", values: [1] }
d.buildSelectQuery({ tableName: 'users', asOf: new Date('2024-01-01') });
// SELECT * FROM `users` AS OF TIMESTAMP('2024-01-01 ...')asOf accepts a branch, tag, commit hash or HEAD~n (sent as a stringDate. Without asOf, the select is byte-identical to MySQL's.d.buildDiffQuery({ from: 'main', to: 'feature', table: 'inventory', where: { diff_type: 'removed' } });
// { sql: "SELECT * FROM DOLT_DIFF('main', 'feature', 'inventory') WHERE `diff_type` = ?", values: ['removed'] }
d.buildDiffQuery({ from: 'main', to: 'feature', table: 'inventory', threeDot: true });
// SELECT * FROM DOLT_DIFF('main...feature', 'inventory')
d.buildDiffSummaryQuery({ from: 'main', to: 'WORKING' });
d.buildDiffStatQuery({ from: 'main', to: 'WORKING', table: 'inventory' });
d.buildSchemaDiffQuery({ from: 'main', to: 'feature' });
d.buildLogQuery({ revision: { from: 'main', to: 'feature' }, tables: ['users'] });
// SELECT * FROM DOLT_LOG('main..feature', '--tables', 'users')where (a where-object, bound as ?) and limit. threeDotdiff(), log().d.buildHistoryQuery('users', { where: { id: 7 }, limit: 5 });
// SELECT * FROM `dolt_history_users` WHERE `id` = ? LIMIT 5
d.buildStatusQuery(); // SELECT * FROM `dolt_status`| Call | Why |
|---|---|
checkout() | Session-scoped branch switch on a pool (see above). |
buildSelectQuery({ lock }) | Dolt documents SELECT ... FOR UPDATE as unsupported: no row-level locks. |
startTransaction({ isolationLevel }) other than REPEATABLE_READ | SET TRANSACTION is not implemented; Dolt has one level. REPEATABLE_READ is accepted and simply not sent. |
createPartition, dropPartition | ADD/DROP PARTITION are not implemented. |
CREATE FUNCTION (loadable functions) is not implemented by Dolt.tests/dialects/dolt.test.ts withoutdolt sql-server is not exercised.CALL returns a result set (e.g. DOLT_COMMIT returns the new hash), butquery() treats CALL as a non-SELECT and returns nocommit() resolves to void; read the hash with hashOf('HEAD').AS OF insertion targets the root table only; joined tables are read atcapabilitiesOf() (src/transaction-support.ts),whereSupportOf() (src/query-builders/expression-render.ts),sqlObjectCapabilitiesOf() (src/sql-objects/capabilities.ts) and the| Capability | dolt |
|---|---|
| Transactions atomic | yes |
| Savepoints | yes |
| Isolation | up to SERIALIZABLE |
| Transaction modes | read-only yes; deferrable no; constraint deferral no |
| RETURNING | not emitted; returning is accepted and ignored |
| Upsert | INSERT … ON DUPLICATE KEY UPDATE |
| JSON column | JSON (JSONB → JSON) |
| Vector column | VECTOR(3) |
| Array column | VARCHAR(255) |
| WHERE builder | 28 operator keys plus the $json: prefix; $and/$or/$not; $exists: no; $in subquery: no; expression operands: no |
| SQL objects | family mysql: triggers yes; procedures yes; functions multiStatement; materialized views emulated (procedure); sequences no; enums inline; RLS no |
| Streaming | queryStream() present; LISTEN absent; createExtension() present |