Skip to Content
Jumentix DocsPackages@jumentix/canaUsage guideReading, writing and bulk operations

Reading, writing and bulk operations

Use the single-record methods for UI actions and bulk methods for setup, imports, sync batches and migrations.

Single-record writes

type Task = {
  id: string;
  title: string;
  categoryId: string;
  completed: boolean;
  priority: 'low' | 'medium' | 'high';
  createdAt: number;
  updatedAt: number;
};

const tasks = client.table<Task>('tasks');

await tasks.add({
  id: 'task-1',
  title: 'Draft the tutorial',
  categoryId: 'work',
  completed: false,
  priority: 'high',
  createdAt: 1,
  updatedAt: 1
});

await tasks.update('task-1', {
  completed: true,
  updatedAt: 2
});

const afterUpdate = await tasks.get('task-1');
await tasks.delete('task-1');
const afterDelete = await tasks.get('task-1');

console.log({ afterUpdate, afterDelete });

Method choice

MethodExisting keyMissing keyBest use
add(record)Fails with ConstraintViolation.Inserts.Create-only actions.
put(record)Replaces the whole record.Inserts.Upsert from sync/import.
update(key, changes)Merges fields.Fails with NotFound.UI edits that must not resurrect deleted rows.
delete(key)Deletes.No stored record remains.Remove actions.
clear()Removes every record in the store.Store becomes empty.Reset/import flows.

Bulk writes

type Category = {
  id: string;
  name: string;
  color: string;
  createdAt: number;
  updatedAt: number;
};

const now = Date.now();
const categories = client.table<Category>('categories');
const tasks = client.table<Task>('tasks');

await categories.bulkAdd([
  { id: 'work', name: 'Work', color: '#2563eb', createdAt: now, updatedAt: now },
  { id: 'home', name: 'Home', color: '#16a34a', createdAt: now, updatedAt: now }
]);

const insertedKeys = await tasks.bulkAdd([
  {
    id: 'task-1',
    title: 'Write the guide',
    categoryId: 'work',
    completed: false,
    priority: 'high',
    createdAt: now,
    updatedAt: now
  },
  {
    id: 'task-2',
    title: 'Review examples',
    categoryId: 'home',
    completed: false,
    priority: 'medium',
    createdAt: now,
    updatedAt: now + 1
  }
]);

console.log({ insertedKeys });

bulkAdd() is still one IndexedDB transaction. If a record violates a constraint, the error names the store and the operation so the caller can report the batch failure without guessing.

Run it here

CRUD

Create, read, update and delete one Task.

const client = cana.createClient({
  name: dbName,
  schema: {
  version: 1,
  stores: [
    { name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
    {
      name: 'tasks',
      keyPath: 'id',
      indexes: [
        { name: 'byCategory', keyPath: 'categoryId' },
        { name: 'byCompleted', keyPath: 'completed' },
        { name: 'byUpdatedAt', keyPath: 'updatedAt' }
      ]
    }
  ]
}
});
await client.open();
await client.table('categories').add({ id: 'work', name: 'Work', color: '#2563eb' });
const tasks = client.table('tasks');
await tasks.add({
  id: 'task-1',
  title: 'Draft the tutorial',
  categoryId: 'work',
  completed: false,
  priority: 'high',
  createdAt: 1,
  updatedAt: 1
});
await tasks.update('task-1', { completed: true, updatedAt: 2 });
const afterUpdate = await tasks.get('task-1');
await tasks.delete('task-1');
return { afterUpdate, afterDelete: await tasks.get('task-1') };

Bulk operations

Seed Category and Task records with bulk operations.

const client = cana.createClient({
  name: dbName,
  schema: {
  version: 1,
  stores: [
    { name: 'categories', keyPath: 'id', indexes: [{ name: 'byName', keyPath: 'name', unique: true }] },
    {
      name: 'tasks',
      keyPath: 'id',
      indexes: [
        { name: 'byCategory', keyPath: 'categoryId' },
        { name: 'byCompleted', keyPath: 'completed' },
        { name: 'byUpdatedAt', keyPath: 'updatedAt' }
      ]
    }
  ]
}
});
await client.open();
const now = Date.now();
await client.table('categories').bulkAdd([
  { id: 'work', name: 'Work', color: '#2563eb', createdAt: now, updatedAt: now },
  { id: 'home', name: 'Home', color: '#16a34a', createdAt: now, updatedAt: now }
]);
await client.table('tasks').bulkAdd([
  {
    id: 'task-1',
    title: 'Write the Cana tutorial',
    categoryId: 'work',
    completed: false,
    priority: 'high',
    createdAt: now,
    updatedAt: now
  },
  {
    id: 'task-2',
    title: 'Review category filters',
    categoryId: 'home',
    completed: true,
    priority: 'medium',
    createdAt: now,
    updatedAt: now + 1
  }
]);
const put = await client.table('tasks').bulkPut([
  {
    id: 'task-2',
    title: 'Review category filters',
    categoryId: 'home',
    completed: false,
    priority: 'high',
    createdAt: Date.now(),
    updatedAt: Date.now()
  },
  {
    id: 'task-3',
    title: 'Publish the example app',
    categoryId: 'work',
    completed: false,
    priority: 'medium',
    createdAt: Date.now(),
    updatedAt: Date.now()
  }
]);
return {
  put,
  categories: await client.table('categories').query({ index: 'byName' }),
  tasks: await client.table('tasks').query({ index: 'byUpdatedAt' })
};

Next

Continue to querying and plans.