DB.js

O DB.js é uma biblioteca JavaScript poderosa e eficiente que simplifica a manipulação de dados JSON. Com funcionalidades semelhantes às operações de um ORM (Mapeamento Objeto-Relacional) .

O DB.js é uma biblioteca JavaScript compacta, simples e poderosa projetada para facilitar a geração de consultas em arrays de objetos JavaScript. Inspirado na classe DB do Laravel, o DB.js adota estruturas semelhantes, conforme desejado pelo seu desenvolvedor.

Com o DB.js, você não precisa mais se preocupar com estruturas de dados complexas para renderizar tabelas no frontend. Ele oferece métodos para selecionar, filtrar, atualizar, apagar, agrupar, ordenar e muito mais, simplificando significativamente essas operações.

Os requisitos mínimos para utilizar o DB.js em seu projeto incluem ter o NPM instalado em sua máquina para baixar o DB.js como dependência, além de possuir conhecimentos básicos em JavaScript. O repositório do projeto está aberto para sua contribuição.

Para instalar o DB.js, use o seguinte comando:

npm i pl-db-js

Exemplo de uso:

import { db } from 'pl-db-js';
 
const peoples = [
 { name: "carla", idade: 27 },
 { name: "Paulo", idade: 18 },
 { name: "Leonardo", idade: 15 },
 { name: "Yago", idade: 41 },
 { name: "Maria", idade: 19 },
 { name: "Priscila", idade: 10 },
 { name: "Fernanda", idade: 20 }
];
  
 
let table = db.table(peoples)
.select(['name','idade'])
.where('idade','>=',22)
.all();

console.table(table)

Repositório no GitHub: https://github.com/paulo-leo/db

Conceitos fundamentais

Para utilizar a biblioteca DB.js, é necessário compreender alguns conceitos fundamentais, como a 'instância de dados', que basicamente consiste em um array de objetos ou uma lista no formato de array do JavaScript. Cada vez que o método table é invocado, uma nova instância de dados é manipulada. Essa instância pode ser modificada antes do seu retorno. O retorno da instância é sempre uma nova versão, possibilitando que o programador passe uma instância para outra chamada do método table, conforme a necessidade.

No contexto de DB.js, os 'filtros' representam critérios para especificar como desejamos que a nova instância de dados seja retornada. Além dos filtros, há as 'seleções', que permitem escolher colunas específicas, similar ao SELECT no SQL. Também há a 'adição de colunas', utilizada para modificar a estrutura da instância de dados, e as 'funções de retorno', que são métodos capazes de renderizar a instância de dados de acordo com os filtros aplicados, ordenações, agrupamentos, entre outros.

A proposta do DB.js é simplificar a manipulação de arquivos do tipo JSON de maneira fácil e eficiente, eliminando a necessidade de escrever muitas estruturas de dados para realizar manipulações complexas em arrays de objetos. A ideia é manipular os dados como se estivesse utilizando um ORM (Mapeamento Objeto-Relacional), aplicando o mesmo conceito de manipulação de dados utilizado no SQL.

Iniciando a manipulação de dados

Para manipular seus dados usando o DB.js, é necessário utilizar o método 'table'. Ao utilizá-lo, é preciso passar um array indexado ou associativo. Se o DB receber um array indexado, ele converterá esse formato em um array de objetos, atribuindo campos 'CodeKeyAutoDB' e 'value' a cada registro.

O DB.js criará automaticamente um identificador ('id') para cada registro.

const data = [
  { name: 'Exemplo 1', value: 100 },
  { name: 'Exemplo 2', value: 200 },
  // ...
];

let table = db.table(data);

Importante: Ao fornecer um array de objetos ou uma lista/array com elementos do tipo string, o DB.js realizará a conversão automaticamente. Isso significa que é viável fornecer campos provenientes de um banco de dados MySQL que sejam do tipo JSON, armazenados como string. O DB.js executará essa conversão automaticamente, tornando esse tipo de dado completamente válido como uma instância de dados, desde que esteja no formato de array de objetos ou array/lista.

