Do Web SQL ao SQLite Wasm: guia de migração do banco de dados

Com o SQLite Wasm com suporte do sistema de arquivos privado de origem, há um substituto versátil para a tecnologia de banco de dados Web SQL descontinuada. Este artigo é um guia para migrar seus dados do Web SQL para o SQLite Wasm.

Plano de fundo obrigatório

A postagem Como descontinuar e remover o Web SQL anunciou a descontinuação da tecnologia de banco de dados Web SQL. Embora a tecnologia em si possa estar descontinuada, os casos de uso abordados por ela não estão. Por isso, a postagem de acompanhamento SQLite Wasm no navegador com suporte do Origin Private File System descreve um conjunto substituto de tecnologias com base no banco de dados SQLite, compilado para Web Assembly (Wasm) e com suporte do Origin Private File System. Para fechar o ciclo, este artigo mostra como migrar bancos de dados do Web SQL para o SQLite Wasm.

Como migrar seus bancos de dados

As quatro etapas a seguir demonstram a ideia conceitual de migrar um banco de dados Web SQL para o SQLite Wasm, com o banco de dados SQLite apoiado pelo sistema de arquivos particular da origem. Isso pode servir como base para seu próprio código personalizado de acordo com suas necessidades de migração do Web SQL.

Os bancos de dados Web SQL a serem migrados

A premissa básica deste guia de migração é que você tem um ou vários bancos de dados Web SQL que contêm dados relevantes para seu app. Na captura de tela abaixo, você vê um exemplo de banco de dados chamado mydatabase com uma tabela de tempestades que mapeia estados de espírito para gravidades. Com o Chrome DevTools, é possível ver bancos de dados Web SQL para depuração, como mostrado na captura de tela a seguir.

Um banco de dados Web SQL inspecionado no DevTools do Chrome. O banco de dados é chamado de mydatabase e hospeda uma tabela com três colunas: ID da linha, humor e gravidade. Há três linhas de dados de amostra.

Como traduzir o banco de dados Web SQL para instruções SQL

Para migrar os dados de maneira transparente para o usuário, ou seja, sem exigir que ele execute nenhuma das etapas de migração por conta própria, as partes de dados no banco de dados precisam ser traduzidas de volta para as instruções SQL originais que os criaram. Esse desafio já surgiu antes, e o script de migração usado neste artigo (mywebsqldump.js) é baseado em uma biblioteca da comunidade chamada websqldump.js, com alguns pequenos ajustes. O exemplo de código a seguir mostra o código necessário para traduzir o banco de dados Web SQL mydatabase em um conjunto de instruções SQL.

websqldump.export({
  database: 'mydatabase',
  version: '1.0',
  success: function(sql) {
    // The SQL statements.
  },
  error: function(err) {
    // Handle the error.
  }
});

A execução desse código resulta na string de instruções SQL abaixo.

CREATE TABLE IF NOT EXISTS rainstorms (mood text, severity int);
INSERT INTO rainstorms(mood,severity) VALUES ('somber','6');
INSERT INTO rainstorms(mood,severity) VALUES ('rainy','8');
INSERT INTO rainstorms(mood,severity) VALUES ('stormy','2');

Importar os dados para o SQLite Wasm

Agora basta executar esses comandos SQL no contexto do SQLite Wasm. Para todos os detalhes sobre a configuração do SQLite Wasm, consulte o artigo SQLite Wasm no navegador com suporte do Origin Private File System (link em inglês), mas o resumo está abaixo. Lembre-se de que esse código precisa ser executado em um worker (que a biblioteca cria automaticamente para você) com os cabeçalhos HTTP obrigatórios definidos corretamente. É possível instalar o pacote @sqlite.org/sqlite-wasm do npm.

import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';

