Defining Models
A MasterRecord entity is an ES class whose fields are methods. Each method receives the schema builder db and chains a type plus modifiers. MasterRecord reads these definitions to create tables, generate migrations, and track changes.
A basic entity#
// app/models/User.js
export default class User {
id(db) { db.integer().primary().auto(); }
name(db) { db.string().notNullable(); }
email(db) { db.string().notNullable().unique(); }
age(db) { db.integer(); } // nullable by default
is_active(db) { db.boolean().default(true); }
created_at(db) { db.datetime(); }
}name(db) { db.string(); }. A constructor assignment like this.name = { type: 'string' } is ignored— the builder reads the class prototype’s methods, so object-literal properties never reach the schema.Field types#
Every type below maps to a real column on all three engines. Call it as a builder method, e.g. db.datetime(). Temporal types (date/time/datetime/timestamp) are stored as TEXT on every engine for cross-engine portability — write ISO-8601 or epoch-millis strings.
| Builder | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
db.integer() | INTEGER | INT | INTEGER |
db.bigint() | BIGINT | BIGINT | INTEGER |
db.string() | VARCHAR(255) | VARCHAR(255) | TEXT |
db.text() | TEXT | TEXT | TEXT |
db.mediumtext() / longtext() | TEXT | MEDIUMTEXT / LONGTEXT | TEXT |
db.float() | REAL | FLOAT | REAL |
db.decimal() | DECIMAL | DECIMAL | REAL |
db.boolean() | BOOLEAN | TINYINT | INTEGER |
db.date() | TEXT | TEXT | TEXT |
db.time() | TEXT | TEXT | TEXT |
db.datetime() / timestamp() | TEXT | TEXT | TEXT |
db.json() | JSON | JSON | TEXT |
db.uuid() | UUID | VARCHAR(36) | TEXT |
db.binary() | BYTEA | BLOB | BLOB |
datetime, date, timestamp, float, decimal, bigint, json, uuid and binary arrived in MasterRecord 1.3.0.Modifiers#
Chain modifiers after the type to shape the column:
| Modifier | Effect |
|---|---|
.primary() | Marks the primary key (implies not-null + unique). |
.auto() | Auto-increment; the DB assigns the value on insert. |
.notNullable() | NOT NULL. (Columns are nullable by default.) |
.nullable() | Explicitly allow NULL. |
.unique() | Adds a UNIQUE constraint. |
.default(value) | Sets a default value. |
.index(name?) | Adds an index on the column. |
.set(fn) / .get(fn) | Transform values in / out of the database. See Transformers. |
.defaultSql('expr') | Database-side default expression (EF HasDefaultValueSql), e.g. CURRENT_TIMESTAMP. |
.computed('expr', { stored }) | Generated column (EF HasComputedColumnSql); never written by the ORM, read back after insert. |
.check('predicate', name?) | CHECK constraint (EF HasCheckConstraint). |
.rowVersion() | ORM-managed integer concurrency token, bumped on every UPDATE (EF IsRowVersion). |
.concurrencyToken() | App-managed token: original value added to the UPDATE/DELETE WHERE (EF IsConcurrencyToken). |
.owned(Class?) | Owned / complex value stored as JSON, hydrated into the class on read (EF OwnsOne(...).ToJson()). |
.transform({ toDatabase, fromDatabase }) | Value converter (EF HasConversion). |
.virtual() | Keep the property on the entity but emit no column. |
Inheritance (TPH), composite keys, owned types, computed columns, check constraints, indexes and concurrency tokens are covered on Advanced Modeling.
Registering models in a context#
Models become queryable by registering them in a context with this.dbset(Model). Name the file after the class (AppContext.js) so the migration CLI can resolve it.
// app/models/AppContext.js
import context from 'masterrecord/context';
import User from './User.js';
import Post from './Post.js';
class AppContext extends context {
constructor() {
super();
this.env('config/environments'); // env.<NODE_ENV>.json
this.dbset(User);
this.dbset(Post);
}
}
export default AppContext;master generate model Comment body:text creates the entity and registers the dbset.Relationships & transformers#
Navigation properties like Posts(db) { db.hasMany('Post'); } and User(db) { db.belongsTo('User'); } declare associations — covered in Relationships. To (de)serialize complex values, use .set() / .get().