Skip to Content
PortuguêsDocumentação JumentixPacotes@jumentix/canaGuia de usoSchema e chaves

Schema e chaves

O schema do Cana é dado puro. O IndexedDB aplica mudanças de schema somente quando a versão do banco aumenta, então versionamento faz parte do contrato da aplicação.

Schema versionado

import { createClient, validateSchema, type CanaSchema } from '@jumentix/cana';

const schemaV1: CanaSchema = {
  version: 1,
  stores: [
    {
      name: 'categories',
      keyPath: 'id',
      indexes: [{ name: 'byName', keyPath: 'name', unique: true }]
    }
  ]
};

const schemaV2: CanaSchema = {
  version: 2,
  stores: [
    {
      name: 'categories',
      keyPath: 'id',
      indexes: [{ name: 'byName', keyPath: 'name', unique: true }]
    },
    {
      name: 'tasks',
      keyPath: 'id',
      indexes: [
        { name: 'byCategory', keyPath: 'categoryId' },
        { name: 'byUpdatedAt', keyPath: 'updatedAt' }
      ]
    }
  ]
};

const problems = validateSchema(schemaV2);
if (problems.length > 0) {
  throw new Error(problems.join('\n'));
}

const firstClient = createClient({ name: 'tasks-schema-demo', schema: schemaV1 });
await firstClient.open();
await firstClient.table('categories').put({ id: 'work', name: 'Work' });
await firstClient.close();

const upgradedClient = createClient({ name: 'tasks-schema-demo', schema: schemaV2 });
await upgradedClient.open();
await upgradedClient.table('tasks').put({
  id: 'task-1',
  title: 'Created after schema upgrade',
  categoryId: 'work',
  completed: false,
  priority: 'medium',
  createdAt: Date.now(),
  updatedAt: Date.now()
});

Regras de upgrade

MudançaComportamento do Cana
Adicionar storeAplicado na próxima versão maior.
Adicionar índiceAplicado na próxima versão maior.
Remover uma store do objeto de schemaA store antiga permanece. O Cana evita perda acidental de dados.
Alterar definição de índice existenteO índice antigo permanece. Use um novo nome de índice para reconstruir de propósito.
Abrir versão antiga sobre dados novosRecusado com UpgradeFailed.

Estratégias de chave

const inboundSchema: CanaSchema = {
  version: 1,
  stores: [{ name: 'tasks', keyPath: 'id' }]
};

const generatedInboundSchema: CanaSchema = {
  version: 1,
  stores: [{ name: 'tasks', keyPath: 'id', autoIncrement: true }]
};

const outboundSchema: CanaSchema = {
  version: 1,
  stores: [{ name: 'cache' }]
};

Use chaves inbound para registros de aplicação como categories e tasks. Use chaves outbound para entradas de cache em que a chave é metadado fora do objeto armazenado.

await client.table('tasks').put({
  id: 'task-1',
  title: 'Stable inbound key',
  categoryId: 'work',
  completed: false,
  priority: 'medium',
  createdAt: 1,
  updatedAt: 1
});

await client.table('cache').put(
  { body: '<html>cached response</html>', savedAt: Date.now() },
  'https://example.com/tasks'
);

Execute aqui

Upgrade de schema

Comece com Category, depois suba a versao e adicione a tabela Task.

const v1 = cana.createClient({
  name: dbName,
  schema: {
    version: 1,
    stores: [{ name: 'categories', keyPath: 'id' }]
  }
});
await v1.open();
await v1.table('categories').add({ id: 'work', name: 'Work' });
await v1.close();

const v2 = 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 v2.open();
await v2.table('tasks').add({
  id: 'task-1',
  title: 'Created after upgrade',
  categoryId: 'work',
  completed: false,
  priority: 'medium',
  createdAt: Date.now(),
  updatedAt: Date.now()
});
return {
  categories: await v2.table('categories').query(),
  tasks: await v2.table('tasks').query()
};

Chaves

Use ids estaveis nos registros Category e 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: 'docs',
  name: 'Docs',
  color: '#0f766e',
  createdAt: 1,
  updatedAt: 1
});
await client.table('tasks').add({
  id: 'docs-1',
  title: 'Document stable keys',
  categoryId: 'docs',
  completed: false,
  priority: 'medium',
  createdAt: 2,
  updatedAt: 2
});
return {
  categoryKey: 'docs',
  taskKey: 'docs-1',
  task: await client.table('tasks').get('docs-1')
};

Próximo

Continue em leitura, escrita e operações em lote.