(async () => {
  try {
    const promiser = await new Promise((resolve) => {
      const _promiser = sqlite3Worker1Promiser({
        onready: () => {
          resolve(_promiser);
        },
      });
    });

    let response;

    response = await promiser('open', {
      filename: 'file:mydatabase.db?vfs=opfs',
    });
    const { dbId } = response;

    const sql = `
      CREATE TABLE IF NOT EXISTS rainstorms (mood text, severity int);
      INSERT INTO rainstorms(mood,severity) VALUES ('somber','6');
      INSERT INTO rainstorms(mood,severity) VALUES ('rainy','8');
      INSERT INTO rainstorms(mood,severity) VALUES ('stormy','2');`
    await promiser('exec', { dbId, sql });

    await promiser('close', { dbId });
  } catch (err) {
    if (!(err instanceof Error)) {
      err = new Error(err.result.message);
    }
    console.error(err.name, err.message);
  }
})();

Depois de executar esse código, inspecione o arquivo de banco de dados importado com a extensão OPFS Explorer do Chrome DevTools. Agora há dois arquivos, um com o banco de dados real e outro com informações de registro em diário. Esses dois arquivos ficam no sistema de arquivos privado da origem. Portanto, é necessário usar a extensão OPFS Explorer para vê-los.

Inspeção do sistema de arquivos privados de origem com o OPFS Explorer Chrome DevTools. Há dois arquivos: um chamado mydatabase.db e outro chamado mydatabase.db-journal.

Para verificar se os dados importados são os mesmos que os dados iniciais do Web SQL, clique no arquivo mydatabase.db. A extensão OPFS Explorer vai mostrar uma caixa de diálogo Salvar arquivo para que você possa salvar o arquivo no sistema de arquivos visível para o usuário. Com o arquivo de banco de dados salvo, use um app visualizador de SQLite para analisar os dados. O Project Fugu API Showcase apresenta vários apps para trabalhar com SQLite no navegador. Por exemplo, o Sqlime: SQLite Playground permite abrir um arquivo de banco de dados SQLite do disco rígido e executar consultas nele. Como você pode ver na captura de tela abaixo, a tabela "rainstorm" foi importada corretamente para o SQLite.

Analisando o arquivo mydatabase.db na ferramenta Sqlime SQLite Playground. O app é mostrado com a consulta SQL "select star from rainstorms limit 10" em execução, resultando nas três linhas dos dados de amostra iniciais do Web SQL.

Liberar armazenamento do Web SQL

Embora seja (talvez surpreendentemente) impossível excluir um banco de dados Web SQL, você ainda pode liberar algum armazenamento descartando as tabelas Web SQL obsoletas depois de migrar os dados para o SQLite Wasm. Para listar todas as tabelas em um banco de dados Web SQL e descartá-las usando JavaScript, use o código no snippet a seguir:

const dropAllTables = () => {
  try {
    db.transaction(function (tx) {
      tx.executeSql(
        "SELECT name FROM sqlite_master WHERE type='table' AND name !='__WebKitDatabaseInfoTable__'",
        [],
        function (tx, result) {
          const len = result.rows.length;
          const tableNames = [];
          for (let i = 0; i < len; i++) {
            const tableName = result.rows.item(i).name;
            tableNames.push(`'${tableName}'`);
            db.transaction(function (tx) {
              tx.executeSql('DROP TABLE ' + tableName);
            });
          }
          console.log(`Dropped table${tableNames.length > 1 ? 's' : ''}: ${tableNames.join(', ')}.`);
        }
      );
    });
  } catch (err) {
    console.error(err.name, err.message);
  }
};

Como trabalhar com os dados após a migração

Depois de migrar os dados, trabalhe com eles conforme descrito neste exemplo de código para iniciantes. Consulte a referência da API SQLite Wasm para mais detalhes. Vale lembrar que você precisa acessar o SQLite Wasm de um worker se usar o sistema de arquivos privado de origem como back-end de armazenamento.

Conclusões

É possível migrar seus bancos de dados Web SQL para o SQLite Wasm com suporte do sistema de arquivos privado de origem de maneira transparente para os usuários. Eles não vão perceber que os dados agora estão hospedados no sistema de arquivos privado de origem em um banco de dados SQLite, e não mais no Web SQL. No geral, migrar do Web SQL para o SQLite é uma etapa necessária para desenvolvedores da Web que querem garantir a estabilidade e a escalonabilidade de longo prazo dos aplicativos. Embora o processo exija algum esforço inicial, os benefícios de uma solução de banco de dados mais robusta, flexível e, acima de tudo, preparada para o futuro, fazem valer a pena o investimento.