Skip to content

Tabelas ​

Sua automação pode guardar dados na plataforma: você declara as tabelas no código, o datallog push leva a declaração junto e a plataforma cria o que falta. Não há console de banco, string de conexão nem migration para escrever.

Precisa do pacote datallog 0.4.21 ou mais novo.

Declarar ​

python
from datallog import table, Text, Number, Date, Bool, Json

leads = table("leads", fields={
    "company": Text(),
    "stage": Text(index=True),
    "value": Number(),
    "next_action": Date(),
    "active": Bool(),
    "payload": Json(),
})

table() roda na sua máquina, valida na hora e devolve a declaração como dado puro. Declare no topo do arquivo da automação, ou num módulo que elas importem — o que importa é que a linha execute quando o código é carregado.

Os tipos ​

TipoGuardaVira, no banco
Text()texto de qualquer tamanhotext
Number()número exato, inclusive dinheironumeric
Date()data, sempre em YYYY-MM-DDdate
Bool()verdadeiro ou falsoboolean
Json()objeto ou lista inteirosjsonb

index=True cria um índice naquela coluna. Use nas que você filtra ou ordena; cada índice ocupa espaço e custa em toda escrita, então não é para todas.

Toda tabela ganha uma coluna id automática, que você não declara e não escreve.

Os nomes ​

Nome de tabela e de coluna aceita letras minúsculas, números e _, começando por letra, até 63 caracteres. São reservados id, order_by, limit, offset e columns como coluna, e tables e schema como tabela.

As chaves são em inglês de propósito: elas atravessam a rede e aparecem na tela da plataforma.

Publicar ​

bash
datallog push

A saída diz quantas tabelas achou:

Found 2 declared tables

A declaração é aditiva: tabela nova é criada, coluna nova é acrescentada, e coluna que você tirou da declaração não é apagada — o dado dela continua lá. Para remover de verdade, é pedido nosso, de propósito: push a partir de um checkout velho não pode apagar coluna.

Publicar duas vezes a mesma declaração não faz nada na segunda: o que já existe fica como está.

Dois tetos valem por push: 1599 colunas por tabela (o Postgres recusa mais de 1600, e uma é o id) e 200 tabelas por declaração.

O que a plataforma recusa, e o que você captura ​

A mesma validação roda dos dois lados — na sua máquina, para o erro apontar o seu arquivo, e no servidor, porque o que chega pela rede é o que alguém escolheu mandar. Os erros são importáveis:

python
from datallog import InvalidIdentifier, InvalidManifest, UnknownType, TableRedeclared

try:
    table("Leads!", fields={"company": Text()})
except InvalidIdentifier as erro:
    print(erro)
    # invalid table name: 'Leads!'. Use only lowercase letters, digits and _,
    # starting with a letter, up to 63 characters.
ErroQuando
InvalidIdentifiernome de tabela ou coluna fora da regra, ou reservado
UnknownTypetipo que não existe ("Texto", "string")
InvalidManifestforma errada: tabela sem campo, campo repetido, teto estourado
TableRedeclareda mesma tabela declarada duas vezes com campos diferentes
DataEngineErrora base de todos, para capturar de uma vez

Declare a tabela em um lugar só

Duas automações que declaram leads com os mesmos campos não dão problema — é copiar e colar, e a plataforma trata as duas como uma. Com campos diferentes, sai TableRedeclared: aí extraia a declaração para um módulo e importe nas duas.

Mudar uma tabela que já existe ​

Acrescentar coluna é só declarar e dar push. Trocar o tipo de uma coluna que já tem dado é recusado — mudar Text para Number com linha gravada perde dado, e a plataforma prefere dizer isso a converter no escuro:

the manifest changes the type of a column that already exists, and changing
type with data inside loses data: leads.value is text in the database and
numeric in the manifest

O caminho é declarar outra coluna com o tipo certo, migrar o conteúdo pela sua automação e parar de escrever na antiga.

Gravar e ler ​

A tabela que table() devolve é o que você usa dentro da automação. Não há URL para montar nem credencial para passar: ela já sabe falar com a plataforma.

python
from datallog import automation, table, Text, Number, Date

leads = table("leads", fields={
    "company": Text(),
    "stage": Text(index=True),
    "value": Number(),
    "next_action": Date(),
})

@automation()
def roda(seed=None):
    lead = leads.insert({"company": "Acme", "stage": "aberto", "value": 4500})
    leads.update(lead["id"], stage="em conversa")
    return leads.find(stage="em conversa", limit=20)
OperaçãoO que faz
insert(linha)grava uma linha e devolve ela inteira, com o id
insert_many(linhas)grava um lote e devolve só os id
find(**filtros)as linhas que casam, como lista de dicionários
find_with_total(**filtros)(linhas, total), para paginar mostrando "31 de 1.200"
get(id)a linha, ou None se ela não existe
count(**filtros)quantas linhas casam, sem trazer nenhuma
update(id, **campos)muda os campos dados e devolve a linha atualizada
delete(id)apaga; True se apagou, False se já não existia
aggregate(...)conta, soma, média, mínimo e máximo, com group by

Filtrar ​

Filtro é coluna=valor, e None procura quem está vazio:

python
leads.find(stage="aberto")                      # igualdade
leads.find(stage="aberto", company="Acme")      # as duas condições
leads.find(next_action=None)                    # sem data marcada
leads.count(stage="perdido")

limit, offset, order_by e columns são parâmetros, não filtros — e isso nunca é ambíguo, porque o motor reserva esses quatro nomes como coluna:

python
leads.find(stage="aberto", order_by="-value", limit=50, offset=100)
leads.find(columns=["company", "value"])        # só o que a tela usa

columns é a maior economia da rota

Medido no porte do CRM: um kanban precisava de 11.859 bytes e recebia 643.514 — 54 vezes mais — porque a tabela tinha uma coluna Json grande que ninguém ia desenhar. Peça as colunas que você usa.

Contas no banco, não na automação ​

python
leads.aggregate(
    [{"function": "sum", "column": "value", "as": "total"},
     {"function": "count", "as": "quantos"}],
    group_by="stage",
)
# [{"stage": "aberto", "total": 91500, "quantos": 20}, ...]

Somar mil linhas trazendo as mil é pagar banda e memória por um número.

Quando algo dá errado ​

python
from datallog import InvalidValue, TableNotFound, RowNotFound

try:
    leads.insert({"value": "R$ 4.500,00"})
except InvalidValue as erro:
    print(erro)   # Postgres refused a value in this operation: … send numbers
                  # without currency symbols or thousand separators …

get e delete já tratam a linha que sumiu — devolvem None e False. update numa linha apagada por outra pessoa levanta RowNotFound.

Fora da plataforma não funciona, e diz isso

A credencial vem do ambiente da execução. Rodando na sua máquina, qualquer operação levanta "no execution credential: reading and writing tables only works inside a Datallog automation".

Em projeto que roda contra outro ambiente que não produção, ponha datallog_api_url nas variáveis do projeto — sem isso a automação fala com a conta de produção.

Onde ver ​

No painel, em Uso → Dados, aparecem as tabelas da conta, o tamanho de cada uma, o teto do plano e o custo do dia.