npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2024 – Pkg Stats / Ryan Hefner

@woofjs/data

v0.4.5

Published

Data models, collections and validation for dogs. πŸ•

Downloads

22

Readme

πŸ•πŸ’Ύ @woofjs/data

Data models, collections and validation for dogs. πŸ•

Modern apps may have many sources of data, but you still need a single source of truth. In @woofjs/data, models ensure the truth that your data is what you expect it to be, while collections ensure that only one copy of a given record exists at once in that collection.

Models

Models ensure that your data is structured how you expect by enforcing a schema that you define. Model instances (called 'records') are uniquely identified by the value of their key.

import { makeModel, v } from "@woofjs/data";

const User = makeModel({
  key: "id",

  schema: v
    .object({
      id: v.number(),
      name: v.shape({
        family: v.string().optional(),
        given: v.string(),
        format: v.oneOf("family-given", "given-family").optional(),
      }),
      status: v.oneOf("offline", "online"),
      createdAt: v.string().isoDate(),
    })
    .strict(),
});

Validating objects

Models can validate plain objects to determine if they match the model's schema.

const data = {
  id: 1,
  name: "Bob Jones",
  createdAt: "yesterday",
};

const result = User.validate(data);

// result:
{
  key: undefined,
  valid: false,
  errors: [
    {
      path: ["name"],
      message: "expected an object; received a string",
      received: "Bob Jones"
    },
    {
      path: ["status"],
      message: "expected one of: 'offline', 'online'; received undefined",
      received: undefined
    }
    {
      path: ["createdAt"],
      message: "string does not match expected pattern",
      received: "yesterday"
    },
  ]
}

Subscribing to changes

Records are observable, meaning you can .subscribe to them to receive new values when the data they hold has changed.

const user = new User(data);

const subscription = user.subscribe((latest) => {
  console.log(`Hello ${latest.name.given}!`);
});

user.name.given = "Jimothy"; // Observer receives the data with this new name.

// "Hello Jimothy!"

// Stop receiving changes
subscription.unsubscribe();

Collections

Collections group records that conform to a model's schema. Records are identified by their key, so only one copy of a given record can exist in a collection at one time.

import { collectionOf } from "@woofjs/data";

const Users = collectionOf(User);

Adding and removing records

Collections have three methods to modify their collected records; set, delete and clear.

// A User instance.
const user = new User({
  id: 1,
  name: {
    family: "Jones",
    given: "Bob",
    format: "given-family",
  },
  status: "online",
  createdAt: new Date().toISOString(),
});

await Users.set(user);

await Users.delete(user);

// Remove all records.
await Users.clear();

The set and delete methods can take one or more objects, and delete can also take IDs.

await Users.set(user1, user2, user3);

await Users.delete(user1, 123, user3);

Updating records

Model IDs in a collection are unique, so if you want to update an existing record you just set another object with the same ID.

Querying records

// Returns the first record where the function returns true.
const user = await Users.find((user) => {
  return user.id === 123;
});

// Get one record by ID (shorthand).
const user = await Users.find(123);

// Get all records where the function returns true.
const onlineUsers = await Users.filter((user) => {
  return user.status === "online";
});

find and filter return observables, so if you want to subscribe to a live query instead of getting a value only once, you can call .subscribe.

const subscription = Users.filter((user) => user.status === "online").subscribe(
  (results) => {
    // Gets the list of online users whenever the collection changes.
  }
);

const subscription = Users.find(123).subscribe((user) => {
  // Gets the latest result whenever user 123 is updated.
});

// Unsubscribe to stop receiving updates.
subscription.unsubscribe();

Subscribing to collection changes

Collections emit events when their data changes. Each callback receives an array of the affected records.

const cancel = Users.on("add", (users) => {
  // Do something with the new records.
});

const cancel = Posts.on("update", (users) => {
  // Do something with the updated records.
});

const cancel = Users.on("delete", (users) => {
  // Do something with the removed records.
});

// Cancel to stop listening for changes.
cancel();

Sorting collections

Collections can be sorted so their records always appear in a certain order when filtered or iterated through. The sortBy option can be a string, object or function. All three ways to define it are outlined below.

const Users = collectionOf(User, {
  // Sort by 'createdAt' ascending
  sortBy: "createdAt",

  // Sort by 'createdAt' descending
  sortBy: {
    key: "createdAt",
    descending: true,
  },

  // Or pass a sort function directly that takes two records.
  sortBy: (a, b) => {
    return a.createdAt < b.createdAt ? -1 : 1;
  },
});