Monthly summaries with native selectionsΒΆ
A calculation can consume an entire employee, project and customer selection as one value. This avoids a Cartesian product of separate scalar inputs. Existing native KPI properties continue to expose the result.
In an installed application, with existing Employee, Project and Customer managers, declare:
from datetime import date
from general_manager.interface import CalculationInterface
from general_manager.manager import GeneralManager, Input, graph_ql_property
class WorkforceSummary(GeneralManager):
month: date
employees: list[Employee] | None
projects: list[Project] | None
customers: list[Customer] | None
class Interface(CalculationInterface):
month = Input.monthly_date(
start=date(2020, 1, 1), end=date(2100, 12, 31), anchor="start"
)
employees = Input(list[Employee], required=False)
projects = Input(list[Project], required=False)
customers = Input(list[Customer], required=False)
@graph_ql_property(cache="none")
def selected_employee_count(self) -> int | None:
# None means unrestricted; [] is explicitly empty in this application.
return None if self.employees is None else len(self.employees)
Retain the application's normal read permissions and add its existing KPI methods. The framework preserves None and []; it does not decide which employees, projects or customers are visible to the caller.
summary = WorkforceSummary(
month="2026-10-01",
employees_id=["17", "18"],
projects=[],
customers=None,
)
assert summary.selected_employee_count == 2
assert WorkforceSummary(month="2026-10-01", employees=[]).selected_employee_count == 0
assert WorkforceSummary(month="2026-10-01").selected_employee_count is None
The constructor resolves each ID using the declared manager type. Existing manager instances and identification mappings are also accepted. For a composite manager, use complete constructor mappings, for example selections=[{"label": "scenario", "values": [2, 1, 2]}] when the referenced manager declares label = Input(str) and values = Input(list[int]).
The generated single-summary query is:
query Summary($month: Date!, $employees: [ID!], $projects: [ID!], $customers: [ID!]) {
workforceSummary(
month: $month
employeesId: $employees
projectsId: $projects
customersId: $customers
) {
month
selectedEmployeeCount
employees { id }
}
}
{
"month": "2026-10-01",
"employees": ["17", "18"],
"projects": [],
"customers": null
}
This requests one WorkforceSummaryType. employeesId deliberately follows the existing _id constructor alias; it is not renamed employeesIds. Lists retain order and duplicates. For required collections use Input(list[T]); the GraphQL argument then gains outer non-null, but [] remains valid.
The owning employees field is checked first. If a selected employee fails its manager-level read permission, GraphQL omits only that member and preserves the order and duplicates of the permitted members. Field-level permissions still apply to id, name, and other selected member fields.
Whole-list validators can enforce application constraints without a new descriptor:
values = Input(list[int], validator=lambda values: len(values) <= 100)
choices = Input(list[int], possible_values=[[], [1, 2]])
The second input has two whole-selection choices. values__in=[[1, 2], []] likewise selects alternative complete lists in Python; the original scalar employee__in=[1, 2] still enumerates separate employee inputs. No JSON encoding or GraphQL JSONString is involved.