dbt-hologres
dbt enables data analysts and engineers to transform their data using the same practices that software engineers use to build applications.
dbt is the T in ELT. Organize, cleanse, denormalize, filter, rename, and pre-aggregate the raw data in your warehouse so that it's ready for analysis.
dbt-hologres
dbt-hologres enables dbt to work with Alibaba Cloud Hologres, a real-time data warehouse compatible with PostgreSQL.
For more information on using dbt with Hologres, consult the dbt documentation.
Getting started
Installation
Install from PyPI
pip install dbt-alibaba-cloud-hologres
Install from Source
For development or to get the latest features, you can install directly from the source code:
# Clone the repository
git clone https://github.com/aliyun/dbt-hologres.git
cd dbt-hologres
# Install in editable mode
pip install --force-reinstall -e .
This allows you to:
- Modify the adapter code and see changes immediately
- Contribute to the project development
- Test unreleased features
Configuration
Configure your profiles.yml file:
hologres_project:
target: dev
outputs:
dev:
type: hologres
host: hgxxx-xx-xxx-xx-xxx.hologres.aliyuncs.com
port: 80
user: BASIC$your_username
password: your_password
database: your_database
schema: "" # Use empty string if no default schema needed
threads: 4
connect_timeout: 10
sslmode: disable
Product Features
Core Adapter Features
| Feature | Description |
|---|---|
| HologresAdapter | Core adapter with PostgreSQL-compatible syntax support |
| Psycopg3 Driver | Uses modern Psycopg 3 library for better performance |
| Incremental Strategies | Multiple strategies: append, delete+insert, merge, microbatch |
| Logical Partition Incremental Refresh | Dedicated logical_partition_table materialization with partition-level replacement |
| Constraints | Full support for primary key, not null, unique, foreign key constraints |
| Catalog by Relation | Enabled for better metadata management |
Table Properties Configuration
Hologres-specific table properties can be configured in your model:
| Property | Description |
|---|---|
orientation |
Storage direction: column or row |
distribution_key |
Distribution key for data sharding |
clustering_key |
Clustering key for query optimization |
event_time_column / segment_key |
Event time column for time-series data |
bitmap_columns |
Bitmap index columns |
dictionary_encoding_columns |
Dictionary encoding columns |
Example configuration:
models:
my_model:
materialized: table
orientation: column
distribution_key: user_id
clustering_key: created_at
event_time_column: created_at
bitmap_columns: status,type
dictionary_encoding_columns: category
Supported Data Types
The adapter supports standard PostgreSQL types plus Hologres-specific types:
| Type | Description | Example |
|---|---|---|
roaringbitmap |
Compressed bitmap for efficient set operations | rb_build(array[1,2,3]) |
json |
JSON data type (text format) | '{"key": "value"}'::json |
jsonb |
Binary JSON format with index support | '{"key": "value"}'::jsonb |
integer[] |
Integer array type | array[1, 2, 3] |
text[] |
Text array type | array['a', 'b', 'c'] |
RoaringBitmap Example:
{{ config(materialized='table') }}
select
1 as id,
rb_build(array[1,2,3,4,5]) as user_ids -- Creates a bitmap for user tagging
Note: RoaringBitmap columns require
materialized='table'for proper storage.
Dynamic Tables
Dynamic Tables are Hologres's implementation of materialized views with automatic refresh:
models:
my_model:
materialized: dynamic_table
freshness: "30 minutes"
auto_refresh_mode: auto
computing_resource: serverless
Supported configurations:
freshness: Data freshness requirement (e.g., "30 minutes", "1 hours")auto_refresh_mode:auto,incremental, orfullcomputing_resource:serverless,local, or warehouse name- Logical partitioning support for time-series data
Logical Partition Tables
Use the dedicated materialization to incrementally replace complete logical partitions:
{{ config(
materialized='logical_partition_table',
logical_partition_key='ds',
incremental_partition_key='ds',
incremental_strategy='partition',
on_schema_change='fail'
) }}
Supported configurations and behavior:
logical_partition_keyis required and accepts 1-2 comma-separated columns. Supported types are INT, TEXT, VARCHAR, DATE, TIMESTAMP, and TIMESTAMPTZ; partition keys are set to NOT NULL.incremental_partition_keyenables partition-incremental runs. It is optional, but when set it must exactly matchlogical_partition_key, including column order.incremental_strategydefaults topartitionand no other strategy is supported by this materialization.unique_keyis not used.- The first run and
--full-refreshrebuild the complete table. On an incremental run,is_incremental()returns true, and every target partition represented in the model result is deleted and then reinserted. - The model result must contain the complete data for every partition key it includes. Filtering to only changed rows would delete the rest of those partitions and produce partial backfills; filter on the actual partition key and include the boundary partition.
- The legacy
materialized='table'pluslogical_partition_keyconfiguration remains supported, but it always performs a full table rebuild. Omittingincremental_partition_keyfrom the dedicated materialization also results in a full rebuild. - Table properties such as
orientationanddistribution_keyremain supported.
For two-column partitions, compare the complete ordered tuple when selecting a batch—for example, (order_year, order_month) against the target's latest (order_year, order_month)—rather than filtering on only one column.
Non-atomic replacement: Hologres connections use autocommit and disable
BEGIN. The partition strategy therefore does not guarantee cross-statement atomicity for itsDELETE + INSERT; plan recovery or a full refresh if a run fails between those operations.
LocalDate Date Utilities
The adapter provides a powerful LocalDate class for date manipulation in Jinja2 templates:
Basic Usage
{%- set ds = adapter.parse_date('2024-03-15') -%}
{# Date arithmetic #}
{{ ds.sub_days(7) }} {# 2024-03-08 #}
{{ ds.add_months(2) }} {# 2024-05-15 #}
{# Period boundaries #}
{{ ds.start_of_month() }} {# 2024-03-01 #}
{{ ds.end_of_quarter() }} {# 2024-03-31 #}
Chained Operations
{%- set ds = adapter.parse_date('2024-03-15') -%}
{%- set start_date = ds.sub_months(2).start_of_month() -%}
{{ start_date }} {# 2024-01-01 #}
Available Methods
| Category | Methods |
|---|---|
| Arithmetic | add_days(), sub_days(), add_months(), sub_months(), add_years(), sub_years() |
| Period Boundaries | start_of_month(), end_of_month(), start_of_quarter(), end_of_quarter(), start_of_year(), end_of_year(), start_of_week(), end_of_week() |
| Formatting | format(), str(), to_sql() |
| Comparison | is_before(), is_after(), is_equal(), days_between() |
| Properties | year, month, day, quarter, day_of_year |
Helper Functions
{# Get today's date #}
{%- set today = adapter.today() -%}
{# Parse date from string #}
{%- set ds = adapter.parse_date('2024-06-15') -%}
{%- set ds = adapter.parse_date('2024/06/15') -%} {# Slash format #}
{%- set ds = adapter.parse_date('20240615') -%} {# Compact format #}
SQL Macros
The adapter provides various SQL macros for Hologres-specific operations:
CTAS with Properties
{%- set with_properties = [
"orientation = 'column'",
"distribution_key = 'id'"
] -%}
create table {{ relation }}
with (
{{ with_properties | join(',\n ') }}
)
as (
{{ compiled_code }}
);
Logical Partition Table DDL
create table {{ relation }} (
{{ column_definitions }}
)
logical partition by list ({{ partition_columns }});
Date Utility Macros
The following macros are available for date operations:
| Macro | Description |
|---|---|
parse_date(date_input) |
Parse date string into LocalDate object |
local_date(date_input) |
Alias for parse_date(), providing more intuitive naming |
today() |
Get today's date as LocalDate |
ds() |
Get execution date from EXECUTION_DATE variable or environment |
format_date(local_date, format_str) |
Format LocalDate to string |
Example usage in SQL:
{# Using local_date macro with to_sql() for SQL-compatible output #}
select
{{ local_date('2024-01-15').to_sql() }} as base_date,
{{ local_date('2024-01-15').sub_days(7).to_sql() }} as week_ago
{# Date range generation #}
{%- set start = adapter.parse_date('2024-01-01') -%}
{%- set end = adapter.parse_date('2024-01-05') -%}
{%- set days = start.days_between(end) -%}
{# Format date #}
{{ ds.format('%Y%m%d') }}
Connection Parameters
| Parameter | Required | Default | Description |
|---|---|---|---|
host |
Yes | - | Hologres instance hostname |
port |
No | 80 | Port number |
user |
Yes | - | Username (case-sensitive) |
password |
Yes | - | Password (case-sensitive) |
database |
Yes | - | Database name |
schema |
Yes | "" | Default schema (use empty string "" if not needed) |
threads |
No | 1 | Number of threads for parallel execution |
connect_timeout |
No | 10 | Connection timeout in seconds |
sslmode |
No | disable | SSL mode (disabled by default) |
application_name |
No | dbt_hologres_{version} | Application identifier |
retries |
No | 1 | Number of connection retries |
Testing Your Connection
Run dbt debug to verify your connection:
dbt debug
Example Project Structure
my_hologres_project/
├── dbt_project.yml
├── profiles.yml
├── models/
│ ├── staging/
│ │ └── stg_orders.sql
│ ├── marts/
│ │ └── fct_orders.sql
│ └── schema.yml
└── tests/
└── assert_positive_order_total.sql
Important Notes
- Case Sensitivity: Hologres usernames and passwords are case-sensitive
- Default Port: Default port is 80 (not 5432 like PostgreSQL)
- SSL Mode: SSL is disabled by default for Hologres connections
- Psycopg3: This adapter uses Psycopg 3, which has API differences from Psycopg 2
- Model Name Restrictions: Model names must not exceed 27 characters and are case-insensitive (converted to lowercase)
Supported dbt Versions
- dbt-core >= 1.8.0
- Python >= 3.10
Unit Tests
This project includes comprehensive unit tests with mocked database connections.
Test Coverage Overview
| Test File | Test Classes | Test Methods | Coverage Area |
|---|---|---|---|
| test_adapter.py | 5 | 29 | Adapter core functionality and configuration |
| test_adapter_cache.py | 4 | 18 | Adapter caching mechanisms |
| test_adapter_capabilities.py | 5 | 21 | Adapter capability checks |
| test_connection.py | 15 | 70 | Connection management and credentials |
| test_relation.py | 5 | 33 | Relation objects and index management |
| test_column.py | 9 | 52 | Column handling and data types |
| test_local_date.py | 22 | 123 | LocalDate date utilities |
| test_local_date_internals.py | 2 | 19 | LocalDate internal implementation |
| test_index_config.py | 5 | 34 | Index configuration |
| test_dynamic_table_config.py | 6 | 49 | Dynamic table configuration |
| test_sql_macros.py | 6 | 26 | SQL macro rendering |
| test_logical_partition.py | 12 | 48 | Logical partition DDL, validation, materialization, and incremental refresh |
| test_date_utils_macros.py | 9 | 34 | Date utility macros |
| test_exception_handling.py | 7 | 22 | Exception handling |
| test_edge_cases.py | 7 | 62 | Edge cases and boundary conditions |
| Total | 119 | 640 |
Parametrized cases expand the suite to 668 tests during pytest collection and execution.
Test Class Descriptions
test_adapter.py
TestHologresAdapter: Core adapter functionality, incremental strategies, timestamp operationsTestHologresConfig: Table property configuration (orientation, distribution_key, etc.)TestHologresAdapterParseDate: Date parsing functionalityTestHologresAdapterToday: Current date retrievalTestHologresAdapterTimestampAdd: Timestamp interval SQL generation
test_adapter_cache.py
TestAdapterCacheInvalidation: Cache invalidation behaviorTestAdapterCacheConsistency: Cache consistency checksTestAdapterCachePerformance: Cache performance characteristicsTestAdapterCacheEdgeCases: Cache edge case handling
test_adapter_capabilities.py
TestAdapterCapabilities: Adapter capability declarationsTestAdapterBehavior: Adapter behavior flagsTestAdapterConstraints: Constraint support capabilitiesTestAdapterMaterializations: Supported materializationsTestAdapterFeatureFlags: Feature flag handling
test_connection.py
TestHologresCredentials: Credential validation and defaultsTestHologresConnectionManager: Connection lifecycle managementTestHologresConnectionManagerOpen: Connection opening behaviorTestHologresCredentialsValidation: Credential boundary validationTestGetResponse: SQL response parsing
test_relation.py
TestHologresRelation: Relation creation and propertiesTestGetIndexConfigChanges: Index configuration change detectionTestDynamicTableConfigChanges: Dynamic table configuration changes
test_local_date.py
TestLocalDateCreation: Date object creation from various inputsTestLocalDateSubtraction: Date subtraction operationsTestLocalDateAddition: Date addition operationsTestLocalDatePeriodBoundaries: Month, quarter, year boundariesTestLocalDateChaining: Method chaining supportTestLocalDateProperties: Year, month, day, quarter propertiesTestLocalDateFormatting: Date format string generationTestLocalDateComparison: Date comparison methodsTestParseDateFunction: parse_date helper functionTestTodayFunction: today() helper functionTestLocalDateWeekMethods: Week boundary methodsTestLocalDateDayOfYear: Day of year property
test_local_date_internals.py
TestDualAccessor: Dual accessor implementationTestMonthArithmetic: Month calculation optimizationTestDateOverflow: Date overflow handlingTestCallableInteger: Callable integer subclass behavior
test_sql_macros.py
TestAdaptersMacros: CTAS and DDL statement renderingTestRelationOperations: Drop, truncate, rename operationsTestSchemaOperations: Schema creation and deletionTestViewOperations: View creation and managementTestInsertOperations: Insert statement generationTestTimestampOperations: Timestamp interval operations
test_logical_partition.py
TestLogicalPartitionConfigandTestPartitionConfigurationMacros: Configuration parsing and key validationTestLogicalPartitionMetadata: Existing logical-partition metadata inspectionTestPartitionStrategySQL: Partition deletion and insertion SQLTestLogicalPartitionMaterializationConfig: Dedicated materialization lifecycle validationTestIsIncrementalMacro: Standard and logical-partition incremental conditionsTestLogicalPartitionDDL: Single-key and two-key DDL generation
Running Tests
Using Hatch (Recommended)
Hatch is the recommended way to run tests:
# Install hatch
pip install hatch
# Run all unit tests
hatch -e cd run unit-tests
# Run a specific test file
hatch -e cd run unit-tests tests/unit/test_adapter.py
# Run a specific test class
hatch -e cd run unit-tests tests/unit/test_adapter.py::TestHologresAdapter
# Run a specific test method
hatch -e cd run unit-tests tests/unit/test_adapter.py::TestHologresAdapter::test_date_function
Using pytest Directly
You can also run tests directly with pytest:
# Install dependencies
pip install -e .
pip install pytest pytest-mock pytest-xdist freezegun
# Run all unit tests
python -m pytest tests/unit -v
# Run with parallel execution
python -m pytest tests/unit -v -n auto
# Run a specific test file
python -m pytest tests/unit/test_connection.py -v
# Run with coverage report
python -m pytest tests/unit --cov=src/dbt/adapters/hologres --cov-report=term-missing
Test Markers
| Marker | Description |
|---|---|
unit |
Unit tests (default for tests/unit/) |
integration |
Integration tests (requires database connection) |
slow |
Slow-running tests |
smoke |
Basic smoke tests |
Integration Tests
Integration tests require an actual Hologres database connection and perform real database operations including creating, updating, and dropping tables.
Prerequisites
Before running integration tests, configure your Hologres connection using one of the following methods:
Method 1: Using test.env file (Recommended)
- Copy the example environment file:
cp test.env.example test.env
- Edit
test.envand fill in your actual Hologres connection details:
# Hologres instance configuration
DBT_HOLOGRES_HOST=your_hologres_instance.hologres.aliyuncs.com
DBT_HOLOGRES_PORT=80
DBT_HOLOGRES_USER='BASIC$your_username'
DBT_HOLOGRES_PASSWORD='your_password'
DBT_HOLOGRES_DATABASE='your_database'
DBT_HOLOGRES_SCHEMA='test_schema'
# Enable integration tests
DBT_HOLOGRES_RUN_INTEGRATION_TESTS=true
- Load the environment variables before running tests:
# Load environment variables from test.env
export $(cat test.env | grep -v '^#' | xargs)
# Run integration tests
pytest tests/integration/
Method 2: Setting environment variables directly
export DBT_HOLOGRES_RUN_INTEGRATION_TESTS=true
export DBT_HOLOGRES_HOST=your_hologres_instance.hologres.aliyuncs.com
export DBT_HOLOGRES_PORT=80
export DBT_HOLOGRES_USER=your_username
export DBT_HOLOGRES_PASSWORD=your_password
export DBT_HOLOGRES_DATABASE=your_database
export DBT_HOLOGRES_SCHEMA=test_schema # Optional, defaults to 'test_schema'
Running Integration Tests
# Run all integration tests
pytest tests/integration/
# Run specific integration test
pytest tests/integration/test_table_operations.py
# Run with verbose output
pytest tests/integration/ -v
# Run only table operation tests
pytest tests/integration/test_table_operations.py -v
# Run only view operation tests
pytest tests/integration/test_view_operations.py -v
# Run only Hologres-specific feature tests
pytest tests/integration/test_hologres_features.py -v
# Run only logical-partition incremental integration tests
pytest tests/integration/test_logical_partition_incremental.py -v
Integration Test Structure
The integration test suite includes:
- test_table_operations.py: Tests for table creation, updates, deletion, and incremental models
- test_view_operations.py: Tests for view creation, dependencies, and conversions
- test_hologres_features.py: Tests for Hologres-specific features like indexes, dynamic tables, and partitioning
- test_logical_partition_incremental.py: Tests single-key and two-key partition replacement against a live Hologres database
Each test uses an isolated schema to ensure tests don't interfere with each other. Test schemas are automatically cleaned up after each test run.
Test Isolation
Integration tests create unique schemas for each test to ensure isolation:
- Each test gets a unique schema name (e.g.,
test_a1b2c3d4e5f6g7h8i9j0) - Tests clean up their schemas automatically after completion
- Failed tests still attempt cleanup
Functional Tests
Functional tests use the official dbt test framework (dbt-tests-adapter) to verify
end-to-end dbt operations against a Hologres database.
Test Structure
tests/functional/
├── conftest.py # dbt test framework configuration
├── fixtures.py # Shared test models and seeds
├── test_basic.py # Basic dbt run, seed, compile tests
├── test_materializations/
│ ├── test_table.py # Table materialization tests
│ ├── test_incremental.py # Incremental model tests
│ └── test_dynamic_table.py # Dynamic table tests
├── test_logical_partition.py # Logical partition tests
└── test_date_utils.py # Date utility macro tests
Running Functional Tests
# Set required environment variables
export DBT_HOLOGRES_RUN_FUNCTIONAL_TESTS=true
export DBT_HOLOGRES_HOST=your-hologres-host
export DBT_HOLOGRES_USER=your-user
export DBT_HOLOGRES_PASSWORD=your-password
export DBT_HOLOGRES_DATABASE=your-database
# Run using Hatch
hatch -e cd run integration-tests
# Or run directly with pytest
python -m pytest tests/functional/ -v
Test Coverage
| Test File | Test Classes | Coverage |
|---|---|---|
| test_basic.py | 5 | Basic run, seed, compile, test operations |
| test_table.py | 9 | Table materialization with indexes, properties |
| test_incremental.py | 8 | Incremental strategies (append, merge, delete+insert) |
| test_dynamic_table.py | 8 | Dynamic table creation and auto-refresh |
| test_logical_partition.py | 12 | Logical partition creation, incremental refresh, metadata validation, and failure recovery |
| test_date_utils.py | 10 | LocalDate operations and date macros |
Building and Publishing
Build
This project uses Hatchling as the build backend.
# Install hatch (if not already installed)
pip install hatch
# Build wheel and sdist (output to dist/)
hatch build
# Build wheel only
hatch build -t wheel
Verify
Validate the built package before publishing:
hatch run build:check-all
This runs twine check and installation verification to ensure package quality.
Publish to PyPI
# Install twine (if not already installed)
pip install twine
# Upload to PyPI
twine upload dist/*
You need to configure PyPI credentials beforehand, either via ~/.pypirc or environment variables:
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=your-pypi-api-token
Version Management
The version number is maintained in a single file:
src/dbt/adapters/hologres/__version__.py
Hatchling reads the version automatically from this file during build — no need to update it elsewhere.
Release Checklist
- Update version in
src/dbt/adapters/hologres/__version__.py - Update
CHANGELOG.mdand user-facing documentation - Build:
hatch build - Verify:
hatch run build:check-all - Publish:
twine upload dist/* - Tag:
git tag v<version> && git push origin v<version>
Resources
License
Apache License 2.0
Support
For issues and questions:
Metadata
Release files for dbt-alibaba-cloud-hologres 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dbt_alibaba_cloud_hologres-1.2.0.tar.gz | 184.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dbt_alibaba_cloud_hologres-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 230.1 kB
Release files / dbt_alibaba_cloud_hologres-1.2.0.tar.gz
| Download URL | dbt_alibaba_cloud_hologres-1.2.0.tar.gz |
|---|---|
| Size | 184.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8de2927ef26e94dfdfc21ef164e4392a373c610d289c2b2bbbbd2c9fc2549b7f
|
|
BLAKE2b-256 checksum How to use checksums |
2a0a3d97329b9f5e5eff3e6a91385ce353fadc958c84086a52c8a393443b96f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / dbt_alibaba_cloud_hologres-1.2.0-py3-none-any.whl
| Download URL | dbt_alibaba_cloud_hologres-1.2.0-py3-none-any.whl |
|---|---|
| Size | 45.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1c932a0b78a24314e853a7c59ced43c5a127733466928743e03abd7253f3a2fc
|
|
BLAKE2b-256 checksum How to use checksums |
3ee78b13841adee25556d33223628426aba42e85cf13aac80005ed6f82e43790
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|