MasterRecord
Field Transformers
Store complex JavaScript values in simple columns — transparently.
Transformers let a column convert values on the way in and out of the database. Use .set(fn) to transform before writing, and .get(fn) to transform after reading. Your application code works with the rich type; the database stores the simple one.
Storing arrays as JSON#
User.js
export default class User {
id(db) { db.integer().primary().auto(); }
tags(db) {
db.string()
.set((value) => (Array.isArray(value) ? JSON.stringify(value) : value))
.get((value) => (value ? JSON.parse(value) : []));
}
}
// Usage — assign and read a real array
const user = db.User.new();
user.tags = ['admin', 'moderator']; // stored as '["admin","moderator"]'
await user.save();
const loaded = await db.User.findById(user.id);
console.log(loaded.tags); // ['admin', 'moderator']Native JSON columns#
On Postgres/MySQL you can use a real json() column and still attach transformers for ergonomic (de)serialization on SQLite, where JSON is stored as TEXT:
javascript
metadata(db) {
db.json()
.set((v) => JSON.stringify(v || {}))
.get((v) => (typeof v === 'string' ? JSON.parse(v) : v));
}Mapping enums to integers#
enum.js
const ROLE = { viewer: 0, editor: 1, admin: 2 };
const NAME = ['viewer', 'editor', 'admin'];
export default class Member {
id(db) { db.integer().primary().auto(); }
role(db) {
db.integer()
.set((v) => (typeof v === 'string' ? ROLE[v] : v))
.get((v) => NAME[v]);
}
} Batch inserts apply transformers too
As of 1.2.10, both single and batch inserts run the same normalization pipeline, so
.set() transforms apply consistently whether you save one entity or many.