Aviso: A partir da versão 1.3.0, a biblioteca não usará mais o ID como chave primária para gerenciar os dados. A chave agora será automaticamente criada pela biblioteca DB.js com o nome 'CodeKeyAutoDB'. Os métodos de retorno, como update, delete, only e except, não retornarão essa chave que foi criada automaticamente. No entanto, se desejar acessá-la, poderá utilizar os métodos de retorno get(), getString() e pluck(). A nova orientação é preferir o uso do método all() em vez de get(). O método all() não retorna a chave primária criada automaticamente, conforme mencionado anteriormente. Além disso, ainda é possível passar um parâmetro opcional como true, caso deseje que o retorno seja em string no método all().

Adicionando seleções

Assim como no SQL, é possível especificar as colunas desejadas para seleção utilizando o método 'select' no DB.js. Este método aceita um parâmetro, que pode ser uma string contendo os nomes das colunas separados por vírgulas ou uma lista com os nomes das colunas.

Aqui está um exemplo de como utilizar o método 'select':

const data = [
  { id: 1, name: 'Exemplo 1', value: 100, category: 'A' },
  { id: 2, name: 'Exemplo 2', value: 200, category: 'B' },
  { id: 3, name: 'Exemplo 3', value: 150, category: 'A' },
  // ...
];

let t = db.table(data);

// Selecionando colunas específicas 
//usando uma string com os nomes das colunas
t = t.select('name, value'); 
// Retorna apenas as colunas 'name' e 'value'

// Selecionando colunas específicas usando 
//uma lista com os nomes das colunas
t = t.select(['name', 'category']); 
// Retorna apenas as colunas 'name' e 'category'

Uma novidade interessante é a capacidade de atribuir um apelido (alias) para uma coluna selecionada no DB.js. Para isso, basta separar o nome da coluna desejada pelo apelido utilizando o símbolo ':'.

Aqui está um exemplo de como atribuir um apelido a uma coluna selecionada:

const data = [
  { id: 1, name: 'Exemplo 1', value: 100, category: 'A' },
  { id: 2, name: 'Exemplo 2', value: 200, category: 'B' },
  { id: 3, name: 'Exemplo 3', value: 150, category: 'A' },
  // ...
];

let t = db.table(data);

// Selecionando colunas específicas com apelidos
t = t.db.select('name:nome, value:valor'); 
// Retorna as colunas 'name' com o apelido 'nome' e 'value' com o apelido 'valor'

Além das funcionalidades anteriores, é possível atribuir valores padrões para as linhas selecionadas e até mesmo executar uma função de callback para definir esses valores. Isso é viabilizado quando o parâmetro do método 'select' é um array, sendo que cada coluna também é representada como um array. No array da coluna, o primeiro índice representa o nome da coluna e seu apelido (se houver), enquanto o segundo índice é o valor padrão da coluna ou a função de callback que retornará o valor da coluna.

Aqui está um exemplo demonstrando como definir valores padrões ou usar funções de callback para as colunas selecionadas:

const data = [
  { id: 1, name: 'Exemplo 1', value: 100, category: 'A' },
  { id: 2, name: 'Exemplo 2', value: 200, category: 'B' },
  { id: 3, name: 'Exemplo 3', value: 150, category: 'A' },
  // ...
];

t = db.table(data);

// Selecionando colunas com valores padrões ou funções de callback
t.select([
  ['name:nome', 'Nome Padrão'],
  ['value:valor', (value) => value * 2], // Função de callback para 'value',
  ['idade', (value,row) =>{ 
  return row.idade * 2 + db.table(data).count();
  }], // Função de callback para 'idade'
  ['category', 'Sem Categoria'], // Valor padrão para 'category'
]);

