# Filtragem (SQL) ## GoogleViz O projeto utiliza a API de Visualização do Google (Google Viz) para ler e filtrar dados em massa de uma planilha do Google usando SQL. É **muito** mais rápido do que iterar nas linhas da planilha usando `SpreadsheetApp` e filtrando com Javascript/Apps Script. Quando isso foi implementado, foi obtido uma melhora na performance de 92x em relação à implementação que iterava em ranges obtidas via `SpreadsheetApp`. Isso é extremamente valioso em um ambiente restrito de recursos como o Google Apps Script (ver [problemas](#problemas)). Na escala atual da planilha, é impossível obter os dados de todos os processos sem essa técnica. A função mais importante é `filtrarGoogleViz()` definida em `filtragem.ts`. Através dela, podemos fazer buscas na planilha com SQL e iterar nestas linhas, segundo o exemplo "{ref}`exemplo-sql`". ```{code-block} ts :name: exemplo-sql :caption: Um exemplo de uso de `filtrarGoogleViz` :emphasize-lines: 6-19 export function obterEquipe( numero: number, setor: string, encarregado: string ): ColaboradorRelatorio[] { const linhasBuscadas = filtrarGoogleViz( EQUIPE, new VizSelectQueryBuilder() .or( (b) => b.equals(COLUNA_EQUIPE_STATUS, "PRESENTE"), (b) => b .notEquals(COLUNA_EQUIPE_STATUS, "PRESENTE") .notNull(COLUNA_EQUIPE_SUBSTITUICOES) ) .notNullOrEquals(COLUNA_EQUIPE_TIME, numero) .notNullOrEquals(COLUNA_EQUIPE_AREA, setor) .notNullOrEquals(COLUNA_EQUIPE_ENCARREGADO, encarregado) ); const linhas = linhasBuscadas.table?.rows?.map((linha) => linha.c); if (!linhas) return []; const valores = linhas.map((linha) => linha?.map((val) => val?.v ?? null)); return valores .map((colaborador) => { // Corpo do que fazer com esses colaboradores aqui }) .map(resolverSubstitutos); } ``` :::{warning} Atente-se às colunas sendo manipuladas nos seus dados, especialmente a **coluna final**. Em todos os casos do momento de escrita desta documentação, todos os intervalos iniciais são "A" porque os números das colunas definidos nas constantes são relativos à primeira coluna (ver {ref}`coordenadas`). A função `filtrarGoogleViz` tenta obter automaticamente a coluna final do intervalo usando o `VizSelectQueryBuilder`, mas às vezes é preciso usar colunas além das fornecidas na query SQL. Nestes casos, É preciso passar diretamente a maior coluna para `filtrarGoogleViz`. ::: ## Query Builder Para reduzir (se não eliminar) erros de digitação nas queries SQL, foi implementada uma classe `VizSelectQueryBuilder` cujo propósito é produzir o texto final que virará a a query SQL a ser enviada à API do Google Viz. Deste modo, podemos abstrair a tarefa de gerar SQL sintáticamente válido sem ter que lidar com strings grandes de difícil leitura, balanceamento de parênteses, aspas e outros caracteres de natureza similar, ou conversão para notação A1 usando `numParaCol()`. Ela funciona encadeiando uma série de filtros/_statements_ lógicos (implementados como funções) com AND. É possível, como visto anteriormente, encadear o builder recursivamente com OR. O usuário passa a `or()` uma sequência de subbuilders ou funções que produzem subbuilders que são por si também `VizSelectQueryBuilder`s, ele irá avaliar o texto destes builders e encadear o resultado final com ORs. O exemplo {ref}`exemplo-sql` produz a seguinte query: ``` Query em Equipe (A-Q): SELECT * WHERE ((E = "PRESENTE") OR (E != "PRESENTE" AND I IS NOT NULL)) AND M = 2 AND Q = "PINTURA" AND L = "JOÃO SILVA" (retornou 5 linhas) ``` A API é feita para ser flexível. Funções podem ser usadas de mais de uma maneira. Por exemplo: A função `equals()` automaticamente converte algo como `equals(COLUNA_STATUS, "Execução Concluída", "Cancelada/Tramitado")` para `("A" = "Execução Concluída" OR "A" = "Cancelada/Tramitado")`. O oposto, aplicando o [teorema de De Morgan](https://pt.wikipedia.org/wiki/Teoremas_de_De_Morgan) na expressão booleana, vale para `notEquals()`. Funções que usam colunas aceitam as coordenadas brutas (números) ou a notação A1 (strings) das colunas. :::{note} É possível usar o operador `IN` do SQL para substituir a lógica booleana na verificação de valores iguais ou não iguais. Isso fica como uma possível refatoração a ser feita futuramente. :::