Workflow Query Quick Start

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

Table of Contents

  1. Overview
  2. Step 1 — Define an Aggregate-Enabled Query
  3. Step 2 — Save It Through the API
  4. Step 3 — Execute with Object ID
  5. Step 4 — Use It in the Workflow Engine
  6. Related Guides

Overview

This quick start builds one query that filters documents by an aggregate (total line amount) and executes it scoped to a single document. No configuration is required in the workflow engine for the object-ID behavior — the engine extracts the ID itself.

flowchart LR
    A["Define filters_json<br/>annotations + rules"] --> B["Save via SaveQueryView"]
    B --> C["SavedQuery stored<br/>with workflow"]
    C --> D["execute(object_id=...)"]
    C --> E["Condition step<br/>auto object_id"]
    D --> F["Scoped results"]
    E --> F

Step 1 — Define an Aggregate-Enabled Query

json
{
  "condition": "AND",
  "annotations": [
    {"function": "sum", "field": "line_total", "related_model": "lines", "alias": "total"},
    {"function": "count", "field": "id", "related_model": "lines", "alias": "item_count"}
  ],
  "rules": [
    {"id": "total", "field": "total", "type": "double", "operator": "greater", "value": "500"},
    {"id": "item_count", "field": "item_count", "type": "integer", "operator": "greater", "value": "3"}
  ]
}

This matches documents whose line amounts total more than 500 and that have more than 3 line items. The rule field values must equal the annotation alias values.


Step 2 — Save It Through the API

POST the query to SaveQueryView (enezaworkflowengine:save_query):

json
{
  "name": "Large Orders",
  "model_slug": "frameworktestdocument",
  "workflow_name": "InvoiceWorkflow",
  "query": {
    "condition": "AND",
    "annotations": [
      {"function": "sum", "field": "amount", "related_model": "lines", "alias": "total_amount"}
    ],
    "rules": [
      {"id": "total_amount", "field": "total_amount", "type": "double", "operator": "greater", "value": "1000"}
    ]
  }
}

Alternatively, send annotations as a separate top-level key — the view merges it into filters_json before saving (enezaworkflowengine/views/querybuilder.py:104-107):

json
{
  "name": "Large Orders",
  "model_slug": "frameworktestdocument",
  "workflow_name": "InvoiceWorkflow",
  "query": {
    "condition": "AND",
    "rules": []
  },
  "annotations": [
    {"function": "sum", "field": "amount", "related_model": "lines", "alias": "total_amount"}
  ]
}

Step 3 — Execute with Object ID

text
GET /workflow/savedquery/5/?execute=1&object_id=550e8400-e29b-41d4-a716-446655440000

SaveQueryDetailView reads object_id from the query string and forwards it to the query (views/querybuilder.py:231-234):

python
object_id = self.request.GET.get('object_id')
queryset = self.object.execute(object_id=object_id)

object_id is a string (UUID for EnezaModel subclasses); Django's ORM accepts it directly in pk=....


Step 4 — Use It in the Workflow Engine

No configuration is needed. When a condition step evaluates, the engine supplies the ID automatically:

python
# Web path: services/step_handlers.py:242 — has workflow_instance
queryset = condition_query.get_queryset(object_id=workflow_instance.object_id)

# Celery path: tasks/workflow_tasks.py:253-254 — delegates to the service function
from enezaworkflowengine.services.condition_step import evaluate_condition_for_document
result = evaluate_condition_for_document(workflow_instance.document, condition_query)
# -> evaluate_condition_for_document extracts str(document.pk) and passes it on
sequenceDiagram
    participant W as WorkflowInstance
    participant H as ConditionStepHandler
    participant Q as SavedQuery

    W->>H: STEP_ENTERED
    H->>Q: get_queryset(object_id=workflow_instance.object_id)
    Q-->>H: count
    H-->>W: CONDITION_TRUE or CONDITION_FALSE