Writing Data with Mutators

Zero generates basic CRUD mutators for every table you sync. Mutators are available at zero.mutate.<tablename>:

const z = new Zero(...);
z.mutate.user.insert({
	id: nanoid(),
	username: 'abby',
	language: 'en-us',
});
🤔Note

Insert

Create new records with insert:

z.mutate.user.insert({
  id: nanoid(),
  username: 'sam',
  language: 'js',
});

Optional fields can be set to null to explicitly set the new field to null. They can also be set to undefined to take the default value (which is often null but can also be some generated value server-side).

// schema.ts
import {createTableSchema} from '@rocicorp/zero';

const userSchema = createTableSchema({
  tableName: 'user',
  columns: {
    id: {type: 'string'},
    name: {type: 'string'},
    language: {type: 'string', optional: true},
  },
  primaryKey: ['id'],
  relationships: {},
});

// app.tsx

// Sets nickname to `null` specifically
z.mutate.user.insert({
  id: nanoid(),
  username: 'sam',
  language: null,
});

// Sets nickname to the default server-side value. Could be null, or some
// generated or constant default value too.
z.mutate.user.insert({
  id: nanoid(),
  username: 'sam',
});

// Same as above
z.mutate.user.insert({
  id: nanoid(),
  username: 'sam',
  language: undefined,
});

Upsert

Create new records or update existing ones with upsert:

z.mutate.user.upsert({
  id: samID,
  username: 'sam',
  language: 'ts',
});

upsert supports the same null / undefined semantics for optional fields that insert does (see above).

Update

Update an existing record. Does nothing if the specified record (by PK) does not exist.

You can pass a partial, leaving fields out that you don’t want to change. For example here we leave the username the same:

// Leaves username field to previous value.
z.mutate.user.update({
  id: samID,
  language: 'golang',
});

// Same as above
z.mutate.user.update({
  id: samID,
  username: undefined,
  language: 'haskell',
});

// Reset language field to `null`
z.mutate.user.update({
  id: samID,
  language: null,
});

Delete

Delete an existing record. Does nothing if specified record does not exist.

z.mutate.user.delete({
  id: samID,
});

Batch Mutate

You can do multiple CRUD mutates in a single batch. If any of the mutations fails, all will. They also all appear together atomically in a single transaction to other clients.

z.mutateBatch(async tx => {
  const samID = nanoid();
  tx.user.create({
    id: samID,
    username: 'sam',
  });

  const langID = nanoid();
  tx.language.insert({
    id: langID,
    userID: samID,
    name: 'js',
  });
});