Recipes
These build on the case data from Filtering Data.
Project a Record for a Role
Section titled “Project a Record for a Role”Turn a per-role glob map into a reusable projection helper. Each role’s list is a glob list:
{ "guest": ["id", "name", "profile.bio", "profile.avatar"], "editor": [ "*", "!passwordHash", "!account.billing", "!posts[*].secret" ], "admin": ["*", "!passwordHash"]}import { Notation } from 'notation';import fieldGlobs from './field-globs.json' with { type: 'json' };
/** Return a copy of `record` containing only what `role` may see. */function project(record, role) { const globs = fieldGlobs[role] ?? fieldGlobs.guest; // default to least access return Notation.create(record).filter(globs).value; // filter() never mutates}
project(user, 'editor'); // billing, passwordHash, post secrets strippedproject(user, 'guest'); // only id, name, profile.bio, profile.avatarproject(user, 'nope'); // falls back to guestfilter() returns a fresh object, so the original record is safe to reuse
across requests.
Combine Two Roles’ Access
Section titled “Combine Two Roles’ Access”When a user holds multiple roles, merge their glob lists with
union() — it normalizes away redundant and
contradictory patterns:
import { NotationGlob } from 'notation';
const globs = NotationGlob.union(fieldGlobs.guest, fieldGlobs.editor);Notation.create(user).filter(globs).value;Expand a Flat Database Row
Section titled “Expand a Flat Database Row”Columns like account.billing.card.last4 rehydrate into a nested object with
expand():
const row = { id: 42, 'account.plan': 'pro', 'account.billing.card.last4': '4242'};Notation.create(row).expand().value;// » { id: 42, account: { plan: "pro", billing: { card: { last4: "4242" } } } }Build an Object from Flat Form Data
Section titled “Build an Object from Flat Form Data”Form fields named with notation (user.name, user.roles[0]) assemble directly
via merge():
const form = { 'user.name': 'Jane', 'user.roles[0]': 'editor'};Notation.create({}).merge(form).value;// » { user: { name: "Jane", email: "[email protected]", roles: ["editor"] } }Strip Fields Before Persisting
Section titled “Strip Fields Before Persisting”The inverse of projection — pull sensitive fields out with
separate(), keeping both halves:
const secrets = Notation.create(user).separate(['passwordHash', 'account.billing']);// `user` no longer has those; `secrets` holds them