@normalized-cache/core
v0.0.5
Published
A typed, normalized entity cache with valtio-powered reactivity and model relationships.
Readme
@normalized-cache/core
A typed, normalized entity cache for web apps, built on valtio for reactivity. Define models, register relationships between them, and read/write normalized data with a small, type-safe API.
Framework-agnostic. For React hooks (useModel/useModelAll), see @normalized-cache/react.
Install
npm install @normalized-cache/coreDefining models
Each model lives in its own file:
// models/UserModel.ts
import { Model } from "@normalized-cache/core";
import type { PostModelType } from "./PostModel";
export interface UserModelType {
id: string;
name: string;
email: string;
}
export interface UserRelations {
posts: PostModelType[];
}
export const UserModel = new Model<UserModelType, UserRelations>("User");// models/PostModel.ts
import { Model } from "@normalized-cache/core";
import type { UserModelType } from "./UserModel";
export interface PostModelType {
id: string;
userId: string;
title: string;
}
export interface PostRelations {
author: UserModelType | null;
}
export const PostModel = new Model<PostModelType, PostRelations>("Post");Relationships are registered separately, once all models exist:
// models/registerRelationships.ts
import { UserModel } from "./UserModel";
import { PostModel } from "./PostModel";
UserModel.hasMany(PostModel, { foreignKey: "userId", as: "posts" });
PostModel.belongsTo(UserModel, { foreignKey: "userId", as: "author" });Creating the cache
// models/cache.ts
import { NormalizedCache } from "@normalized-cache/core";
import "./registerRelationships";
import { UserModel } from "./UserModel";
import { PostModel } from "./PostModel";
export const cache = new NormalizedCache({
User: UserModel,
Post: PostModel,
});Reading and writing
cache.set("User", {
id: "u1",
name: "Ada",
email: "[email protected]",
posts: [{ id: "p1", title: "Hello world" }], // normalized into the Post table automatically
});
const user = cache.get("User", "u1");
user?.name; // "Ada"
user?.posts; // lazily-computed getter -> Post[]
const allUsers = cache.getAll("User"); // denormalized User[]
cache.delete("Post", "p1");
cache.clear(); // empties every model table
cache.dispose(); // removes all subscribers
// Write without notifying subscribers (e.g. inside a listener, to avoid loops):
cache.set("User", { id: "u1", name: "Ada Lovelace" }, { writeWithoutBroadcast: true });set accepts a single entity or an array. Partial updates merge shallowly with the existing cached entity. hasMany/hasOne children nested in a write are normalized into their own model table with the foreign key applied, and any previously-linked children missing from the new payload are removed.
License
MIT
