Database

Database engines

DipDup officially supports SQLite, PostgreSQL and TimescaleDB as a database engine. This table will help you choose a database engine that mostly suits your needs.

SQLitePostgreSQLTimescaleDB
Recommended versionslatest14, 1514, 15
Best applicationearly developmentgeneral usageworking with timeseries
SQL scripts🟢🟢🟢
Immune tables⚠️🟢🟢
Hasura integration🔴🟢🟢
Migrations🔴🟢🟢

By default, DipDup uses an in-memory SQLite database that is destroyed after the process exits.

Warning
Immune tables support for SQLite is experimental and requires advanced.unsafe_sqlite flag set. Use this feature only for early experiments with database structure, and switch to PostgreSQL/TimescaleDB later.

The latest PostgreSQL and TimescaleDB versions are recommended due to significant performance improvements in recent releases (see Feature matrix page).

Usually, it's okay to use different database engines for development and production, but be careful with SQL scripts and column types that can behave differently.

Internal tables

Several tables having dipdup_ prefix are created by DipDup automatically and are not intended to be modified by the user. However, they can be useful for external monitoring and debugging.

tabledescription
dipdup_schemaInformation about database schema in use including hash to detect changes that require reindexing.
dipdup_headThe latest block received by index datasources in realtime state. Indicates that underlying datasource is ok.
dipdup_indexEverything about specific indexes from config: status, current level, template and its values if applicable.
dipdup_contractInfo about contracts used by all indexes, including ones added in runtime.
dipdup_model_updateService table to store model diffs for database rollback. Configured by advanced.rollback_depth
dipdup_metaArbitrary key-value storage for DipDup internal use. Survives reindexing. You can use it too, but don't touch keys with dipdup_ prefix.
dipdup_contract_metadataSee Metadata interface.
dipdup_token_metadataSee Metadata interface

See dipdup.models module for exact table definitions.

If you want to use these tables in monitoring, here are some SQL snippets to help you get started:

-- Time since last block received by index datasources
SELECT name, NOW() - timestamp FROM dipdup_head;

-- Index statuses
SELECT name, status FROM dipdup_index;

-- Get last reindex time
SELECT created_at FROM dipdup_schema WHERE name = 'public';

SQL scripts

Put your *.sql scripts to dipdup_indexer/sql. You can run these scripts from any callback with ctx.execute_sql_script('name'). If name is a directory, each script it contains will be executed.

Scripts are executed without being wrapped with SQL transactions. It's generally a good idea to avoid touching table data in scripts.

By default, an empty sql/<hook_name> directory is generated for every hook in config during init. Remove ctx.execute_sql call from hook callback to avoid executing them.

# Execute all scripts in sql/my_hook directory
await ctx.execute_sql_script('my_hook')

# Execute a single script
await ctx.execute_sql_script('my_hook/my_script.sql')

Helper functions

When using PostgreSQL or Timescale as database engine you can use dipdup_approve and dipdup_wipe functions to manage schema state from SQL console if needed:

SELECT dipdup_approve('public');

-- WARNING: This action is irreversible! All indexed data will be lost!
SELECT dipdup_wipe('public');

Please note that dipdup_wipe function doesn't support preserving immune tables.

Immune tables

You might want to keep several tables during schema wipe if the data in them is not dependent on index states yet heavy. A typical example is indexing IPFS data — changes in your code won't affect off-chain storage, so you can safely reuse this data.

dipdup.yaml
database:
  immune_tables:
    - ipfs_assets

immune_tables is an optional array of table names that will be ignored during schema wipe. Once an immune table is created, DipDup will never touch it again (unless schema wipe --immune is called). If you need to change the schema of an immune table, you should perform a migration manually. Check schema export output before doing this to ensure the resulting schema is the same as Tortoise ORM would generate.

TimescaleDB

TimescaleDB is a PostgreSQL extension that provides time-series data management capabilities. You can use it with DipDup as a drop-in replacement for PostgreSQL.

You can choose timescale/timescaledb or timescale/timescaledb-ha Docker images when initializing DipDup project.

Warning
Be careful! Unlike other PostgreSQL images timescale/timescaledb-ha uses /home/postgres/pgdata/data as a persistent volume.

Use SQL scripts in on_reindex directory to prepare the database. First, create a hypertable replacing the primary key with a composite one:

sql/on_reindex/00_prepare_db.sql
CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;

ALTER TABLE swap DROP CONSTRAINT swap_pkey;
ALTER TABLE swap ADD PRIMARY KEY (id, timestamp);
SELECT create_hypertable('swap', 'timestamp', chunk_time_interval => 7776000);

Now you can create a continuous aggregate on top of the hypertable:

sql/on_reindex/20_create_ca_quotes_1m.sql
CREATE MATERIALIZED VIEW
    candlestick_1m
WITH (timescaledb.continuous) AS

SELECT
    time_bucket('1 minute'::INTERVAL, timestamp) AS bucket,
    token0_id as token_id,
    candlestick_agg(
        timestamp,
        abs(amount_usd/amount0),
        amount_usd
    ) as candlestick
FROM swap
    WHERE
        amount_usd!=0
    AND
        amount0!=0

GROUP BY
    bucket,
    token0_id
ORDER BY
    bucket,
    token0_id
WITH NO DATA;

CREATE INDEX candlestick_1m_bucket ON candlestick_1m(bucket);
CREATE INDEX candlestick_1m_token_id ON candlestick_1m(token_id);

SELECT add_continuous_aggregate_policy(
    'candlestick_1m',
    start_offset => INTERVAL '1 hour',
    end_offset => INTERVAL '0 minutes',
    schedule_interval => INTERVAL '1 minute',
    initial_start := '2018-07-01'
);

For more information visit the official TimescaleDB documentation:

Migrations

Note
The database migrations feature is optional and is disabled by default. To enable it, you need to install aerich, which is available in the [migrations] optional dependencies group.

DipDup supports database migrations with aerich, a Tortoise ORM migration tool. The migration files are stored in the migrations directory in the project root.

DipDup provides a set of commands to manage database migrations:

  • dipdup schema history to show the migration history.
  • dipdup schema heads to show the current available heads.
  • dipdup schema migrate to create a new migration changes file.
  • dipdup schema upgrade to upgrade the database to the latest or a specified version.
  • dipdup schema downgrade to downgrade the database to a previous version.

The migrations directory should be initialized before using these commands. You can run dipdup schema init or simply run the indexer with dipdup run.

These commands invoke aerich's commands under the hood. You can find more information about aerich in the GitHub repository.

Note that you won't be able to directly use aerich commands in your project, as DipDup uses its own way of configuring it.

Help and tips -> Join our Discord
Ideas or suggestions -> Issue Tracker
GraphQL IDE -> Open Playground