Special Table Types
Hugr provides special table type annotations for optimized handling of specific data patterns like OLAP cubes and time-series data.
Cubes with @cube
The @cube
directive enables OLAP-style pre-aggregation for analytical queries:
type sales @table(name: "sales") @cube {
id: BigInt! @pk
# Dimension fields (used for grouping)
customer_id: Int!
product_id: Int!
store_id: Int!
sale_date: Date!
# Measurement fields (aggregated)
quantity: Int! @measurement
unit_price: Float! @measurement
total_amount: Float! @measurement
discount: Float! @measurement
}
Querying Cubes
When querying cubes, specify aggregation functions for measurements:
query {
sales {
# Dimensions (grouped by)
sale_date(bucket: month)
customer {
country
}
product {
category {
name
}
}
# Measurements (aggregated)
quantity(measurement_func: SUM)
total_amount(measurement_func: SUM)
unit_price(measurement_func: AVG)
discount(measurement_func: AVG)
}
}
Measurement Aggregation Functions
Available functions by type:
Numeric (Int, BigInt, Float):
SUM
- Total sumAVG
- Average valueMIN
- Minimum valueMAX
- Maximum valueANY
- Any value (for dimensions)
Boolean:
ANY
- Any valueOR
- Logical ORAND
- Logical AND
Date/Timestamp:
MIN
- Earliest dateMAX
- Latest dateANY
- Any value
Cube Behavior
- Pre-aggregation: Data is grouped before joins
- Automatic dimensions: Non-measurement fields become group-by dimensions
- Subquery impact: Adding related fields automatically includes foreign keys in grouping
Example with automatic dimension inclusion:
query {
sales {
# customer_id automatically included in GROUP BY
customer {
name
country
}
# Aggregations
total_amount(measurement_func: SUM)
quantity(measurement_func: SUM)
}
}
Mixed Queries
Combine measurements with and without aggregation:
query {
sales {
# Dimensions
sale_date(bucket: quarter)
store_id
# Aggregated measurement
total_revenue: total_amount(measurement_func: SUM)
# Non-aggregated (becomes dimension)
unit_price
# Count of records
_rows_count
}
}
TimescaleDB Hypertables
For PostgreSQL with TimescaleDB, optimize time-series data:
type sensor_readings @table(name: "sensor_readings") @hypertable {
sensor_id: Int! @pk
timestamp: Timestamp! @pk @timescale_key
temperature: Float!
humidity: Float!
pressure: Float!
}
Time-Series Queries
Leverage TimescaleDB functions:
query {
sensor_readings_bucket_aggregation {
key {
# TimescaleDB time_bucket function
timestamp(bucket: hour)
sensor_id
}
aggregations {
temperature {
avg
min
max
}
humidity {
avg
}
}
}
}
Continuous Aggregates
Define views on hypertables:
type hourly_sensor_stats @view(
name: "hourly_sensor_stats"
) @hypertable {
sensor_id: Int! @pk
hour: Timestamp! @pk @timescale_key
avg_temperature: Float!
avg_humidity: Float!
min_temperature: Float!
max_temperature: Float!
}
Combining Special Types
Use cubes with time-series data:
type sales_metrics @table(name: "sales_metrics")
@cube
@hypertable {
# Time dimension
timestamp: Timestamp! @timescale_key
# Other dimensions
product_id: Int!
region: String!
# Measurements
revenue: Float! @measurement
units_sold: Int! @measurement
customers: Int! @measurement
}
Query with time-series optimization:
query {
sales_metrics {
# Time bucket using TimescaleDB
timestamp(bucket: day)
# Dimension
region
# Aggregated measurements
revenue(measurement_func: SUM)
units_sold(measurement_func: SUM)
customers(measurement_func: COUNT)
}
}
Performance Benefits
Cube Benefits
- Reduced computation: Pre-aggregation before joins
- Optimized grouping: Automatic dimension detection
- Memory efficiency: Less data transferred
Hypertable Benefits
- Automatic partitioning: By time dimension
- Faster queries: Optimized for time-range queries
- Data compression: Automatic old data compression
- Continuous aggregates: Materialized time-based views
Best Practices
When to Use @cube
Use for tables that are:
- Frequently aggregated
- Have clear dimensions vs measurements
- Used in analytical/reporting queries
- Large fact tables in star/snowflake schemas
When to Use @hypertable
Use for tables that:
- Have time-series data
- Are partitioned by time
- Need efficient time-range queries
- Require automatic data retention policies
Combining with Other Features
Cubes and hypertables work with all other Hugr features:
type sales @table(name: "sales")
@cube
@cache(ttl: 300, tags: ["sales"]) {
id: BigInt! @pk
store_id: Int! @field_references(
references_name: "stores"
field: "id"
query: "store"
)
sale_date: Date!
amount: Float! @measurement
}
Query with relations:
query {
sales {
sale_date(bucket: month)
store {
region
country
}
amount(measurement_func: SUM)
}
}
Limitations
Cube Limitations
- Pre-aggregation happens before joins
- Cannot mix aggregated and non-aggregated measurements
- All non-measurement fields become dimensions
Hypertable Limitations
- Requires PostgreSQL with TimescaleDB
- Primary key must include time column
- Some constraints not supported on distributed hypertables