As possibilidades de criação são vastas. Você pode executar o DB.js dentro da seleção e invocar outros estados, permitindo até mesmo a criação de colunas de relacionamento. O limite está apenas na sua criatividade e nas necessidades específicas do projeto.

Ao explorar a capacidade de executar o DB.js dentro da seleção, é possível criar estruturas mais complexas, manipular os dados de maneira mais dinâmica e estabelecer relações entre diferentes conjuntos de dados. Essa flexibilidade oferece um vasto campo para explorar e personalizar as consultas conforme necessário.

Atenção: Apesar de o método 'select' ser encadeado, é recomendado seu uso apenas uma vez por instância de dados. Isso ocorre devido ao mapeamento comparativo que este método realiza. Utilizá-lo mais de uma vez pode resultar em travamentos no navegador devido ao custo computacional.

Se houver a necessidade de adicionar novos seletores, é possível utilizar o método encadeado 'addSelect'. O 'addSelect' pode ser chamado várias vezes, porém aceita apenas um seletor por vez. A lógica de parâmetros do 'addSelect' é a mesma do 'select', mas permite adicionar somente uma coluna por vez em vez de um array com várias colunas ou uma string.

Adicionando colunas

Para adicionar uma nova coluna ao seu array de objetos, você pode utilizar o método 'addCol' do DB.js. Esse método aceita dois parâmetros, sendo o segundo opcional. O primeiro parâmetro é o nome da coluna que você deseja adicionar, enquanto o segundo parâmetro (opcional) é o valor padrão que o campo terá.

É possível passar uma função como segundo parâmetro, permitindo a criação de subconsultas. Essa função pode receber até dois parâmetros: o primeiro são os valores da linha atual e o segundo é o array de objetos completo.

Aqui está um exemplo de uso do método 'addCol' com uma função para adicionar uma nova coluna chamada 'novaColuna' ao array de objetos:


const data = [
  { id: 1, name: 'Exemplo 1', value: 100 },
  { id: 2, name: 'Exemplo 2', value: 200 },
  // ...
];

let table = db.table(data);

 table.addCol('novaColuna', (row, fullArray) => {
  // 'row' contém os valores da linha atual
  // 'fullArray' é o array de objetos completo
  return row.value * 2; 
  // Definindo 'novaColuna' como o dobro do valor atual
});

/*Agora o array de objetos terá a nova coluna 
'novaColuna' com os valores calculados.*/

Adcionando linhas

Às vezes, pode ser necessário adicionar uma ou mais linhas a uma tabela por vários motivos, como teste de conteúdo. Com o DB.js, isso se torna simples utilizando o método 'addRow'. Este método possui dois parâmetros opcionais.

O primeiro parâmetro determina a quantidade de linhas a serem adicionadas. Por padrão, é inserida apenas uma linha. O segundo parâmetro, também opcional, é para os dados que você deseja adicionar. No caso de informar esses dados, é recomendável que todas as colunas sejam tratadas.

Se os parâmetros forem ignorados, o método fará uma cópia do objeto do primeiro índice do array e o inserirá repetidamente.

Aqui está um exemplo de uso do método 'addRow':


const data = [
  { id: 1, name: 'Exemplo 1', value: 100 },
  { id: 2, name: 'Exemplo 2', value: 200 },
  // ...
];

let table = db.table(data);

// Adicionando uma linha sem dados específicos (irá copiar o primeiro índice)
let table1 = table.addRow(); 
// Adiciona uma linha com dados copiados do primeiro índice

// Adicionando três linhas com dados específicos
let table2 = table.addRow(3, { id: 3, name: 'Novo Exemplo 1', value: 150 }); 
// Adiciona três linhas com os dados especificados

Filtrando dados

O método 'filter' do DB.js é utilizado para aplicar filtros aos dados. Os métodos que não retornam valores são encadeados, permitindo adicionar quantos filtros forem necessários. Este método aceita até três parâmetros.

