Skip to content

Recipes

These build on the case data from Filtering Data.

Turn a per-role glob map into a reusable projection helper. Each role’s list is a glob list:

cases/api/field-globs.json
{
"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 stripped
project(user, 'guest'); // only id, name, profile.bio, profile.avatar
project(user, 'nope'); // falls back to guest

filter() returns a fresh object, so the original record is safe to reuse across requests.

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;

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" } } } }

Form fields named with notation (user.name, user.roles[0]) assemble directly via merge():

const form = {
'user.name': 'Jane',
'user.email': '[email protected]',
'user.roles[0]': 'editor'
};
Notation.create({}).merge(form).value;
// » { user: { name: "Jane", email: "[email protected]", roles: ["editor"] } }

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