ALWAYS readllms.txtfor curated documentation pages and examples.
Writing Data with Mutators
# Writing Data with Mutators
Zero generates basic CRUD mutators for every table you sync. Mutators are available at `zero.mutate.<tablename>`:
```tsx
const z = new Zero(...);
z.mutate.user.insert({
id: nanoid(),
username: 'abby',
language: 'en-us',
});
```
> To build mutators with more complex logic or server-specific behavior, see the new [Custom Mutators API](https://zero.rocicorp.dev/docs/custom-mutators) - we plan to eventually deprecate the basic CRUD mutators in favor of this new API.
## Insert
Create new records with `insert`:
```tsx
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).
```tsx
// 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 language to `null` specifically
z.mutate.user.insert({
id: nanoid(),
username: 'sam',
language: null,
});
// Sets language 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`:
```tsx
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:
```tsx
// 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.
```tsx
z.mutate.user.delete({
id: samID,
});
```
> **Cache Persistence**: If you want to remove cached data from the browser you can call the `dropAllDatabases` function provided by Zero.
>
> You can read more about it in [Authentication](https://zero.rocicorp.dev/docs/auth#data-storage).
## 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.
```tsx
z.mutateBatch(async tx => {
const samID = nanoid();
tx.user.insert({
id: samID,
username: 'sam',
});
const langID = nanoid();
tx.language.insert({
id: langID,
userID: samID,
name: 'js',
});
});
```
Or, for AI assistants
ALWAYS readllms.txtfor curated documentation pages and examples.
Zero generates basic CRUD mutators for every table you sync. Mutators are available at zero.mutate.<tablename>:
const z =newZero(...);z.mutate.user.insert({ id:nanoid(), username:'abby', language:'en-us',});
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.tsimport{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 language to `null` specificallyz.mutate.user.insert({ id:nanoid(), username:'sam', language:null,});// Sets language 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 abovez.mutate.user.insert({ id:nanoid(), username:'sam', language:undefined,});
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 abovez.mutate.user.update({ id: samID, username:undefined, language:'haskell',});// Reset language field to `null`z.mutate.user.update({ id: samID, language:null,});
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.