O primeiro parâmetro é o nome do campo pelo qual você deseja filtrar. O segundo parâmetro é o operador a ser utilizado no filtro, enquanto o terceiro parâmetro é o valor procurado. Se você optar por ignorar o terceiro parâmetro, o filtro considerará o segundo parâmetro como o valor e automaticamente usará o operador de igualdade.

Aqui está um exemplo de uso do método 'filter':


const data = [
  { id: 1, name: 'Exemplo 1', value: 100 },
  { id: 2, name: 'Exemplo 2', value: 200 },
  { id: 3, name: 'Exemplo 3', value: 150 },
  // ...
];

let t = db.table(data);

// Aplicando um filtro simples
t = t.filter('value', '>', 100); 
// Filtra os valores maiores que 100

// Encadeando múltiplos filtros
t = t.filter('name', 'includes', 'Exemplo'); 
// Filtra os nomes que incluem 'Exemplo'
t = t.filter('id', '=', 2); // Filtra o id igual a 2

// Se ignorarmos o terceiro parâmetro, 
//ele usará automaticamente o operador de igualdade
t = t.filter('id', 3); // Filtra o id igual a 3

O método 'where' do DB.js opera de forma semelhante ao 'filter', permitindo a aplicação de múltiplos filtros. No entanto, o 'where' aceita um array de filtros para maior flexibilidade.

Ele opera basicamente como o método 'filter', mas ao invés de aceitar apenas um filtro por vez, possibilita a aplicação de vários filtros de uma vez através de um array.

Aqui está um exemplo de como usar o método 'where' com um array de filtros:

const data = [
  { id: 1, name: 'Exemplo 1', value: 100 },
  { id: 2, name: 'Exemplo 2', value: 200 },
  { id: 3, name: 'Exemplo 3', value: 150 },
  // ...
];

let t = db.table(data);

const filters = [
  ['value', '>', 100],         // Filtra os valores maiores que 100
  ['name', 'c', 'Exemplo'], // Filtra os nomes que contém 'Exemplo'
  ['id', '=', 2]               // Filtra o id igual a 2
];

t = db.where(filters);

console.log(t.get()); 
//Imprime os resultados no console

Lista de operadores de filtros possíveis:

Métodos de retorno

Até o momento, todos os métodos que exploramos são métodos de montagem, ou seja, manipulam a instância de dados a partir do método 'table'. Cada chamada do método 'table' resulta em uma nova instância de dados. No entanto, após realizar as manipulações desejadas com filtros, seletores e adições de colunas, queremos obter o retorno dos dados conforme configurado.

Para isso, dispomos de um conjunto de métodos de retorno que trazem os dados de acordo com as configurações aplicadas nos filtros, seletores e adições de colunas. Após utilizar um método de retorno, a montagem não aceitará nenhum outro método, pois concluiu seu processo e retornou os dados conforme a lógica programada.

Métodos de retorno de cálculos

No DB.js, é viável realizar cálculos em colunas específicas de maneira similar às funções do SQL, tais como sum, avg, max, count e min. Abaixo está uma lista dessas funções disponíveis

  1. sum(coluna): Calcula a soma dos valores de uma determinada coluna.

  2. avg(coluna): Calcula a média dos valores de uma determinada coluna.

  3. max(coluna): Retorna o valor máximo encontrado em uma determinada coluna.

  4. count(coluna): Conta o número total de linhas ou registros. De uma coluna, se a coluna não for informada a função irá considerar todos os índices do array de objetos.

  5. count(coluna): Conta o número de valores não nulos em uma coluna específica.

  6. min(coluna): Retorna o valor mínimo encontrado em uma determinada coluna.

  7. calc(callback) : Retorna o resultado de uma expressão matemática sobre o array de objetos filtrado.

