Um formulário a partir da tabela
Tradução automática
Esta página foi traduzida automaticamente do inglês e ainda não foi revisada por um falante nativo; correções são bem-vindas no GitHub. Se algo não bater, vale o original em inglês. O código e os resultados são os mesmos do original, importados dos arquivos testados.
Tarefa: um formulário para uma tabela sem escrever de novo cada campo e cada regra.
# Recipe: the table's schema gives the action its rules and the form its fields.
paths:
components: ./components
migrations: ./migrations
datasources:
db:
driver: sqlite
database: ./data/library.dbO esquema já diz do que um livro precisa:
CREATE TABLE authors (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
);
CREATE TABLE books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title VARCHAR(120) NOT NULL,
author_id INTEGER NOT NULL REFERENCES authors(id),
genre TEXT NOT NULL CHECK (genre IN ('novel', 'poetry', 'essay')),
pages INTEGER,
lent BOOLEAN NOT NULL DEFAULT 0
);
INSERT INTO authors (name) VALUES ('Clarice Lispector'), ('Machado de Assis');<q:action table="books" datasource="db"> o lê e faz um q:param de cada coluna menos a chave, na ordem da tabela:
| Coluna | Vira |
|---|---|
title VARCHAR(120) NOT NULL | obrigatório, no máximo 120 caracteres |
author_id ... REFERENCES authors(id) | um inteiro que precisa nomear um autor existente |
genre ... CHECK (genre IN (...)) | um dos três |
pages INTEGER (aceita NULL) | um inteiro; deixado em branco, chega à ação como None |
lent BOOLEAN | uma caixa |
Um ui:form sem campos próprios desenha um por parâmetro, com o rótulo tirado do nome (author_id vira "Author"). O campo do autor é uma lista com os nomes dos autores. null="true" no parâmetro pages da consulta grava um campo em branco como NULL.
<q:component name="Books">
<!-- No q:param: each column but the key becomes one, with the rules the
schema gives it (UI-10). NOT NULL is required, VARCHAR(120) a
maxlength, the CHECK a list, the REFERENCES a row that must exist. -->
<q:action name="add" method="POST" table="books" datasource="db">
<q:query name="added" datasource="db">
INSERT INTO books (title, author_id, genre, pages, lent)
VALUES (:title, :author_id, :genre, :pages, :lent)
<q:param name="title" value="{title}" type="string" />
<q:param name="author_id" value="{author_id}" type="integer" />
<q:param name="genre" value="{genre}" type="string" />
<q:param name="pages" value="{pages}" type="integer" null="true" />
<q:param name="lent" value="{lent}" type="boolean" />
</q:query>
<q:redirect url="/" flash="Added: {title}" />
</q:action>
<q:query name="books" datasource="db">
SELECT b.title, a.name AS author, b.genre FROM books b JOIN authors a ON a.id = b.author_id
ORDER BY b.id
</q:query>
<ui:window title="Library">
<q:if condition="flash">
<ui:alert variant="{flashType == 'error' and 'danger' or 'success'}">{flash}</ui:alert>
</q:if>
<!-- A form with no fields draws one per param: a list of authors for
author_id, a list for genre, a box for lent, and the button. -->
<ui:form on-submit="add" submit="Add book" />
<ui:table source="{books}" />
</ui:window>
</q:component><q:test name="the form draws a field per column, labelled from its name" page="/">
<test:visit />
<test:expect text="Title" />
<test:expect text="Author" />
<test:expect text="Machado de Assis" />
<test:expect text="Add book" />
</q:test>
<q:test name="a book is added" page="/">
<test:submit action="add" title="Dom Casmurro" author_id="2" genre="novel" pages="256" />
<test:expect redirect="/" flash="Added: Dom Casmurro" />
<test:expect table="books" count="1" where="title = 'Dom Casmurro' AND pages = 256 AND lent = 0" />
</q:test>
<q:test name="the rules come from the schema" page="/">
<test:submit action="add" title="" author_id="9" genre="comic" pages="many" />
<test:expect error="title" message="Required" />
<test:expect error="author_id" message="Must name an existing row of authors (no id = 9)" />
<test:expect error="genre" message="Must be one of: novel, poetry, essay" />
<test:expect error="pages" message="Must be an integer, got 'many'" />
<test:expect table="books" count="0" />
</q:test>
<q:test name="a blank optional column is stored as NULL" page="/">
<test:submit action="add" title="A hora da estrela" author_id="1" genre="novel" pages="" />
<test:expect table="books" count="1" where="pages IS NULL" />
</q:test>tests/books.test.q
PASS the form draws a field per column, labelled from its name
PASS a book is added
PASS the rules come from the schema
PASS a blank optional column is stored as NULL
4 passed, 0 failedUm q:param escrito na ação vence o do esquema, e columns="a,b" fica só com essas colunas. Veja UI-10.