Skip to content
VibORM
Esc
navigateopen⌘Jpreview
On this page

MySQL Driver

MySQL migration support with inline ENUM columns, btree/fulltext/spatial indexes, and InnoDB-aware type handling

Capabilities

Feature Supported
Native enums Yes (inline ENUM column type)
Native arrays No (stored as JSON)
Index types btree, fulltext, spatial
Transactions Limited — DDL statements implicitly commit

Type Mappings

VibORM Scalar MySQL Type
string() TEXT
int() INT
bigint() BIGINT
number() DOUBLE
decimal({ precision, scale }) DECIMAL(precision,scale)
boolean() TINYINT(1)
datetime() DATETIME(3)
date() DATE
time() TIME(3)
json() JSON
blob() BLOB
enumScalar() Inline ENUM('a', 'b', ...)
Array scalars JSON

DATETIME(3) and TIME(3) preserve JavaScript Date millisecond precision. Decimal-list JSON contains canonical coefficient strings, never JSON numbers, and carries one exact VibORM column-comment marker so introspection can recover the element precision and scale.

Exact decimal requirements

Every effectful MySQL migration command proves MySQL 8.0.16 or later and a strict SQL mode on its pinned session before its first effect. Earlier releases parse CHECK syntax but do not enforce the named constraints that prove a decimal conversion before MODIFY COLUMN. The accepted modes are STRICT_TRANS_TABLES and STRICT_ALL_TABLES.

The V1 provider domain is uniform for scalar and list fields: precision <= 65, scale <= 30, and precision + scale <= 65. A descriptor with precision 65 and scale 30 is therefore outside the admitted API even though MySQL can spell DECIMAL(65,30) in another context.

The proof is command-wide, not a decimal-statement classifier. Migration work can include provider-authored DDL and manual artifacts whose value effects cannot be classified safely before execution. One admission proof therefore protects the complete command without adding a per-statement mode query. Ordinary typed writes do not add a session-admission query. Arithmetic remains fail-loud on non-strict sessions because its UPDATE checks the exact intermediate and final domains before assignment. Configure strict mode for raw SQL and other out-of-band writes.

A scalar descriptor conversion uses a reversible three-statement proof bracket: add one reserved named CHECK, run MODIFY COLUMN, then drop the proof. Each completed DDL statement is an implicit commit boundary. An interruption can therefore leave at most one reserved proof behind.

The next locked migration command authenticates that proof’s reserved name, column, and exact predicate before its first effect. A foreign collision, malformed proof, or multiple reserved proofs is refused before any DROP. The authenticated cleanup is planned once per command, runs in the first sequential program, and is recorded through the same last-completed-statement boundary as the conversion statements. A later failure reports the last statement that completed, including the recovery DROP when it completed.

A decimal list can widen precision without rewriting its member strings when its scale does not change. The migration still adds a validating CHECK, runs MODIFY COLUMN to replace the descriptor marker, then drops the check. A list change that must rewrite JSON members is refused before effects: MySQL DDL implicitly commits, and a column CHECK cannot validate every member of a JSON array before that boundary.

PlanetScale has no admitted effectful migration route. Decimal-list marker create/introspect/alter survival is therefore proved on the MySQL dialect substrate; a hosted PlanetScale connection can only provide the available introspection leg.

Portable String Collation

VibORM’s MySQL adapter targets MySQL 8.0+. New tables use utf8mb4_0900_bin. Its binary, no-pad comparison keeps case, accents, and trailing spaces distinct for primary keys and unique constraints, matching PostgreSQL and SQLite-family behavior.

Existing MySQL tables are not converted automatically because VibORM’s schema snapshot does not track table collation. Apply an explicit migration for each existing table that participates in portable string comparisons:

ALTER TABLE `users`
  CONVERT TO CHARACTER SET utf8mb4
  COLLATE utf8mb4_0900_bin;

This rebuilds character columns and their indexes and may lock or copy a large table. Review the database’s online-DDL plan and deploy the migration deliberately; a code upgrade alone does not change existing schema semantics.

Auto-Increment

AUTO_INCREMENT requires an integer column type (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT); the driver rejects it on anything else:

const User = model("users", {
  id: int().primaryKey().autoIncrement(),
});

Generates:

CREATE TABLE `users` (
  `id` INT AUTO_INCREMENT PRIMARY KEY
);

Enums

MySQL has no standalone enum type — the ENUM is part of the column definition:

const User = model("users", {
  status: enumScalar(["active", "inactive", "pending"]),
});

Generates:

CREATE TABLE `users` (
  `status` ENUM('active', 'inactive', 'pending') NOT NULL
);

Changing an enum’s values therefore issues a MODIFY COLUMN for every column using it.

Index Types

The driver generates and introspects btree (default), FULLTEXT, and SPATIAL indexes. InnoDB does not support user-defined hash indexes. See Index Options for declaring indexes on models.

Indexed TEXT Columns

InnoDB can’t index a TEXT column without an explicit key length. When a string() column participates in a primary key, unique constraint, index, or foreign key, the driver maps it to VARCHAR(191) instead (191 × 4 bytes fits the 767-byte InnoDB key limit).

Column Defaults

MySQL doesn’t allow DEFAULT values on TEXT, BLOB, JSON, or spatial columns; the driver omits defaults for those types.

Limitations

Limitation Behavior
DDL in transactions Statements implicitly commit — a failed migration can leave earlier statements applied
Native arrays Stored as JSON
Hash indexes Not supported by InnoDB

Next Steps

Was this page helpful?