const data = [
  { id: 1, value: 10 },
  { id: 2, value: 20 },
  { id: 3, value: 30 },
  // ...
];

let table = db.table(data);

// Exemplos de utilização das funções de cálculo
const soma = table.sum('value'); // Calcula a soma dos valores da coluna 'value'
const media = table.avg('value'); // Calcula a média dos valores da coluna 'value'
const valorMaximo = table.max('value'); // Retorna o valor máximo da coluna 'value'
const totalRegistros = table.count(); // Conta o número total de registros
const countNotNull = table.count('value'); // Conta o número de linhas não nulas
const valorMinimo = table.min('value'); // Retorna o valor mínimo da coluna 'value'
const calculo = table.calc((results)=>{
  return results.length * 10;
});

Métodos de retorno de atualização e exclusão de linhas

O DB.js disponibiliza quatro métodos para retornar uma nova estrutura da instância de dados. Esses métodos permitem realizar atualizações em colunas de linhas específicas, remover colunas e deletar linhas.

Atualização de linhas

O método 'update' permite retornar toda a instância de dados, porém, os dados que corresponderam aos filtros terão seus valores atualizados. Este método aceita um parâmetro, que é um objeto contendo o nome e os valores das colunas a serem atualizadas. Além disso, é possível passar uma função de callback para os valores que serão atualizados. Essa função pode receber até dois parâmetros: o primeiro representa o valor da linha atual e o segundo, o array de objetos.

return db.table(t)
.where('id',10)
.update(
  {
    name: 'Paulo',
    age: (row) => row.age + 1
  }
);

Deletando linhas

O método delete retorna toda a instância de dados, exceto as linhas que correspondem aos critérios do filtro. Se nenhum filtro for fornecido, nenhum dado será retornado. Essa mesma lógica se aplica ao método update. No caso do update, todos os campos seriam atualizados, a menos que um filtro seja especificado para limitar as atualizações.

return db.table(t)
.where('id',10)
.delete();

Retornando colunas especificas

Os métodos only e except são semelhantes ao get, porém com uma diferença crucial: eles permitem especificar quais colunas devem ser retornadas ou excluídas do retorno, respectivamente. O método only possibilita especificar as colunas desejadas para o retorno, enquanto o except permite omitir colunas específicas. Ambos os métodos exigem um parâmetro obrigatório que pode ser uma lista no formato de array contendo os nomes das colunas ou uma string com os nomes das colunas separados por vírgula.

const data = [
  { id: 1, name: 'Alice', age: 25, city: 'Rio de Janeiro' },
  { id: 2, name: 'Bob', age: 30, city: 'São Paulo' },
  { id: 3, name: 'Charlie', age: 28, city: 'Caxias' },
  // ... outros registros
];

let table = db.table(data);
let e = table.except('city');
let o = table.only('city');
console.log(e);
console.log('--------');
console.log(o);

Ordenação de dados.

Com o DB.js, é possível realizar operações de agrupamento, ordenação por campos específicos e até mesmo limitar a quantidade de dados retornados, em uma funcionalidade similar ao comportamento do SQL. O DB.js oferece três métodos para realizar essas operações: limit, orderBy e groupBy.

// Limita a quantidade de dados
let table1 = db.table(t).limit(3).get();

// Agrupa os dados pelo campo 'name'
let table2 = db.table(t).groupBy(['name']).get();

// Ordena os dados pelo campo 'id'
let table3 = db.table(t).orderBy(['id']).get();

Os métodos orderBy, groupBy e limit são encadeados e podem ser usados com o método get, juntamente a outros métodos de retorno. Tanto o orderBy quanto o groupBy requerem um parâmetro obrigatório, que é um array contendo o nome das colunas. Este parâmetro pode ser também uma string com os nomes das colunas separados por vírgula.

Além disso, no caso do método orderBy, é possível passar um segundo parâmetro do tipo string com o valor desc, para realizar uma ordenação descendente.

Last updated