@mathislair/mtbdb
v0.4.0
Published
mtbDB - schema-driven ORM for TypeScript with introspection and code generation (inspired by TDBM)
Downloads
456
Maintainers
Readme
mtbDB
A schema-driven ORM for TypeScript: introspect your database, generate typed beans and DAOs, and write code against them.
Inspired by TheDataBaseMachine (TDBM) from the PHP world.
Status
PostgreSQL is supported today. The driver layer is dialect-agnostic; MySQL and
SQLite drivers can be added by implementing the Driver interface in
src/drivers/Driver.ts.
Install
npm install @mathislair/mtbdbOr install from source:
git clone https://github.com/mathislair/orm.git
cd orm
npm install
npm run buildWorkflow
Describe your DB in
mtbDB.config.json:{ "driver": "postgres", "host": "localhost", "port": 5432, "user": "postgres", "password": "postgres", "database": "myapp", "schema": "public", "outDir": "./src/generated" }Generate beans + DAOs:
npx mtbdb generateThis creates two files per table:
_base/<Table>Bean.base.ts(regenerated each run, do not edit)<Table>Bean.ts(user-editable, regenerated only if missing)
Same pattern for DAOs. This is the same two-tier layout TDBM uses in PHP — you can re-run generation safely without losing your custom code.
Use them:
import { Connection } from '@mathislair/mtbdb'; import { UserDao, CountryDao } from './generated'; const conn = await Connection.open({ driver: 'postgres', host: 'localhost', database: 'myapp', user: 'postgres', password: 'postgres', }); const userDao = conn.dao(UserDao); const countryDao = conn.dao(CountryDao); // Create const fr = countryDao.create(); fr.code = 'FR'; fr.name = 'France'; await countryDao.save(fr); const u = userDao.create(); u.email = '[email protected]'; u.fullName = 'Alice'; u.setCountry(fr); // FK setter keeps country_id in sync await userDao.save(u); // Read with FK navigation const found = await userDao.findOne({ email: '[email protected]' }); const country = await found?.getCountry(); // typed: CountryBean | null // Update — only dirty columns hit the DB if (found) { found.fullName = 'Alice Smith'; await userDao.save(found); } // Delete if (found) await userDao.delete(found); await conn.close();
Architecture
src/
drivers/
Driver.ts # Driver + Dialect interfaces (the seam for new DBs)
PostgresDriver.ts # pg-backed implementation
schema/
types.ts # DatabaseSchema, TableInfo, ColumnInfo, ForeignKey
PostgresIntrospector.ts
runtime/
Connection.ts # entry point + DAO registry
AbstractBean.ts # dirty tracking, state machine
AbstractDao.ts # CRUD: find, findById, findOne, save, delete, count
QueryBuilder.ts # parameterized SQL via the Dialect
IdentityMap.ts # row-identity cache per Connection
codegen/
Generator.ts # emits two-tier .ts files from the introspected schema
naming.ts # table -> ClassName conventions (singular)
cli/
index.ts # `mtbdb generate`Adding a new database driver
- Implement
DriverandDialectinsrc/drivers/<Name>Driver.ts. - Write an introspector that returns the same
DatabaseSchemashape. - Register the driver name in
Connection.createDriver.
The runtime, code generator, and CLI work unchanged — they only depend on the
driver interface and DatabaseSchema.
Tests
npm testThe default test suite runs without a database (it tests the query builder, bean state machine, and code generator end-to-end against a synthetic schema).
Publishing to npm
Maintainers only. The prepublishOnly script builds and runs tests; only
dist/, README.md, and LICENSE are shipped (see the files whitelist in
package.json).
npm login
npm publish --access publicSee also
dbform — a companion package that
turns a database schema registry into auto-generated forms (React, Vue, Svelte).
The two packages are intentionally decoupled: dbform consumes a plain
SchemaRegistry value and takes no runtime dependency on mtbDB. The
introspected DatabaseSchema produced by mtbDB can be transformed into that
shape in a thin user-space adapter.
