Cargar un archivo CSV en una tabla
Traducción automática
Esta página se tradujo automáticamente del inglés y todavía no la revisó un hablante nativo; las correcciones son bienvenidas en GitHub. Si algo no coincide, vale el original en inglés.
Tarea: cargar una lista de productos en la base de datos, todo o nada.
yaml
# Recipe: load the rows of a CSV file into a table, all or nothing.
paths:
components: ./components
migrations: ./migrations
datasources:
db:
driver: sqlite
database: ./data/shop.dbsql
CREATE TABLE products (
sku TEXT PRIMARY KEY,
name TEXT NOT NULL,
price INTEGER NOT NULL CHECK (price > 0)
);text
sku,name,price
MUG-1,Mug,30
TEE-1,T-shirt,80
STK-1,Sticker,5La acción lee el archivo con q:data y después inserta cada fila dentro de un solo q:transaction; las consultas que contiene, también las del bucle, usan su fuente de datos.
xml
<q:component name="Import">
<q:action name="load" method="POST">
<q:data name="rows" source="import/products.csv" type="csv">
<q:column name="price" type="integer" />
</q:data>
<!-- One transaction for the whole file: if one row is refused (a sku
already there, a price that is not positive), none stays. -->
<q:transaction datasource="db">
<q:loop items="{rows}" var="row">
<q:query name="inserted">
INSERT INTO products (sku, name, price) VALUES (:sku, :name, :price)
<q:param name="sku" value="{row.sku}" type="string" />
<q:param name="name" value="{row.name}" type="string" />
<q:param name="price" value="{row.price}" type="integer" />
</q:query>
</q:loop>
</q:transaction>
<q:redirect url="/" flash="Loaded {len(rows)} products." />
</q:action>
<q:query name="products" datasource="db">SELECT sku, name, price FROM products ORDER BY sku</q:query>
<ui:window title="Products">
<q:if condition="flash">
<ui:alert variant="success">{flash}</ui:alert>
</q:if>
<ui:text>{products_result.recordCount} products</ui:text>
<ui:table source="{products}" />
<ui:form on-submit="load" submit="Load import/products.csv" />
</ui:window>
</q:component>La segunda prueba carga el archivo cuando uno de sus productos ya está: la segunda fila falla, y la primera, ya insertada, se revierte.
xml
<q:test name="the file's rows land in the table" page="/">
<test:submit action="load" />
<test:expect redirect="/" flash="Loaded 3 products." />
<test:expect table="products" count="3" />
<test:expect table="products" count="1" where="sku = 'TEE-1' AND price = 80" />
<test:expect text="3 products" />
</q:test>
<q:test name="a file that fails halfway leaves nothing behind" page="/">
<!-- TEE-1 is already there: the second row fails, so the first is undone too. -->
<test:given table="products" sku="TEE-1" name="T-shirt" price="80" />
<test:submit action="load" />
<test:expect status="500" />
<test:expect table="products" count="1" />
<test:expect table="products" count="0" where="sku = 'MUG-1'" />
</q:test>text
tests/load.test.q
PASS the file's rows land in the table
PASS a file that fails halfway leaves nothing behind
2 passed, 0 failed