Package Exports
- @mostajs/orm
- @mostajs/orm/bridge
- @mostajs/orm/register
- @mostajs/orm/validator
Readme
@mostajs/orm
Plug & Play ORM to Drive 13 Databases at Once
Hibernate-inspired multi-dialect ORM for Node.js & TypeScript โ one API, 13 databases, zero lock-in, bundler-friendly.
๐ฆ npm ยท https://www.npmjs.com/package/@mostajs/orm ๐ GitHub ยท https://github.com/apolocine/mosta-orm ๐ Docs ยท (coming soon) ๐ Product Hunt ยท (launch link to be added)
Why @mostajs/orm ?
- ๐ฏ One API, 13 dialects. Switch from PostgreSQL to MongoDB to SQLite without rewriting a single repository call.
- ๐ชถ Zero lock-in. Native drivers, no proprietary query DSL โ your SQL/NoSQL stays portable.
- ๐งฌ Hibernate / JPA semantics.
@OneToMany, cascade types,SAVEPOINT, schema strategies (validate/update/create/create-drop) โ concepts battle-tested for 25 years, ported to TypeScript. - ๐ Drop-in Prisma replacement.
@mostajs/orm-bridgelets you keep your Prisma code while running on any of 13 databases. - ๐ Cross-dialect replication built-in.
@mostajs/replicatorโ CDC + master/slave + failover across SQL โ MongoDB. - ๐งช Bundler-friendly. Tree-shakable ESM, no
eval, works with esbuild / Vite / Next.js / Bun out of the box.
60-second demo
npm install @mostajs/orm better-sqlite3import { getDialect } from '@mostajs/orm'
import { UserSchema } from './schemas/user.schema'
const db = await getDialect({ dialect: 'sqlite', uri: ':memory:' }, [UserSchema])
const userRepo = db.repo<typeof UserSchema>('User')
await userRepo.create({ email: 'alice@example.com', name: 'Alice' })
const alice = await userRepo.findOne({ email: 'alice@example.com' })Want PostgreSQL instead ? Change one line :
const db = await getDialect({ dialect: 'postgres', uri: process.env.DATABASE_URL }, [UserSchema])That's it. Same repo.create(), same repo.findOne(), same TypeScript types โ different dialect.
How it compares
| @mostajs/orm | Prisma | Drizzle | TypeORM | |
|---|---|---|---|---|
| SQL dialects | 9 (PG, MySQL, MariaDB, SQLite, MSSQL, Oracle, DB2, HANA, Cockroachโฆ) | 5 | 5 | 8 |
| NoSQL dialects | MongoDB native | โ | โ | โ |
| Same API across SQL & NoSQL | โ | โ | โ | โ |
| Cross-dialect replication | โ (via @mostajs/replicator) | โ | โ | โ |
| Schema-as-code (no DSL) | โ TypeScript objects | DSL .prisma |
TS objects | Decorators |
| Code generation step | โ (zero codegen) | โ required | โ | โ |
| Drop-in Prisma replacement | โ (via @mostajs/orm-bridge) | โ | โ | โ |
| Migration from Prisma | โ (automated CLI) | โ | manual | manual |
| Hibernate / JPA semantics | โ | โ | โ | partial |
| License | AGPL-3.0 (+ commercial) | Apache-2.0 | Apache-2.0 | MIT |
Numbers as of v1.13.1 โ see
@mostajs/orm-clifor the automated Prisma โ @mostajs migration tool.
Star ยท Sponsor ยท Contribute
If @mostajs/orm saves you days of glue code, please :
- โญ Star the repo โ visibility helps me keep maintaining it.
- ๐ Sponsor development โ github.com/sponsors/apolocine
- ๐ Report issues / submit PRs โ every contribution counts.
- โ๏ธ Commercial license & support : drmdh@msn.com
Databases
SQLite ยท PostgreSQL ยท MySQL ยท MariaDB ยท MongoDB ยท Oracle ยท SQL Server ยท CockroachDB ยท DB2 ยท SAP HANA ยท HSQLDB ยท Spanner ยท Sybase
Demos
1. Initialize the app
2. Initialize the database
3. Configure the app
4. Setup replication
5. Cross-dialect CDC rules & live sync
6. Frontend CRUD app
7. Prisma project (before migration)
8. Prisma โ @mostajs/orm migration (bootstrap)
Install
npm install @mostajs/orm
# + the driver for your dialect :
npm install better-sqlite3 # or: pg, mysql2, mongoose, oracledb, mssql, ibm_db, mariadb, @sap/hana-client, @google-cloud/spannerDefine a schema
import type { EntitySchema } from '@mostajs/orm'
export const UserSchema: EntitySchema = {
name: 'User',
collection: 'users',
timestamps: true,
fields: {
email: { type: 'string', required: true, unique: true },
name: { type: 'string', required: true },
},
relations: {
roles: { target: 'Role', type: 'many-to-many', through: 'user_roles' },
},
indexes: [{ fields: { email: 'asc' }, unique: true }],
}Unique keys
A field can be marked unique, or several fields can be combined into a composite unique constraint via indexes.
export const MemberSchema: EntitySchema = {
name: 'Member',
collection: 'members',
fields: {
email: { type: 'string', required: true, unique: true }, // single unique
tenantId: { type: 'string', required: true },
slug: { type: 'string', required: true },
},
indexes: [
{ fields: { tenantId: 'asc', slug: 'asc' }, unique: true }, // composite unique
],
}Both shapes enforce a DDL UNIQUE constraint on SQL dialects and a unique index on MongoDB. Lookup works the same way :
await repo.findOne({ email: 'a@b.com' }) // single unique
await repo.findOne({ tenantId: 't1', slug: 'admin' }) // composite uniqueConnect & CRUD
import { registerSchemas, getDialect, BaseRepository } from '@mostajs/orm'
registerSchemas([UserSchema])
const dialect = await getDialect() // reads DB_DIALECT + SGBD_URI from env
const repo = new BaseRepository(UserSchema, dialect)
await repo.create({ email: 'a@b.com', name: 'Admin' })
await repo.findOne({ email: 'a@b.com' })
await repo.findAll({ status: 'active' }, { sort: { name: 1 }, limit: 10 })
await repo.update(id, { name: 'Updated' })
await repo.delete(id)
await repo.findByIdWithRelations(id, ['roles'])
await repo.upsert({ email: 'a@b.com' }, { name: 'Upserted' })
await repo.count({ status: 'active' })Transactions
Group multiple operations into a single atomic unit. SQL dialects (PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle, DB2, CockroachDB, HANA, Sybase, HSQLDB, Spanner) wrap the callback in BEGIN / COMMIT / ROLLBACK. If any operation throws, every write inside the block is rolled back.
import { getDialect } from '@mostajs/orm'
const dialect = await getDialect()
await dialect.$transaction(async (tx) => {
await tx.create('accounts', { id: 'a', balance: 100 })
await tx.update('accounts', { id: 'b' }, { $inc: { balance: -50 } })
await tx.update('accounts', { id: 'a' }, { $inc: { balance: 50 } })
// throw here โ both updates are rolled back, `accounts.a` row is removed
})Isolation : default per dialect (SQL โ READ COMMITTED, SQLite โ DEFERRED). Pass { isolation: 'SERIALIZABLE' } as 2nd argument to override (SQL only).
All SQL dialects listed above support ACID natively โ PostgreSQL, MySQL/MariaDB, SQL Server, Oracle, DB2, SQLite, CockroachDB, HANA, Sybase, HSQLDB, Spanner. No configuration required beyond the usual connection.
MongoDB is the only exception : multi-document ACID transactions require a replica set (a single-node mongod --replSet rs0 is enough for dev โ this is a MongoDB server requirement, not a limitation of this library). On a standalone server, $transaction runs the callback without wrapping โ safe for read-heavy flows, non-atomic for writes.
Manual transactions โ beginTx / commitTx / rollbackTx (v1.11+)
When the $transaction(cb) callback pattern is too restrictive (transaction spans several unrelated functions, commit depends on an external event), use the manual API :
const tx = await dialect.beginTx()
try {
await dialect.create(UserSchema, { email: 'a@b.c', name: 'A' })
await someExternalCheck() // could be async, could take seconds
if (ok) await dialect.commitTx(tx)
else await dialect.rollbackTx(tx)
} catch (e) {
await dialect.rollbackTx(tx)
throw e
}Nested transactions โ SAVEPOINTs are used automatically :
const outer = await dialect.beginTx() // โ BEGIN
await dialect.create(UserSchema, { email: 'o@x.io', name: 'Outer' })
const inner = await dialect.beginTx() // โ SAVEPOINT mosta_sp_2_xxxx
await dialect.create(UserSchema, { email: 'i@x.io', name: 'Inner' })
await dialect.rollbackTx(inner) // โ ROLLBACK TO SAVEPOINT
// (inner row gone, outer untouched)
await dialect.commitTx(outer) // โ COMMIT
// (outer row persisted)Depth unbounded as long as the engine supports SAVEPOINT (every SQL dialect above except Spanner). MSSQL / Sybase use SAVE TRANSACTION / ROLLBACK TRANSACTION internally โ transparent to the API. commitTx / rollbackTx enforce LIFO order (out-of-order commit throws, out-of-order rollback is silent).
Environment
DB_DIALECT=postgres
SGBD_URI=postgresql://user:pass@localhost:5432/mydb
DB_SCHEMA_STRATEGY=update # validate | update | create | create-drop | none
DB_SHOW_SQL=trueThe naming mirrors Hibernate's hibernate.hbm2ddl.auto / hibernate.show_sql
properties (see Hibernate User Guide ยง schema strategies). Values have identical semantics : validate /
update / create / create-drop / none.
The dialect matching DB_DIALECT is lazy-loaded at runtime (v1.9.3+). Only the driver you actually use is evaluated โ no other dialect module enters your bundle. This is what makes @mostajs/orm safe to pull into a Next.js / Vite / SvelteKit project without bundler workarounds.
Profile cascade with MOSTA_ENV (v1.13+)
Powered by @mostajs/config.
Keep one .env file with profile-prefixed overrides and switch via a
single MOSTA_ENV variable โ exactly like Spring Boot profiles
(spring.profiles.active=test loading application-test.properties).
# .env โ committed (non-secret) defaults
MOSTA_ENV=TEST
# Base defaults (used when no profile, or as fallback)
DB_DIALECT=sqlite
SGBD_URI=./data.sqlite
# Profile overrides
TEST_DB_DIALECT=sqlite
TEST_SGBD_URI=./test.sqlite
TEST_DB_SCHEMA_STRATEGY=create-drop
DEV_DB_DIALECT=postgres
DEV_SGBD_URI=postgres://localhost:5432/devdb
DEV_DB_SCHEMA_STRATEGY=update
PROD_DB_DIALECT=mongodb
PROD_SGBD_URI=${SCALEWAY_MONGO_URI} # secret injected by orchestrator
PROD_DB_SCHEMA_STRATEGY=validateResolution cascade (first non-empty wins) :
${MOSTA_ENV}_${KEY}โ profile-prefixed${KEY}โ plainfallbackargumentundefinedโ no crash, caller decides whether that's fatal
Silent fallback is guaranteed : a missing profile override never throws, it
just falls through to the plain variable or to the default. Empty strings
(TEST_DB_DIALECT=) are treated as "not set" so they don't silently leak a
blank value.
For generic use outside @mostajs/orm, import directly from the config
package :
import { getEnv, getEnvBool, getEnvNumber, getCurrentProfile } from '@mostajs/config'
const url = getEnv('REDIS_URL', 'redis://localhost:6379')
console.log(`Profile : ${getCurrentProfile() ?? 'none'}`)Switch databases with one env var
DB_DIALECT=sqlite SGBD_URI=./data.sqlite
DB_DIALECT=postgres SGBD_URI=postgres://...
DB_DIALECT=mongodb SGBD_URI=mongodb://...
# same code in both casesSubpaths
| Subpath | When to use |
|---|---|
@mostajs/orm |
The core ORM API : getDialect, registerSchemas, BaseRepository, EntityService, schema types, diffSchemas, errors. |
@mostajs/orm/bridge |
JDBC bridge (v1.9.4+) : JdbcNormalizer, BridgeManager, JDBC_REGISTRY, jar upload. Pulled out of the root to keep child_process / fs spawn out of client bundles. |
@mostajs/orm/register |
Zero-code registration side-effect for dynamic schema loading. |
@mostajs/orm/validator |
v1.14+ โ ORMConceptValidator : algorithmic linter for EntitySchema sets. Detects 18 conceptual anomalies (empty relations, FK naming inconsistency, soft-delete patterns, dead code, missing audit, unbounded blobsโฆ). See below. |
๐ ORMConceptValidator (v1.14+)
Algorithmic linter for your ORM schemas โ detects 18 conceptual
anomalies before they bite in production. Zero IA, zero heuristics
flou, fully generic (no hardcoded entity name โ KNOWN_ENTITY_REFS
is derived at runtime from the schemas you pass).
Quick start
# CLI โ point it at your schemas directory
npx mostajs-orm-validator ./schemas
# With cross-file rules (R005, R007, R008, R011, R012, R014, R015) :
npx mostajs-orm-validator ./schemas --src ./lib
# In a CI pipeline :
npx mostajs-orm-validator ./schemas --src ./lib --ci --max-warnings 0Or programmatically :
import { validateSchemas, formatText } from '@mostajs/orm/validator'
import * as schemas from './schemas'
const report = await validateSchemas(Object.values(schemas), {
sourceRoot: './lib',
})
console.log(formatText(report))
console.log(`${report.findings.length} findings`)What it detects (18 rules)
| ID | Severity | Detection |
|---|---|---|
| R001-EMPTY-RELATIONS | warning | String field named like another entity (e.g. project, respondent) but relations: {} empty โ loses ORM cascade & FK validation |
| R002-FK-NAMING-INCONSISTENT | warning | Mix of conventions in same set (parentId vs project, questionId vs section) โ flags the minority |
| R003-SOFT-DELETE-INCONSISTENT | warning/info | Multiple soft-delete patterns concurrent (deleted/cancelled/archived) OR manual deleted/deletedAt while softDelete: true is available natively |
| R004-DUPLICATE-ENTITY-SHAPE | info | Pair of schemas with Jaccard on field names โฅ threshold (default 0.7) โ possible legacy |
| R004B-LEGACY-ENTITY | info/warning | Name overlap (substring โฅ 4 chars or Jaro-Winkler โฅ 0.75) โ flags the smaller schema. Bumps to warning if legacy/deprecated comment found in sources |
| R005-ANY-TYPED-REPO | warning | BaseRepository<any> in source files โ typing lost. Needs --src |
| R006-JSON-AS-RELATION | info | *sJson field containing list of FK slugs/ids โ should be normalized into junction table |
| R007-REDUNDANT-DERIVED-FIELD | info | Persisted field duplicate of a pure function of its id (e.g. blobPath derivable from archiveBlobPath(id)). Needs --src |
| R008-BEST-EFFORT-FK-RESOLVER | warning | best-effort/TODO V2/HACK comment + ?? null fallback โ root cause hidden. Needs --src |
| R009-MISSING-LOOKUP-INDEX | info/hint | unique field without dedicated index, OR FK string without index for inverse lookups |
| R010-MISSING-AUDIT-TABLE | hint | No schema resembling AuditLog (actor + action + timestamp) โ sensitive actions untraceable |
| R011-LEGACY-DEAD-CODE | info | TS source file never imported (entry points like page.tsx/route.ts excluded). Needs --src |
| R012-DUPLICATE-IMPLEMENTATION | info | Pair of source files exporting overlapping function signatures (Jaccard โฅ 0.85). Needs --src |
| R013-MISSING-CASCADE | warning | many-to-one relation without explicit onDelete โ orphans on parent delete |
| R014-REPO-FACTORY-BOILERPLATE | info | โฅ 5 get*Repo() helpers in same file โ suggest factory. Needs --src |
| R015-FLAT-LIB-STRUCTURE | hint | Directory with > 25 flat files โ suggest sub-directory organisation. Needs --src |
| R016-AUDIT-EMAIL-AS-STRING | info | createdBy/validatedBy/etc. typed string instead of FK User โ loses ref. integrity if email changes |
| R017-UNBOUNDED-BLOB-FIELD | hint | *Json/*Payload/*Blob/*Manifest without documented size limit |
| R018-EXTERNAL-SCHEMA-OVERSCOPED | info | (stub V2 โ full impl in V3 with ts-morph) External schema with many unused fields |
Output formats
# Console output (TTY-aware ANSI colors)
npx mostajs-orm-validator ./schemas
# JSON (for CI / diff)
npx mostajs-orm-validator ./schemas --format json --out report.json
# Markdown (human-readable report)
npx mostajs-orm-validator ./schemas --format markdown --out REPORT.mdExample output :
โ Section.project R001-EMPTY-RELATIONS warning
Field 'Section.project' looks like an FK to 'Project' but no ORM
relation declared.
Suggestion:
relations: {
project: { type: 'many-to-one', target: 'Project',
required: true, onDelete: 'cascade' },
},Configuration
All thresholds and patterns are configurable โ no hardcoded business
strings. Pass a config to validateSchemas :
const report = await validateSchemas(schemas, {
sourceRoot: './lib',
ignore: ['R015', 'R017'], // skip these rules entirely
rules: { R001: 'error' }, // override severity (e.g. block CI on R001)
softDeletePatterns: [
{ flag: 'deleted', timestamp: 'deletedAt' },
{ flag: 'cancelled', timestamp: 'cancelledAt' },
{ flag: 'archived', timestamp: 'archivedAt' },
// add your project-specific patterns here
],
auditByFields: ['createdBy', 'validatedBy', 'reviewedBy'],
thresholds: {
duplicateEntityJaccard: 0.7, // R004
duplicateImplJaroWinkler: 0.85, // R012
flatLibMaxFiles: 25, // R015
},
})CI integration
// package.json
{
"scripts": {
"lint:schemas": "mostajs-orm-validator ./schemas --src ./lib --ci --max-warnings 0"
}
}The --ci flag exits with code 1 if the number of error + warning
findings exceeds --max-warnings (default 0). Bind it to your
pre-commit hook or GitHub Actions to block regressions.
Generic by design
The validator is fully generic โ no hardcoded entity name, no
project-specific assumption. The set of "known entities"
(KNOWN_ENTITY_REFS) is derived at runtime from the schemas you pass.
Same binary detects the same anti-patterns in any consumer codebase.
TypeScript schemas
The CLI loads .ts/.tsx/.js/.mjs files directly via jiti
โ no pre-compile step required. TypeScript paths aliases are resolved
automatically.
EntityService (for @mostajs/net)
import { EntityService } from '@mostajs/orm'
const service = new EntityService(dialect)
const res = await service.execute({
op: 'findAll',
entity: 'User',
filter: { status: 'active' },
relations: ['roles'],
options: { limit: 10 },
})Operations : findAll, findOne, findById, create, update, delete, deleteMany, count, search, aggregate, upsert, updateMany, addToSet, pull, increment.
Schema management
await dialect.initSchema(getAllSchemas()) // create / update DDL per strategy
await dialect.truncateTable?.('users')
await dialect.truncateAll?.(getAllSchemas())
await dialect.dropTable?.('users')
await dialect.dropSchema?.(getAllSchemas())
await dialect.dropAllTables?.()Dialect-level guarantees (v1.13+)
Two classes of correctness fixes ship with 1.13, both driven by real
production pain encountered during @mostajs/replicator runs.
SQL dialects (AbstractSqlDialect)
- FK columns preserve falsy-but-valid values (
0,false). The previous short-circuitdata[name] || nullsilently replaced legitimate zero IDs and booleanfalsewithnull, breaking FK writes whose source-side PK happened to be0. The insert/update path now usesvalue === '' ? null : (value ?? null)โ empty strings still null-out (SQL foreign-key constraints reject them on most dialects) but numeric zero,falseand any non-empty value round-trip intact. - One-to-one relations get a column-level
UNIQUEconstraint. Emitted both atCREATE TABLEtime and atALTER TABLE ADDtime when growing an existing schema. Matches the JPA / Hibernate semantics where an@OneToOneFK must be injective (otherwise the "one" side of the relation is not actually single-valued).
Mongo dialect
- FK fields accept UUID strings in addition to native
ObjectId.buildMongooseSchemanow declares FK refs asSchema.Types.Mixedrather thanSchema.Types.ObjectId. Replicated documents originating from a SQL dialect (SQLite / Postgres / โฆ using UUID primary keys) are no longer rejected by Mongoose path validation. A native Mongo app writing properObjectIdrefs keeps working unchanged. findAll()/findOne()fall back to{ id: fkValue }whenpopulate()returnsnull. When a UUID-string FK cannot be resolved through the default Mongoose_idlookup (which expects matching type), the dialect keeps a rawlean()query alongside the populated one and patches the missing refs post-hoc by a directfindOne({ id: fk })on the target collection. Transparent to the caller, prevented silent data loss during cross-dialect reads.
Together, these four items unblock bidirectional SQL โ Mongo sync through @mostajs/replicator.
Multiple simultaneous connections
import { createIsolatedDialect, registerNamedConnection, getNamedConnection } from '@mostajs/orm'
const oracle = await createIsolatedDialect({ dialect: 'oracle', uri: '...' }, [UserSchema])
const mongo = await createIsolatedDialect({ dialect: 'mongodb', uri: '...' }, [AuditLogSchema])
registerNamedConnection('audit', mongo)
// Later, anywhere in the codebase :
const conn = getNamedConnection('audit')Ecosystem
| Package | Description |
|---|---|
| @mostajs/orm-bridge | Keep your Prisma code, run it on any of the 13 databases (createPrismaLikeDb() is a drop-in replacement for new PrismaClient()). |
| @mostajs/orm-cli | npx @mostajs/orm-cli โ interactive CLI : convert schemas, init databases, scaffold services, replicator + monitor, seeding, bootstrap Prisma migration. |
| @mostajs/orm-adapter | Convert Prisma / JSON Schema / OpenAPI / native .mjs to EntitySchema[] (bidirectional). |
| @mostajs/replicator | Cross-dialect replication : CQRS master/slave, CDC rules (snapshot + incremental), wildcard *, failover (promoteToMaster). As of @mostajs/orm v1.13, Mongo FK columns accept UUID strings coming from SQL dialects (populate falls back to { id: uuid } lookup). |
| @mostajs/orm-copy-data | Cross-dialect data copy : 1 source (DB / CSV / JSON / SQL dump) โ N destinations. Backup, migration, seeding. CLI (mostajs-copy) + API. Cron-ready. |
| @mostajs/replica-monitor | Live web dashboard โ replicas status, CDC stats, activity stream. Zero DB connections (reads tree + stats files). |
| @mostajs/media | Screen capture + video editor (split, speed, stickers, subtitles) + server-side ffmpeg export + project persistence (ORM + SQLite). |
| @mostajs/config | Env loader with MOSTA_ENV profile cascade (Spring-Boot-style). Used by orm/auth/payment/music. |
Design inspirations
@mostajs/orm draws from three decades of mature ORM engineering in the
Java ecosystem, adapted to the TypeScript / Node.js runtime :
| Borrowed concept | Source | @mostajs/orm equivalent |
|---|---|---|
SessionFactory / EntityManagerFactory |
Hibernate ยท JPA | getDialect() returning a cached singleton |
| Entity metadata (annotations / XML) | Hibernate, JPA @Entity |
EntitySchema โ declarative TypeScript schema |
@OneToMany / @ManyToOne / @OneToOne / @ManyToMany |
JPA | relations: { ..., type: 'one-to-many' | ... } |
@JoinColumn, @JoinTable |
JPA | joinColumn, through |
CascadeType / FetchType |
JPA | cascade, fetch in RelationDef |
Cascade types (PERSIST, REMOVE, ALL) |
JPA | cascade: ['persist', 'remove', 'all'] |
Schema-generation strategies (validate, update, create, create-drop) |
Hibernate hibernate.hbm2ddl.auto |
DB_SCHEMA_STRATEGY (same names, same semantics) |
| Show-SQL / format-SQL / highlight-SQL | Hibernate (hibernate.show_sql, hibernate.format_sql) |
DB_SHOW_SQL, DB_FORMAT_SQL, DB_HIGHLIGHT_SQL |
SAVEPOINT for nested transactions |
SQL standard, JPA spec | beginTx() inside beginTx() emits SAVEPOINT |
| Repository pattern | Spring Data | BaseRepository<T> with typed CRUD |
| Profile-based configuration | Spring Boot profiles (spring.profiles.active=test) |
MOSTA_ENV=TEST + TEST_KEY=value cascade (via @mostajs/config) |
| Environment-aware externalized config | Spring Boot application-${profile}.properties |
One .env with ${PROFILE}_${KEY} overrides |
Why borrow from the Java ecosystem ?
Hibernate (2001), JPA (2006, JSR 220), Spring Data (2008), Spring Boot (2014)
have collectively survived two decades of production workloads. Their
vocabulary and semantics are industry defaults : developers who have
worked with any of them recognize @OneToMany, CascadeType.ALL,
spring.profiles.active, hibernate.hbm2ddl.auto=update, SAVEPOINT,
etc. immediately. Reusing those names in @mostajs/orm cuts the learning
curve and avoids inventing a parallel dialect.
Further reading :
- Hibernate ORM โ https://hibernate.org/orm/documentation/
- Jakarta Persistence (JPA) โ https://jakarta.ee/specifications/persistence/
- Spring Framework โ https://spring.io/projects/spring-framework
- Spring Data โ https://spring.io/projects/spring-data
- Spring Boot profiles โ https://docs.spring.io/spring-boot/reference/features/profiles.html
- Spring Boot externalized configuration โ https://docs.spring.io/spring-boot/reference/features/external-config.html
License
AGPL-3.0-or-later + commercial license available.
For closed-source commercial use : drmdh@msn.com
Author
Dr Hamid MADANI drmdh@msn.com