Get Help

Test Parquet, JSON and other files with DuckDB

CAT has no provider for Parquet or JSON — but it has a DuckDB engine, and DuckDB reads them. Prepare a DuckDB database file outside CAT, with views over your files, then test it with CAT.

What you can test

Whatever DuckDB reads, a view in your database file turns into a table CAT tests.

Data How DuckDB reads it
Parquet — a file, a glob, a Hive-partitioned folder read_parquet('…')
JSON and newline-delimited JSON read_json_auto('…')
CSV, when you want DuckDB’s reader options rather than Csv@2 read_csv('…')
Excel, when you have a reason — Excel@2 is the usual way read_xlsx('…'), through DuckDB’s excel extension
files over https://, s3://, az://, gs:// the same functions; httpfs and the cloud extensions are loaded on demand
another DuckDB file ATTACH '…' (READ_ONLY)
Delta, Iceberg and DuckLake tables through their DuckDB extensions

Prepare the database

Do this once with the DuckDB command line or Python, or as a step of your pipeline that runs before CAT. A view reads the files when it is queried, so the database file stays small and the tests see today’s data:

CREATE VIEW sales AS
SELECT * FROM read_parquet('s3://acme-exports/sales/date=*/part-*.parquet', hive_partitioning = true);

In Python:

import duckdb

con = duckdb.connect("catalog.duckdb")
con.execute("""
    CREATE VIEW sales AS
    SELECT * FROM read_parquet('s3://acme-exports/sales/date=*/part-*.parquet', hive_partitioning = true)
""")
con.close()

Use CREATE TABLE … AS SELECT … instead when you want a frozen copy. Unions and joins across files belong in these views, written once, not in every test.

Then close the file. DuckDB lets one writer or many readers hold a file, never both — see Who else has the file open.

Credentials for remote files

Two ways, both with a secret that DuckDB itself keeps.

A persistent secret (recommended). Create it once with the DuckDB client that prepared the file:

CREATE PERSISTENT SECRET acme (TYPE s3, KEY_ID '…', SECRET '…', REGION '…');

DuckDB stores it under your home folder (~/.duckdb/stored_secrets, in DuckDB’s own format, not encrypted), and every DuckDB instance started afterwards on that machine and account loads it by itself — CAT’s included. It must exist before CAT opens the file: an instance that is already running does not pick up a secret created later, so in CAT Studio create it before opening the project. See DuckDB’s documentation of secrets.

A temporary secret in the query. Make CREATE SECRET the first statement of every test’s query and the SELECT the last:

CREATE SECRET acme (TYPE s3, KEY_ID '%AWS_KEY_ID%', SECRET '%AWS_SECRET%', REGION 'eu-west-1');
SELECT 1 FROM sales LIMIT 1

%NAME% is replaced in the query as well as in the connection string, so the values stay in the environment (see Work with secrets), and the statement works on a read-only database. The expanded query can surface, though: the message of a test that does not pass shows the query, a sets match test logs it at Debug level, and a DuckDB error message may echo the statement it failed on — which is why the persistent secret is the recommended route.

Add the data source

Name
Catalog
Provider
DuckDB@1
Technology
DuckDB
Connection string
DataSource=%DATA_DIR%\catalog.duckdb;access_mode=READ_ONLY
Data sources:
- Name: Catalog
  Provider: DuckDB@1
  Technology: DuckDB
  Connection string: DataSource=%DATA_DIR%\catalog.duckdb;access_mode=READ_ONLY

Open the file read-only: nothing a test does can change it, a mistyped path fails instead of creating an empty database, and several readers coexist. In CAT Studio pick DuckDB under Analytics; the guided form asks for the file and has the read-only switch on.

Write the tests

Plain SELECTs over the views. A smoke test — there is data for yesterday:

Name
Yesterday’s sales arrived
Suite
Sales export
Data source
Catalog
Query
SELECT 1 FROM sales WHERE date = ‘2026-10-22’ LIMIT 1
Expectation
set is not empty
Tests:
- Name: Yesterday's sales arrived
  Suite: Sales export
  Data source: Catalog
  Query: SELECT 1 FROM sales WHERE date = '2026-10-22' LIMIT 1
  Expectation: set is not empty

A rule — no nulls in the key column, no duplicates across the whole export:

Name
Sale ids are unique and filled
Suite
Sales export
Data source
Catalog
Query
SELECT sale_id, count(*) AS copies
FROM sales
GROUP BY sale_id
HAVING sale_id IS NULL OR count(*) > 1
Expectation
set is empty
Tests:
- Name: Sale ids are unique and filled
  Suite: Sales export
  Data source: Catalog
  Query: |
    SELECT sale_id, count(*) AS copies
    FROM sales
    GROUP BY sale_id
    HAVING sale_id IS NULL OR count(*) > 1
  Expectation: set is empty

And the comparison — the export against the warehouse table it came from, ordered on both sides:

Name
Export matches the warehouse
Suite
Sales export
First data source
Catalog
First query
SELECT sale_id, amount FROM sales WHERE date = ‘2026-10-22’ ORDER BY sale_id
Second data source
DWH
Second query
SELECT SaleId, Amount FROM fact.Sales WHERE SaleDate = ‘2026-10-22’ ORDER BY SaleId
Expectation
sets match
Tests:
- Name: Export matches the warehouse
  Suite: Sales export
  First data source: Catalog
  First query: SELECT sale_id, amount FROM sales WHERE date = '2026-10-22' ORDER BY sale_id
  Second data source: DWH
  Second query: SELECT SaleId, Amount FROM fact.Sales WHERE SaleDate = '2026-10-22' ORDER BY SaleId
  Expectation: sets match

How to climb from row counts to a full comparison, and what to do with the differences: Compare data across systems.

Csv@2 and Excel@2, or DuckDB@1?

Csv@2 and Excel@2 load the file once per session into tables named after the data source, give you a guided form and normalised names, and let one query join several files and sheets. DuckDB@1 opens a database you prepared, in which the views read the files on every test, and reaches every format and every location DuckDB does.

Use the first when the file is the data. Use the second when the format or the place has no provider, or when you want DuckDB’s reader options as written.

In-memory?

DataSource=:memory: works, and the query can read the files directly, but the database is empty at every test and gone after it, so every test carries the whole preamble and runs an engine of its own. It is not supported at this stage; prepare a database file. See In-memory databases.

Prerequisites

DuckDB ships with CAT. Two things must be in place on the machine:

  • Microsoft Visual C++ Redistributable (Windows). A very common prerequisite used by much other software, so it is probably already installed. If not, get the “X64” version from Latest Microsoft Visual C++ Redistributable Version.
  • Internet connection. DuckDB loads its extensions (httpfs, parquet, json, …) from http://extensions.duckdb.org the first time a query needs them. The URL has to be reachable — white-list it if needed.