Database Architecture
Netpress keeps the model and query API shared while isolating SQL and MongoDB internals into dedicated runtime pieces.
Shared-First Layout
app/Models/contains application modelsdatabase/migrations/contains shared migrationsdatabase/seeders/contains shared seeders@admicaa/netpress/src/base/BaseModel.jsholds shared model behavior@admicaa/netpress/src/base/QueryBuilder.jsholds shared query state@admicaa/netpress/src/database/model-adapters/contains the SQL and Mongo model adapters@admicaa/netpress/src/database/query-builders/containsSqlQueryBuilderandMongoQueryBuilder@admicaa/netpress/src/database/query-adapters/contains driver-specific query compilation and execution@admicaa/netpress/src/database/relations/contains the SQL and Mongo pivot adapters forBelongsToMany
Driver Resolution
Each model resolves its runtime from its connection:
- If
static connectionis set, that value is used. - Otherwise the model resolves against the active app connection from
DB_CONNECTION. mysql,postgres,sqlite, andsqlnormalize to the SQL runtime.mongonormalizes to the MongoDB runtime.
One model class can stay application-facing and still resolve to the correct backend automatically.
Shared Responsibilities
Shared behavior lives in the base layer:
- mass assignment
- casts
- hooks
- serialization
- soft-delete API
- relations
- eager loading
- query state
- pagination
- chunking
- Laravel-style convenience helpers on models and builders
That means the application code does not branch on driver for normal reads and writes.
Driver-Specific Responsibilities
SQL-specific behavior:
- table introspection
- Knex query execution
- SQL full-text and LIKE compilation
- SQL pivot-table operations
Mongo-specific behavior:
- schema inference from the migration manifest
- Mongoose model compilation
- Mongo filter and aggregation compilation
- Mongo
$textand$regexquery translation - Mongo pivot-collection operations
Unified Migrations
Shared migrations live in one directory and can target the default connection or an explicit connection from the same file:
export async function up(database) {
await database.connection("mongo").createTable("users", (table) => {
table.primaryKey("id");
table.string("email", 255).trim().lowercase().notNullable().unique();
table.timestamps(true, true);
});
}
table.primaryKey("id") is the recommended cross-driver primary key helper:
- SQL uses
bigIncrements - MongoDB uses a native
ObjectId table.primaryKey("id", { mongo: "increments" })opts into numeric Mongo ids when a project needs them
Key behavior:
database.createTable(...)targets the default configured connectiondatabase.connection("mongo")ordatabase.connection("mysql")scopes to a specific connection- migration planning analyzes files first and only opens referenced connections
- the same blueprint is replayed into an in-memory manifest so Mongo models can infer schema without handwritten
static schemadefinitions
Shared Seeders
Shared seeders live in database/seeders/ and usually start from DatabaseSeeder.js:
export async function run(db) {
await db.call([
"UserSeeder",
"BookSeeder",
]);
}
db.call(...) accepts:
- seeder names
- arrays of names
- imported modules
- classes with
run() - functions
Compatibility Notes
Legacy folders are still supported as fallbacks when the shared roots are absent:
app/Models/sqlapp/Models/mongodatabase/migrations/sqldatabase/migrations/mongodatabase/seeders/sqldatabase/seeders/mongo
Legacy SQL migrations also keep working through the unified first argument, so older files that call knex.schema.createTable(...) or knex(...) still work in the common cases.