Workflow Query Examples

Developer guide for the Enezaframework workflow engine. Part of the Workflow series.

Table of Contents

  1. Overview
  2. Example 1 — Simple Aggregate Condition
  3. Example 2 — Multiple Aggregates
  4. Example 3 — Aggregate + Regular Field
  5. Example 4 — Groups Format with Annotations
  6. Example 5 — Programmatic Usage
  7. Example 6 — Direct use of parse_annotations
  8. Related Guides

Overview

These examples progress from a single aggregate to groups format and programmatic use. All use the annotation schema from Workflow Aggregate Annotations and the JSON schema from Workflow Query JSON Format.


Example 1 — Simple Aggregate Condition

json
{
  "condition": "AND",
  "annotations": [
    {"function": "sum", "field": "total_amount", "related_model": "lines", "alias": "grand_total"}
  ],
  "rules": [
    {"id": "grand_total", "field": "grand_total", "type": "double", "operator": "greater", "value": "5000"}
  ]
}

SQL equivalent:

sql
SELECT *, SUM(lines.total_amount) AS grand_total
FROM invoice
LEFT JOIN invoice_line AS lines ON lines.invoice_id = invoice.id
GROUP BY invoice.id
HAVING SUM(lines.total_amount) > 5000

Example 2 — Multiple Aggregates

json
{
  "condition": "AND",
  "annotations": [
    {"function": "count", "field": "id", "related_model": "lines", "alias": "item_count"},
    {"function": "avg",   "field": "unit_price", "related_model": "lines", "alias": "avg_price"}
  ],
  "rules": [
    {"id": "item_count", "field": "item_count", "type": "integer", "operator": "greater_or_equal", "value": "5"},
    {"id": "avg_price",  "field": "avg_price",  "type": "double",  "operator": "less", "value": "100"}
  ]
}

Documents with at least 5 line items whose average unit price is below 100.


Example 3 — Aggregate + Regular Field

json
{
  "condition": "AND",
  "annotations": [
    {"function": "sum", "field": "amount", "related_model": "lines", "alias": "total"}
  ],
  "rules": [
    {"id": "status", "field": "status", "type": "string", "operator": "equal", "value": "open"},
    {"id": "total",  "field": "total",  "type": "double", "operator": "greater", "value": "1000"}
  ]
}

Regular model fields and annotation aliases mix freely in the same rules array.

flowchart LR
    R["rules[]"] --> F["filter()"]
    A["annotations[]"] --> AN["annotate()"]
    AN --> F
    F --> Q["queryset"]

Example 4 — Groups Format with Annotations

json
{
  "condition": "AND",
  "primary_model": "frameworktestdocument",
  "related_models": ["lines"],
  "annotations": [
    {"function": "max", "field": "amount", "related_model": "lines", "alias": "max_line_amount"},
    {"function": "min", "field": "amount", "related_model": "lines", "alias": "min_line_amount"}
  ],
  "groups": [
    {
      "condition": "AND",
      "rules": [
        {"id": "max_line_amount", "field": "max_line_amount", "type": "double", "operator": "greater", "value": "500"},
        {"id": "min_line_amount", "field": "min_line_amount", "type": "double", "operator": "less", "value": "50"}
      ]
    }
  ]
}

Documents whose highest line amount exceeds 500 and whose lowest is under 50.


Example 5 — Programmatic Usage

python
from enezaworkflowengine.models import SavedQuery

query = SavedQuery.objects.create(
    name="High Value Orders",
    content_type=invoice_ct,
    filters_json={
        "condition": "AND",
        "annotations": [
            {"function": "sum", "field": "line_total", "related_model": "lines", "alias": "total"},
            {"function": "count", "field": "id", "related_model": "lines", "alias": "line_count"},
        ],
        "rules": [
            {"id": "total", "field": "total", "type": "double", "operator": "greater", "value": "10000"},
            {"id": "line_count", "field": "line_count", "type": "integer", "operator": "greater", "value": "10"},
        ],
    },
    user=user,
    workflow="InvoiceWorkflow",
)

# Scoped to one document
results = query.get_queryset(object_id="550e8400-e29b-41d4-a716-446655440000")

# All matching records
all_results = query.get_queryset()

Example 6 — Direct use of parse_annotations

python
from enezaworkflowengine.utils import parse_annotations
from myapp.models import Invoice

annotations = parse_annotations(Invoice, [
    {"function": "sum", "field": "line_total", "related_model": "lines", "alias": "total"},
    {"function": "count", "field": "id", "related_model": "lines", "alias": "line_count"},
])

queryset = Invoice.objects.annotate(**annotations)
queryset = queryset.filter(total__gt=1000, line_count__gte=5)

This bypasses SavedQuery entirely and applies the same aggregate expressions to any queryset.