AQL Query Language

Complex Queries

Master advanced AQL query patterns for sophisticated model analysis and cross-model operations.

In this tutorial, you’ll learn how to build complex queries using let bindings, nested iterations, cross-model navigation, and advanced query composition techniques. These patterns enable powerful model analysis and validation scenarios.

40 mins Estimated Time

Section 1

Let Bindings and Variable Scope

Let bindings allow you to store intermediate results and build complex queries step by step. They improve query readability and performance by avoiding repeated computation of expensive expressions.

Understanding variable scope in let bindings is crucial for building maintainable and efficient queries that work correctly across different contexts.

AQL Let Binding Patterns

Step 1

Set up a complex model for advanced query examples.

This comprehensive metamodel represents an enterprise system with Organisations, Projects, Teams, and Resources. The complex relationships provide rich opportunities for sophisticated queries.

Enterprise.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
5 name="enterprise" nsURI="http://www.example.org/enterprise" nsPrefix="ent">
6
7 <!-- Organisation: root container for the enterprise structure -->
8 <eClassifiers xsi:type="ecore:EClass" name="Organisation">
9 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
10 <eStructuralFeatures xsi:type="ecore:EAttribute" name="founded" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
11 <eStructuralFeatures xsi:type="ecore:EAttribute" name="headquarters" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
12 <eStructuralFeatures xsi:type="ecore:EReference" name="departments" upperBound="-1"
13 eType="#//Department" containment="true"/>
14 <eStructuralFeatures xsi:type="ecore:EReference" name="projects" upperBound="-1"
15 eType="#//Project" containment="true"/>
16 </eClassifiers>
17
18 <!-- Department: organisational unit with hierarchical structure -->
19 <eClassifiers xsi:type="ecore:EClass" name="Department">
20 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
21 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
22 <eStructuralFeatures xsi:type="ecore:EAttribute" name="budget" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/>
23 <eStructuralFeatures xsi:type="ecore:EAttribute" name="location" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
24 <eStructuralFeatures xsi:type="ecore:EReference" name="employees" upperBound="-1"
25 eType="#//Employee" containment="true"/>
26 <eStructuralFeatures xsi:type="ecore:EReference" name="subDepartments" upperBound="-1"
27 eType="#//Department" containment="true"/>
28 <eStructuralFeatures xsi:type="ecore:EReference" name="parentDepartment" eType="#//Department"
29 eOpposite="#//Department/subDepartments"/>
30 <eStructuralFeatures xsi:type="ecore:EReference" name="manager" eType="#//Employee"/>
31 <eStructuralFeatures xsi:type="ecore:EReference" name="collaboratesWith" upperBound="-1"
32 eType="#//Department"/>
33 </eClassifiers>
34
35 <!-- Employee: worker within a department -->
36 <eClassifiers xsi:type="ecore:EClass" name="Employee">
37 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
38 <eStructuralFeatures xsi:type="ecore:EAttribute" name="employeeId" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
39 <eStructuralFeatures xsi:type="ecore:EAttribute" name="salary" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/>
40 <eStructuralFeatures xsi:type="ecore:EAttribute" name="yearsOfService" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
41 <eStructuralFeatures xsi:type="ecore:EAttribute" name="role" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
42 <eStructuralFeatures xsi:type="ecore:EAttribute" name="skills" upperBound="-1"
43 eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
44 <eStructuralFeatures xsi:type="ecore:EReference" name="supervisor" eType="#//Employee"/>
45 <eStructuralFeatures xsi:type="ecore:EReference" name="directReports" upperBound="-1"
46 eType="#//Employee" eOpposite="#//Employee/supervisor"/>
47 <eStructuralFeatures xsi:type="ecore:EReference" name="assignedProjects" upperBound="-1"
48 eType="#//Project" eOpposite="#//Project/teamMembers"/>
49 <eStructuralFeatures xsi:type="ecore:EReference" name="mentors" upperBound="-1"
50 eType="#//Employee"/>
51 </eClassifiers>
52
53 <!-- Project: work initiative with team members -->
54 <eClassifiers xsi:type="ecore:EClass" name="Project">
55 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
56 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
57 <eStructuralFeatures xsi:type="ecore:EAttribute" name="budget" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/>
58 <eStructuralFeatures xsi:type="ecore:EAttribute" name="status" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
59 <eStructuralFeatures xsi:type="ecore:EAttribute" name="priority" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
60 <eStructuralFeatures xsi:type="ecore:EAttribute" name="startDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
61 <eStructuralFeatures xsi:type="ecore:EAttribute" name="endDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
62 <eStructuralFeatures xsi:type="ecore:EReference" name="teamMembers" upperBound="-1"
63 eType="#//Employee" eOpposite="#//Employee/assignedProjects"/>
64 <eStructuralFeatures xsi:type="ecore:EReference" name="leadDepartment" eType="#//Department"/>
65 <eStructuralFeatures xsi:type="ecore:EReference" name="dependencies" upperBound="-1"
66 eType="#//Project"/>
67 <eStructuralFeatures xsi:type="ecore:EReference" name="milestones" upperBound="-1"
68 eType="#//Milestone" containment="true"/>
69 </eClassifiers>
70
71 <!-- Milestone: project checkpoint with deliverables -->
72 <eClassifiers xsi:type="ecore:EClass" name="Milestone">
73 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
74 <eStructuralFeatures xsi:type="ecore:EAttribute" name="dueDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
75 <eStructuralFeatures xsi:type="ecore:EAttribute" name="completed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
76 <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
77 </eClassifiers>
78
79</ecore:EPackage>

Step 2

Create a complex model instance.

This model contains multiple organisations with overlapping projects, shared resources, and complex team structures. Perfect for demonstrating advanced query patterns.

enterprise-data.xmi
1<?xml version="1.0" encoding="UTF-8"?>
2<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns:enterprise="http://www.example.org/enterprise">
4
5 <enterprise:Organisation name="Acme Technologies" founded="1995" headquarters="Melbourne">
6
7 <!-- Engineering Department with sub-departments -->
8 <departments name="Engineering" code="ENG" budget="2500000.0" location="Melbourne"
9 manager="//@departments.0/@employees.0"
10 collaboratesWith="//@departments.1 //@departments.2">
11
12 <employees name="Sarah Mitchell" employeeId="E001" salary="185000.0" yearsOfService="12"
13 role="Engineering Director" skills="Leadership Strategy Architecture"
14 assignedProjects="//@projects.0 //@projects.1"/>
15
16 <employees name="James Wong" employeeId="E002" salary="145000.0" yearsOfService="8"
17 role="Senior Engineer" skills="Swift Kotlin Architecture"
18 supervisor="//@departments.0/@employees.0"
19 assignedProjects="//@projects.0"
20 mentors="//@departments.0/@employees.0"/>
21
22 <employees name="Emily Chen" employeeId="E003" salary="125000.0" yearsOfService="5"
23 role="Software Engineer" skills="Swift Python Testing"
24 supervisor="//@departments.0/@employees.1"
25 assignedProjects="//@projects.0 //@projects.2"/>
26
27 <employees name="Michael Brown" employeeId="E004" salary="115000.0" yearsOfService="3"
28 role="Junior Engineer" skills="Swift JavaScript"
29 supervisor="//@departments.0/@employees.1"
30 assignedProjects="//@projects.2"
31 mentors="//@departments.0/@employees.1 //@departments.0/@employees.2"/>
32
33 <!-- Platform Team sub-department -->
34 <subDepartments name="Platform Team" code="ENG-PLT" budget="800000.0" location="Melbourne"
35 manager="//@departments.0/@subDepartments.0/@employees.0">
36
37 <employees name="David Lee" employeeId="E005" salary="155000.0" yearsOfService="10"
38 role="Platform Lead" skills="Infrastructure Cloud Kubernetes"
39 assignedProjects="//@projects.1"/>
40
41 <employees name="Anna Kowalski" employeeId="E006" salary="130000.0" yearsOfService="6"
42 role="Platform Engineer" skills="Docker Terraform AWS"
43 supervisor="//@departments.0/@subDepartments.0/@employees.0"
44 assignedProjects="//@projects.1"/>
45
46 <employees name="Tom Nguyen" employeeId="E007" salary="110000.0" yearsOfService="2"
47 role="DevOps Engineer" skills="CI/CD Monitoring"
48 supervisor="//@departments.0/@subDepartments.0/@employees.0"
49 assignedProjects="//@projects.1"
50 mentors="//@departments.0/@subDepartments.0/@employees.1"/>
51 </subDepartments>
52
53 <!-- Mobile Team sub-department -->
54 <subDepartments name="Mobile Team" code="ENG-MOB" budget="600000.0" location="Sydney"
55 manager="//@departments.0/@subDepartments.1/@employees.0">
56
57 <employees name="Rachel Adams" employeeId="E008" salary="150000.0" yearsOfService="9"
58 role="Mobile Lead" skills="iOS Android SwiftUI"
59 assignedProjects="//@projects.0 //@projects.2"/>
60
61 <employees name="Chris Taylor" employeeId="E009" salary="120000.0" yearsOfService="4"
62 role="iOS Developer" skills="Swift SwiftUI UIKit"
63 supervisor="//@departments.0/@subDepartments.1/@employees.0"
64 assignedProjects="//@projects.0"/>
65
66 <employees name="Linda Park" employeeId="E010" salary="118000.0" yearsOfService="3"
67 role="Android Developer" skills="Kotlin Compose"
68 supervisor="//@departments.0/@subDepartments.1/@employees.0"
69 assignedProjects="//@projects.2"
70 mentors="//@departments.0/@subDepartments.1/@employees.0"/>
71 </subDepartments>
72 </departments>
73
74 <!-- Product Department -->
75 <departments name="Product" code="PROD" budget="1200000.0" location="Melbourne"
76 manager="//@departments.1/@employees.0"
77 collaboratesWith="//@departments.0 //@departments.2">
78
79 <employees name="Jessica Moore" employeeId="E011" salary="170000.0" yearsOfService="11"
80 role="Product Director" skills="Strategy Roadmap Analytics"
81 assignedProjects="//@projects.0 //@projects.2 //@projects.3"/>
82
83 <employees name="Daniel Kim" employeeId="E012" salary="135000.0" yearsOfService="7"
84 role="Senior Product Manager" skills="UserResearch Agile"
85 supervisor="//@departments.1/@employees.0"
86 assignedProjects="//@projects.0"/>
87
88 <employees name="Sophie Garcia" employeeId="E013" salary="110000.0" yearsOfService="4"
89 role="Product Manager" skills="Analytics Design"
90 supervisor="//@departments.1/@employees.0"
91 assignedProjects="//@projects.2 //@projects.3"
92 mentors="//@departments.1/@employees.1"/>
93
94 <employees name="Ryan Hughes" employeeId="E014" salary="95000.0" yearsOfService="2"
95 role="Associate Product Manager" skills="Research Documentation"
96 supervisor="//@departments.1/@employees.1"
97 assignedProjects="//@projects.3"
98 mentors="//@departments.1/@employees.1 //@departments.1/@employees.2"/>
99 </departments>
100
101 <!-- Design Department -->
102 <departments name="Design" code="DES" budget="900000.0" location="Sydney"
103 manager="//@departments.2/@employees.0"
104 collaboratesWith="//@departments.0 //@departments.1">
105
106 <employees name="Olivia Martinez" employeeId="E015" salary="160000.0" yearsOfService="10"
107 role="Design Director" skills="Leadership UX BrandStrategy"
108 assignedProjects="//@projects.0 //@projects.2"/>
109
110 <employees name="Nathan Scott" employeeId="E016" salary="125000.0" yearsOfService="6"
111 role="Senior UX Designer" skills="Figma UserResearch Prototyping"
112 supervisor="//@departments.2/@employees.0"
113 assignedProjects="//@projects.0"/>
114
115 <employees name="Mia Thompson" employeeId="E017" salary="105000.0" yearsOfService="3"
116 role="UI Designer" skills="Figma Sketch Illustration"
117 supervisor="//@departments.2/@employees.0"
118 assignedProjects="//@projects.2"
119 mentors="//@departments.2/@employees.1"/>
120
121 <employees name="Alex Rivera" employeeId="E018" salary="90000.0" yearsOfService="1"
122 role="Junior Designer" skills="Figma Basics"
123 supervisor="//@departments.2/@employees.1"
124 assignedProjects="//@projects.2"
125 mentors="//@departments.2/@employees.1 //@departments.2/@employees.2"/>
126 </departments>
127
128 <!-- Operations Department -->
129 <departments name="Operations" code="OPS" budget="700000.0" location="Brisbane"
130 manager="//@departments.3/@employees.0">
131
132 <employees name="William Anderson" employeeId="E019" salary="150000.0" yearsOfService="14"
133 role="Operations Director" skills="ProcessOptimisation SupplyChain"/>
134
135 <employees name="Emma Wilson" employeeId="E020" salary="115000.0" yearsOfService="8"
136 role="Operations Manager" skills="ProjectManagement Logistics"
137 supervisor="//@departments.3/@employees.0"/>
138
139 <employees name="Jack Robinson" employeeId="E021" salary="85000.0" yearsOfService="2"
140 role="Operations Analyst" skills="DataAnalysis Reporting"
141 supervisor="//@departments.3/@employees.1"
142 mentors="//@departments.3/@employees.1"/>
143 </departments>
144
145 <!-- Projects -->
146 <projects name="Customer Portal" code="PRJ-001" budget="450000.0" status="Active"
147 priority="1" startDate="2024-01-15" endDate="2024-09-30"
148 teamMembers="//@departments.0/@employees.0 //@departments.0/@employees.1 //@departments.0/@employees.2 //@departments.0/@subDepartments.1/@employees.0 //@departments.0/@subDepartments.1/@employees.1 //@departments.1/@employees.0 //@departments.1/@employees.1 //@departments.2/@employees.0 //@departments.2/@employees.1"
149 leadDepartment="//@departments.0">
150 <milestones name="Requirements Complete" dueDate="2024-02-28" completed="true"
151 description="All requirements gathered and approved"/>
152 <milestones name="Design Finalised" dueDate="2024-04-15" completed="true"
153 description="UI/UX designs approved by stakeholders"/>
154 <milestones name="Beta Release" dueDate="2024-07-01" completed="false"
155 description="Beta version released for testing"/>
156 <milestones name="Production Launch" dueDate="2024-09-30" completed="false"
157 description="Full production deployment"/>
158 </projects>
159
160 <projects name="Infrastructure Modernisation" code="PRJ-002" budget="320000.0" status="Active"
161 priority="2" startDate="2024-03-01" endDate="2024-12-15"
162 teamMembers="//@departments.0/@employees.0 //@departments.0/@subDepartments.0/@employees.0 //@departments.0/@subDepartments.0/@employees.1 //@departments.0/@subDepartments.0/@employees.2"
163 leadDepartment="//@departments.0/@subDepartments.0"
164 dependencies="//@projects.0">
165 <milestones name="Assessment Complete" dueDate="2024-04-30" completed="true"
166 description="Current infrastructure assessed"/>
167 <milestones name="Migration Plan" dueDate="2024-06-30" completed="true"
168 description="Detailed migration plan approved"/>
169 <milestones name="Cloud Migration" dueDate="2024-10-31" completed="false"
170 description="Services migrated to cloud"/>
171 </projects>
172
173 <projects name="Mobile App Redesign" code="PRJ-003" budget="280000.0" status="Active"
174 priority="1" startDate="2024-02-01" endDate="2024-08-31"
175 teamMembers="//@departments.0/@employees.2 //@departments.0/@employees.3 //@departments.0/@subDepartments.1/@employees.0 //@departments.0/@subDepartments.1/@employees.2 //@departments.1/@employees.0 //@departments.1/@employees.2 //@departments.2/@employees.0 //@departments.2/@employees.2 //@departments.2/@employees.3"
176 leadDepartment="//@departments.0/@subDepartments.1">
177 <milestones name="User Research" dueDate="2024-03-15" completed="true"
178 description="User research and feedback collected"/>
179 <milestones name="Design System" dueDate="2024-05-01" completed="true"
180 description="New design system established"/>
181 <milestones name="App Store Release" dueDate="2024-08-31" completed="false"
182 description="New app version in stores"/>
183 </projects>
184
185 <projects name="Analytics Dashboard" code="PRJ-004" budget="150000.0" status="Planning"
186 priority="3" startDate="2024-06-01" endDate="2024-11-30"
187 teamMembers="//@departments.1/@employees.0 //@departments.1/@employees.2 //@departments.1/@employees.3"
188 leadDepartment="//@departments.1"
189 dependencies="//@projects.0 //@projects.1">
190 <milestones name="Requirements Gathering" dueDate="2024-07-15" completed="false"
191 description="Dashboard requirements defined"/>
192 <milestones name="Prototype" dueDate="2024-09-01" completed="false"
193 description="Interactive prototype ready"/>
194 </projects>
195
196 </enterprise:Organisation>
197</xmi:XMI>

Step 3

Use simple let bindings for intermediate results.

Let bindings store query results in variables for reuse. This avoids repeated computation and makes complex queries more readable.

Terminal
1# Simple let bindings for complex queries
2# Bind intermediate results to named variables for clarity
3
4# Basic let binding - calculate average salary
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let allEmployees = organisation.departments.employees->flatten()
7 in allEmployees->collect(e | e.salary)->sum() / allEmployees->size()"
8
9# Output: 128571.43 (average salary across all direct department employees)
10
11# Multiple let bindings - compare department sizes
12swift-aql evaluate --model enterprise-data.xmi \
13 --expression "let eng = organisation.departments->select(d | d.code = 'ENG')->first(),
14 prod = organisation.departments->select(d | d.code = 'PROD')->first()
15 in Tuple{engineering = eng.employees->size(), product = prod.employees->size()}"
16
17# Output: {engineering: 4, product: 4}
18
19# Let with nested navigation
20swift-aql evaluate --model enterprise-data.xmi \
21 --expression "let seniorStaff = organisation.departments.employees
22 ->flatten()
23 ->select(e | e.yearsOfService >= 10)
24 in seniorStaff->collect(e | e.name)"
25
26# Output: ["Sarah Mitchell", "David Lee", "Jessica Moore", "Olivia Martinez", "William Anderson"]
27
28# Let binding for reusable predicates
29swift-aql evaluate --model enterprise-data.xmi \
30 --expression "let threshold = 130000.0,
31 highEarners = organisation.departments.employees
32 ->flatten()
33 ->select(e | e.salary >= threshold)
34 in Tuple{count = highEarners->size(),
35 totalCost = highEarners->collect(e | e.salary)->sum()}"
36
37# Output: {count: 7, totalCost: 1100000.0}

Step 4

Chain multiple let bindings.

Build complex queries by chaining let bindings together. Each binding can use variables from previous bindings, creating step-by-step query construction.

Terminal
1# Nested let bindings for layered calculations
2# Build complex queries step by step
3
4# Nested let for multi-stage calculation
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let depts = organisation.departments in
7 let employees = depts.employees->flatten() in
8 let avgSalary = employees->collect(e | e.salary)->sum() / employees->size() in
9 let aboveAvg = employees->select(e | e.salary > avgSalary)
10 in Tuple{average = avgSalary,
11 aboveAverageCount = aboveAvg->size(),
12 aboveAverageNames = aboveAvg->collect(e | e.name)}"
13
14# Output: {average: 128571.43, aboveAverageCount: 8, aboveAverageNames: [...]}
15
16# Nested let for department analysis
17swift-aql evaluate --model enterprise-data.xmi \
18 --expression "let dept = organisation.departments->select(d | d.code = 'ENG')->first() in
19 let directEmployees = dept.employees in
20 let subDeptEmployees = dept.subDepartments.employees->flatten() in
21 let allEmployees = directEmployees->union(subDeptEmployees)
22 in Tuple{direct = directEmployees->size(),
23 subDept = subDeptEmployees->size(),
24 total = allEmployees->size()}"
25
26# Output: {direct: 4, subDept: 6, total: 10}
27
28# Nested let for project metrics
29swift-aql evaluate --model enterprise-data.xmi \
30 --expression "let activeProjects = organisation.projects->select(p | p.status = 'Active') in
31 let totalBudget = activeProjects->collect(p | p.budget)->sum() in
32 let avgTeamSize = activeProjects->collect(p | p.teamMembers->size())->sum()
33 / activeProjects->size()
34 in Tuple{activeCount = activeProjects->size(),
35 totalBudget = totalBudget,
36 averageTeamSize = avgTeamSize}"
37
38# Output: {activeCount: 3, totalBudget: 1050000.0, averageTeamSize: 8}
39
40# Deeply nested let for complex reporting
41swift-aql evaluate --model enterprise-data.xmi \
42 --expression "let org = organisation in
43 let depts = org.departments in
44 let engDept = depts->select(d | d.code = 'ENG')->first() in
45 let engBudget = engDept.budget in
46 let subBudgets = engDept.subDepartments->collect(d | d.budget)->sum()
47 in Tuple{departmentBudget = engBudget,
48 subDepartmentBudgets = subBudgets,
49 totalEngineeringBudget = engBudget + subBudgets}"
50
51# Output: {departmentBudget: 2500000.0, subDepartmentBudgets: 1400000.0, totalEngineeringBudget: 3900000.0}

Section 2

Nested Iterations and Cross-Products

Advanced queries often require nested iterations to explore all combinations of model elements. These patterns are essential for relationship analysis, validation, and comprehensive model inspection.

Nested iterations create cross-products between collections, allowing you to analyze relationships between elements from different parts of the model.

Step 1

Create nested iterations for relationship analysis.

Use nested collection operations to explore relationships between elements from different collections. This enables comprehensive cross-analysis.

Terminal
1# Nested iteration patterns
2# Iterate over multiple collections simultaneously
3
4# Nested select for complex filtering
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.departments
7 ->select(d | d.employees->exists(e | e.yearsOfService >= 10))
8 ->collect(d | Tuple{department = d.name,
9 seniors = d.employees
10 ->select(e | e.yearsOfService >= 10)
11 ->collect(e | e.name)})"
12
13# Output: [{department: "Engineering", seniors: ["Sarah Mitchell"]},
14# {department: "Product", seniors: ["Jessica Moore"]}, ...]
15
16# Nested iteration with forAll
17swift-aql evaluate --model enterprise-data.xmi \
18 --expression "organisation.departments
19 ->select(d | d.employees->forAll(e | e.salary >= 100000))
20 ->collect(d | d.name)"
21
22# Output: ["Engineering", "Product", "Design"] (all have employees earning >= 100k)
23
24# Double iteration for relationship analysis
25swift-aql evaluate --model enterprise-data.xmi \
26 --expression "organisation.departments.employees->flatten()
27 ->select(e | e.supervisor <> null)
28 ->collect(e | Tuple{employee = e.name,
29 supervisor = e.supervisor.name,
30 sameDepartment = e.eContainer() = e.supervisor.eContainer()})"
31
32# Output: [{employee: "James Wong", supervisor: "Sarah Mitchell", sameDepartment: true}, ...]
33
34# Nested iteration over projects and employees
35swift-aql evaluate --model enterprise-data.xmi \
36 --expression "organisation.projects
37 ->collect(p | Tuple{project = p.name,
38 departments = p.teamMembers
39 ->collect(e | e.eContainer().name)
40 ->asSet()})"
41
42# Output: [{project: "Customer Portal", departments: ["Engineering", "Product", "Design", ...]}, ...]
43
44# Nested exists with multiple levels
45swift-aql evaluate --model enterprise-data.xmi \
46 --expression "organisation.departments
47 ->select(d | d.subDepartments->exists(sd |
48 sd.employees->exists(e | e.yearsOfService >= 8)))
49 ->collect(d | d.name)"
50
51# Output: ["Engineering"] (has sub-departments with experienced employees)

Step 2

Build cross-product queries.

Generate all combinations of elements from multiple collections to analyze potential relationships and conflicts across the model.

Terminal
1# Cross-product operations
2# Combine elements from multiple collections
3
4# All pairs of departments that collaborate
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.departments
7 ->select(d | d.collaboratesWith->notEmpty())
8 ->collect(d | d.collaboratesWith
9 ->collect(c | Tuple{from = d.name, to = c.name}))
10 ->flatten()"
11
12# Output: [{from: "Engineering", to: "Product"}, {from: "Engineering", to: "Design"},
13# {from: "Product", to: "Engineering"}, {from: "Product", to: "Design"}, ...]
14
15# Cross-product: employees who could mentor each other (different departments)
16swift-aql evaluate --model enterprise-data.xmi \
17 --expression "let seniors = organisation.departments.employees->flatten()
18 ->select(e | e.yearsOfService >= 8),
19 juniors = organisation.departments.employees->flatten()
20 ->select(e | e.yearsOfService <= 3)
21 in seniors->collect(s |
22 juniors->select(j | j.eContainer() <> s.eContainer())
23 ->collect(j | Tuple{mentor = s.name, mentee = j.name}))
24 ->flatten()
25 ->select(p | true)" -- limit output
26
27# Output: [{mentor: "Sarah Mitchell", mentee: "Tom Nguyen"}, ...]
28
29# Cartesian product of projects and departments
30swift-aql evaluate --model enterprise-data.xmi \
31 --expression "organisation.projects
32 ->collect(p | organisation.departments
33 ->collect(d | Tuple{project = p.name,
34 department = d.name,
35 involved = p.teamMembers
36 ->exists(e | e.eContainer() = d or
37 d.subDepartments.employees
38 ->flatten()->includes(e))}))
39 ->flatten()
40 ->select(t | t.involved)"
41
42# Output: [{project: "Customer Portal", department: "Engineering", involved: true}, ...]
43
44# Find all possible skill pairs in the organisation
45swift-aql evaluate --model enterprise-data.xmi \
46 --expression "let allSkills = organisation.departments.employees
47 ->flatten()
48 ->collect(e | e.skills)
49 ->flatten()
50 ->asSet()
51 in allSkills->collect(s1 |
52 allSkills->select(s2 | s1 < s2)
53 ->collect(s2 | Tuple{skill1 = s1, skill2 = s2}))
54 ->flatten()
55 ->select(p | true)->subSequence(1, 10)" -- first 10 pairs
56
57# Output: [{skill1: "Architecture", skill2: "Kotlin"}, ...]

Step 3

Filter cross-products with complex conditions.

Apply sophisticated filtering to cross-products to find specific relationship patterns or constraint violations across model elements.

Terminal
1# Cross-model navigation patterns
2# Navigate relationships across different model elements
3
4# From project to all related departments (via team members)
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.projects
7 ->collect(p | Tuple{
8 project = p.name,
9 leadDept = p.leadDepartment.name,
10 involvedDepts = p.teamMembers
11 ->collect(e | e.eContainer())
12 ->asSet()
13 ->collect(d | d.name)})"
14
15# Output: [{project: "Customer Portal", leadDept: "Engineering",
16# involvedDepts: ["Engineering", "Platform Team", "Mobile Team", "Product", "Design"]}]
17
18# From employee to all projects in their department
19swift-aql evaluate --model enterprise-data.xmi \
20 --expression "organisation.departments->select(d | d.code = 'PROD')->first()
21 .employees
22 ->collect(e | Tuple{
23 employee = e.name,
24 ownProjects = e.assignedProjects->collect(p | p.name),
25 deptProjects = organisation.projects
26 ->select(p | p.leadDepartment = e.eContainer())
27 ->collect(p | p.name)})"
28
29# Output: [{employee: "Jessica Moore", ownProjects: [...], deptProjects: ["Analytics Dashboard"]}]
30
31# Navigate from milestone to responsible employees
32swift-aql evaluate --model enterprise-data.xmi \
33 --expression "organisation.projects.milestones
34 ->flatten()
35 ->select(m | not m.completed)
36 ->collect(m | Tuple{
37 milestone = m.name,
38 project = m.eContainer().name,
39 responsibleTeam = m.eContainer().teamMembers
40 ->collect(e | e.name)})"
41
42# Output: [{milestone: "Beta Release", project: "Customer Portal", responsibleTeam: [...]}, ...]
43
44# Cross-reference: find collaborating department employees on same project
45swift-aql evaluate --model enterprise-data.xmi \
46 --expression "let project = organisation.projects->first() in
47 project.leadDepartment.collaboratesWith
48 ->collect(collabDept | Tuple{
49 department = collabDept.name,
50 teamMembersFromDept = project.teamMembers
51 ->select(e | e.eContainer() = collabDept
52 or collabDept.subDepartments->includes(e.eContainer()))
53 ->collect(e | e.name)})"
54
55# Output: [{department: "Product", teamMembersFromDept: ["Jessica Moore", "Daniel Kim"]},
56# {department: "Design", teamMembersFromDept: ["Olivia Martinez", "Nathan Scott"]}]
57
58# Navigate bidirectional relationships
59swift-aql evaluate --model enterprise-data.xmi \
60 --expression "organisation.departments.employees->flatten()
61 ->select(e | e.directReports->notEmpty())
62 ->collect(e | Tuple{
63 manager = e.name,
64 directReports = e.directReports->collect(r | r.name),
65 theirProjects = e.directReports.assignedProjects
66 ->flatten()
67 ->asSet()
68 ->collect(p | p.name)})"
69
70# Output: [{manager: "Sarah Mitchell", directReports: ["James Wong"], theirProjects: [...]}]

Step 4

Optimise nested queries for performance.

Use efficient query patterns to minimise computation in nested iterations. Order operations to filter early and reduce unnecessary processing.

Terminal
1# Query composition patterns
2# Build complex queries from simpler components
3
4# Compose filtering and transformation
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let activeHighPriority = organisation.projects
7 ->select(p | p.status = 'Active')
8 ->select(p | p.priority <= 2)
9 in activeHighPriority
10 ->collect(p | Tuple{
11 name = p.name,
12 budget = p.budget,
13 teamSize = p.teamMembers->size(),
14 costPerMember = p.budget / p.teamMembers->size()})"
15
16# Output: [{name: "Customer Portal", budget: 450000, teamSize: 9, costPerMember: 50000}, ...]
17
18# Compose aggregation queries
19swift-aql evaluate --model enterprise-data.xmi \
20 --expression "let deptStats = organisation.departments
21 ->collect(d | Tuple{
22 name = d.name,
23 employeeCount = d.employees->size(),
24 avgSalary = d.employees->collect(e | e.salary)->sum()
25 / d.employees->size(),
26 totalBudget = d.budget})
27 in Tuple{
28 departments = deptStats,
29 totalEmployees = deptStats->collect(s | s.employeeCount)->sum(),
30 overallAvgSalary = deptStats->collect(s | s.avgSalary)->sum()
31 / deptStats->size()}"
32
33# Output: {departments: [...], totalEmployees: 16, overallAvgSalary: 127500}
34
35# Compose navigation with filtering
36swift-aql evaluate --model enterprise-data.xmi \
37 --expression "let experiencedEngineers = organisation.departments
38 ->select(d | d.code = 'ENG' or d.code.startsWith('ENG-'))
39 .employees
40 ->flatten()
41 ->select(e | e.yearsOfService >= 5),
42 projectsWithExperts = organisation.projects
43 ->select(p | p.teamMembers
44 ->intersection(experiencedEngineers)->notEmpty())
45 in projectsWithExperts->collect(p | Tuple{
46 project = p.name,
47 expertCount = p.teamMembers
48 ->intersection(experiencedEngineers)->size()})"
49
50# Output: [{project: "Customer Portal", expertCount: 4}, ...]
51
52# Multi-stage composition for complex analysis
53swift-aql evaluate --model enterprise-data.xmi \
54 --expression "let allEmps = organisation.departments.employees->flatten()
55 in let seniorEmps = allEmps->select(e | e.yearsOfService >= 10)
56 in let juniorEmps = allEmps->select(e | e.yearsOfService <= 2)
57 in let mentorPairs = seniorEmps
58 ->collect(s | juniorEmps
59 ->select(j | j.mentors->includes(s))
60 ->collect(j | Tuple{mentor = s.name, mentee = j.name}))
61 ->flatten()
62 in Tuple{totalMentorships = mentorPairs->size(),
63 pairs = mentorPairs}"
64
65# Output: {totalMentorships: 2, pairs: [{mentor: "...", mentee: "..."}, ...]}
66
67# Compose conditional logic
68swift-aql evaluate --model enterprise-data.xmi \
69 --expression "organisation.projects
70 ->collect(p |
71 let status = if p.milestones->forAll(m | m.completed)
72 then 'Complete'
73 else if p.milestones->exists(m | m.completed)
74 then 'In Progress'
75 else 'Not Started' endif endif
76 in Tuple{project = p.name,
77 derivedStatus = status,
78 completedMilestones = p.milestones
79 ->select(m | m.completed)->size(),
80 totalMilestones = p.milestones->size()})"
81
82# Output: [{project: "Customer Portal", derivedStatus: "In Progress", ...}, ...]

Section 3

Cross-Model Navigation

Real-world modeling scenarios often involve multiple related models. AQL can navigate across model boundaries through references and shared elements.

Cross-model queries enable comprehensive analysis that spans multiple model files, supporting complex enterprise scenarios and distributed model architectures.

Step 1

Set up related models for cross-model queries.

Create multiple related model files that reference each other. This simulates real-world scenarios where models are distributed across multiple files.

setup-cross-models.sh
1# Pattern matching in queries
2# Identify specific patterns and structures in models
3
4# Find employees matching supervision pattern (manager -> reports)
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.departments.employees->flatten()
7 ->select(e | e.directReports->size() >= 2)
8 ->collect(e | Tuple{
9 manager = e.name,
10 role = e.role,
11 reportCount = e.directReports->size(),
12 reports = e.directReports->collect(r | r.name)})"
13
14# Output: [{manager: "James Wong", role: "Senior Engineer", reportCount: 2, reports: [...]}]
15
16# Match mentorship chains (mentor -> mentee -> mentee)
17swift-aql evaluate --model enterprise-data.xmi \
18 --expression "organisation.departments.employees->flatten()
19 ->select(e | e.mentors->notEmpty())
20 ->collect(e | Tuple{
21 mentee = e.name,
22 directMentors = e.mentors->collect(m | m.name),
23 grandMentors = e.mentors.mentors->flatten()->asSet()->collect(m | m.name)})"
24
25# Output: [{mentee: "Michael Brown", directMentors: ["James Wong", "Emily Chen"],
26# grandMentors: ["Sarah Mitchell"]}]
27
28# Pattern: find circular collaboration (A collaborates with B, B with A)
29swift-aql evaluate --model enterprise-data.xmi \
30 --expression "organisation.departments
31 ->select(d | d.collaboratesWith->exists(c | c.collaboratesWith->includes(d)))
32 ->collect(d | Tuple{
33 department = d.name,
34 bidirectionalPartners = d.collaboratesWith
35 ->select(c | c.collaboratesWith->includes(d))
36 ->collect(c | c.name)})"
37
38# Output: [{department: "Engineering", bidirectionalPartners: ["Product", "Design"]}]
39
40# Pattern: project dependency chains
41swift-aql evaluate --model enterprise-data.xmi \
42 --expression "organisation.projects
43 ->select(p | p.dependencies->notEmpty())
44 ->collect(p | Tuple{
45 project = p.name,
46 directDeps = p.dependencies->collect(d | d.name),
47 transitiveDeps = p.dependencies.dependencies
48 ->flatten()->asSet()->collect(d | d.name)})"
49
50# Output: [{project: "Analytics Dashboard", directDeps: ["Customer Portal", "Infrastructure..."],
51# transitiveDeps: ["Customer Portal"]}]
52
53# Pattern: employees with cross-departmental project involvement
54swift-aql evaluate --model enterprise-data.xmi \
55 --expression "organisation.departments.employees->flatten()
56 ->select(e | e.assignedProjects
57 ->collect(p | p.leadDepartment)
58 ->asSet()
59 ->select(d | d <> e.eContainer())
60 ->notEmpty())
61 ->collect(e | Tuple{
62 employee = e.name,
63 homeDept = e.eContainer().name,
64 crossDeptProjects = e.assignedProjects
65 ->select(p | p.leadDepartment <> e.eContainer())
66 ->collect(p | p.name)})"
67
68# Output: [{employee: "Emily Chen", homeDept: "Engineering",
69# crossDeptProjects: ["Mobile App Redesign"]}]
70
71# Pattern: find managers who also mentor
72swift-aql evaluate --model enterprise-data.xmi \
73 --expression "organisation.departments.employees->flatten()
74 ->select(e | e.directReports->notEmpty() and
75 organisation.departments.employees->flatten()
76 ->exists(emp | emp.mentors->includes(e)))
77 ->collect(e | Tuple{
78 managerMentor = e.name,
79 directReports = e.directReports->collect(r | r.name),
80 mentees = organisation.departments.employees
81 ->flatten()
82 ->select(emp | emp.mentors->includes(e))
83 ->collect(emp | emp.name)})"
84
85# Output: [{managerMentor: "James Wong", directReports: [...], mentees: ["Michael Brown"]}]

Step 2

Navigate between models through references.

Use AQL to navigate from elements in one model to related elements in other models. This enables queries that span multiple model files.

Terminal
1# Type-based pattern matching
2# Query based on element types and class hierarchy
3
4# Find all elements of a specific type using oclIsKindOf
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.eAllContents()
7 ->select(e | e.oclIsKindOf(Employee))
8 ->size()"
9
10# Output: 21 (total employees across all departments and sub-departments)
11
12# Group elements by type
13swift-aql evaluate --model enterprise-data.xmi \
14 --expression "let contents = organisation.eAllContents()
15 in Tuple{
16 departments = contents->select(e | e.oclIsKindOf(Department))->size(),
17 employees = contents->select(e | e.oclIsKindOf(Employee))->size(),
18 projects = contents->select(e | e.oclIsKindOf(Project))->size(),
19 milestones = contents->select(e | e.oclIsKindOf(Milestone))->size()}"
20
21# Output: {departments: 6, employees: 21, projects: 4, milestones: 12}
22
23# Type-safe navigation using oclAsType
24swift-aql evaluate --model enterprise-data.xmi \
25 --expression "organisation.departments->first()
26 .eAllContents()
27 ->select(e | e.oclIsKindOf(Employee))
28 ->collect(e | e.oclAsType(Employee).name)"
29
30# Output: ["Sarah Mitchell", "James Wong", "Emily Chen", "Michael Brown", ...]
31
32# Find elements by metaclass name
33swift-aql evaluate --model enterprise-data.xmi \
34 --expression "organisation.eAllContents()
35 ->select(e | e.eClass().name = 'Milestone')
36 ->collect(e | Tuple{
37 milestone = e.oclAsType(Milestone).name,
38 completed = e.oclAsType(Milestone).completed})"
39
40# Output: [{milestone: "Requirements Complete", completed: true}, ...]
41
42# Pattern: find all containers of a specific type
43swift-aql evaluate --model enterprise-data.xmi \
44 --expression "organisation.eAllContents()
45 ->select(e | e.oclIsKindOf(Employee))
46 ->collect(e | e.eContainer())
47 ->asSet()
48 ->collect(c | Tuple{
49 containerType = c.eClass().name,
50 name = if c.oclIsKindOf(Department)
51 then c.oclAsType(Department).name
52 else 'Unknown' endif})"
53
54# Output: [{containerType: "Department", name: "Engineering"}, ...]
55
56# Validate type constraints
57swift-aql evaluate --model enterprise-data.xmi \
58 --expression "organisation.projects->forAll(p |
59 p.teamMembers->forAll(m | m.oclIsKindOf(Employee)) and
60 p.leadDepartment.oclIsKindOf(Department))"
61
62# Output: true (all type constraints satisfied)
63
64# Find mismatched references (type checking)
65swift-aql evaluate --model enterprise-data.xmi \
66 --expression "organisation.departments.employees->flatten()
67 ->select(e | e.supervisor <> null)
68 ->forAll(e | e.supervisor.oclIsKindOf(Employee))"
69
70# Output: true (all supervisors are valid Employee types)

Step 3

Query across model hierarchies.

Build queries that traverse model hierarchies across files, analyzing relationships between parent and child models in complex architectures.

Terminal
1# Basic statistical analysis
2# Calculate descriptive statistics on model data
3
4# Calculate mean salary
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let salaries = organisation.departments.employees
7 ->flatten()
8 ->collect(e | e.salary)
9 in salaries->sum() / salaries->size()"
10
11# Output: 127142.86 (mean salary)
12
13# Calculate min, max, range
14swift-aql evaluate --model enterprise-data.xmi \
15 --expression "let salaries = organisation.departments.employees
16 ->flatten()
17 ->collect(e | e.salary)
18 in Tuple{
19 minimum = salaries->min(),
20 maximum = salaries->max(),
21 range = salaries->max() - salaries->min()}"
22
23# Output: {minimum: 85000.0, maximum: 185000.0, range: 100000.0}
24
25# Count and distribution by role
26swift-aql evaluate --model enterprise-data.xmi \
27 --expression "let employees = organisation.departments.employees->flatten()
28 in let roles = employees->collect(e | e.role)->asSet()
29 in roles->collect(r | Tuple{
30 role = r,
31 count = employees->select(e | e.role = r)->size(),
32 avgSalary = employees->select(e | e.role = r)
33 ->collect(e | e.salary)->sum()
34 / employees->select(e | e.role = r)->size()})"
35
36# Output: [{role: "Engineering Director", count: 1, avgSalary: 185000.0}, ...]
37
38# Percentile approximation (count below threshold)
39swift-aql evaluate --model enterprise-data.xmi \
40 --expression "let salaries = organisation.departments.employees
41 ->flatten()
42 ->collect(e | e.salary)->sortedBy(s | s)
43 in let total = salaries->size()
44 in Tuple{
45 below100k = salaries->select(s | s < 100000)->size() * 100 / total,
46 below120k = salaries->select(s | s < 120000)->size() * 100 / total,
47 below150k = salaries->select(s | s < 150000)->size() * 100 / total}"
48
49# Output: {below100k: 19, below120k: 47, below150k: 76} (percentiles)
50
51# Variance calculation (simplified)
52swift-aql evaluate --model enterprise-data.xmi \
53 --expression "let salaries = organisation.departments.employees
54 ->flatten()->collect(e | e.salary),
55 mean = salaries->sum() / salaries->size()
56 in let squaredDiffs = salaries
57 ->collect(s | (s - mean) * (s - mean))
58 in Tuple{
59 mean = mean,
60 variance = squaredDiffs->sum() / salaries->size()}"
61
62# Output: {mean: 127142.86, variance: 612244897.96} (population variance)
63
64# Department budget utilisation
65swift-aql evaluate --model enterprise-data.xmi \
66 --expression "organisation.departments
67 ->collect(d | let empCost = d.employees->collect(e | e.salary)->sum()
68 in Tuple{
69 department = d.name,
70 budget = d.budget,
71 employeeCost = empCost,
72 utilisation = (empCost / d.budget) * 100})"
73
74# Output: [{department: "Engineering", budget: 2500000.0, employeeCost: 570000.0, utilisation: 22.8}]

Step 4

Validate cross-model consistency.

Use cross-model queries to validate consistency and integrity constraints that span multiple model files, ensuring system-wide correctness.

Terminal
1# Advanced statistical analysis
2# Complex calculations and comparisons
3
4# Median approximation (sorted middle value)
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let salaries = organisation.departments.employees
7 ->flatten()
8 ->collect(e | e.salary)
9 ->sortedBy(s | s)
10 in let size = salaries->size()
11 in if size.mod(2) = 0
12 then (salaries->at(size / 2) + salaries->at(size / 2 + 1)) / 2
13 else salaries->at((size + 1) / 2)
14 endif"
15
16# Output: 120000.0 (median salary)
17
18# Correlation indicator: experience vs salary
19swift-aql evaluate --model enterprise-data.xmi \
20 --expression "let employees = organisation.departments.employees->flatten()
21 in let avgExp = employees->collect(e | e.yearsOfService)->sum() / employees->size(),
22 avgSal = employees->collect(e | e.salary)->sum() / employees->size()
23 in let highExpHighSal = employees
24 ->select(e | e.yearsOfService > avgExp and e.salary > avgSal)->size(),
25 lowExpLowSal = employees
26 ->select(e | e.yearsOfService <= avgExp and e.salary <= avgSal)->size()
27 in Tuple{
28 positiveCorrelation = highExpHighSal + lowExpLowSal,
29 negativeCorrelation = employees->size() - highExpHighSal - lowExpLowSal,
30 correlationIndicator = (highExpHighSal + lowExpLowSal) * 100 / employees->size()}"
31
32# Output: {positiveCorrelation: 12, negativeCorrelation: 9, correlationIndicator: 57}
33
34# Salary quartile analysis
35swift-aql evaluate --model enterprise-data.xmi \
36 --expression "let salaries = organisation.departments.employees
37 ->flatten()
38 ->collect(e | e.salary)
39 ->sortedBy(s | s),
40 q1Index = salaries->size() / 4,
41 q2Index = salaries->size() / 2,
42 q3Index = salaries->size() * 3 / 4
43 in Tuple{
44 q1 = salaries->at(q1Index.max(1)),
45 median = salaries->at(q2Index.max(1)),
46 q3 = salaries->at(q3Index.max(1)),
47 iqr = salaries->at(q3Index.max(1)) - salaries->at(q1Index.max(1))}"
48
49# Output: {q1: 105000.0, median: 120000.0, q3: 145000.0, iqr: 40000.0}
50
51# Department comparison metrics
52swift-aql evaluate --model enterprise-data.xmi \
53 --expression "let deptMetrics = organisation.departments
54 ->collect(d | Tuple{
55 name = d.name,
56 avgSalary = d.employees->collect(e | e.salary)->sum()
57 / d.employees->size(),
58 avgExperience = d.employees->collect(e | e.yearsOfService)->sum()
59 / d.employees->size()})
60 in let overallAvgSalary = deptMetrics->collect(m | m.avgSalary)->sum()
61 / deptMetrics->size()
62 in deptMetrics->collect(m | Tuple{
63 department = m.name,
64 avgSalary = m.avgSalary,
65 avgExperience = m.avgExperience,
66 aboveOrgAvg = m.avgSalary > overallAvgSalary})"
67
68# Output: [{department: "Engineering", avgSalary: 142500.0, avgExperience: 7.0, aboveOrgAvg: true}, ...]
69
70# Project risk score (based on dependencies and incomplete milestones)
71swift-aql evaluate --model enterprise-data.xmi \
72 --expression "organisation.projects
73 ->collect(p | let depCount = p.dependencies->size(),
74 incompleteMilestones = p.milestones->reject(m | m.completed)->size(),
75 totalMilestones = p.milestones->size()
76 in Tuple{
77 project = p.name,
78 riskScore = depCount * 10 + incompleteMilestones * 20,
79 completionRate = if totalMilestones > 0
80 then (totalMilestones - incompleteMilestones) * 100 / totalMilestones
81 else 0 endif})
82 ->sortedBy(p | -p.riskScore)"
83
84# Output: [{project: "Analytics Dashboard", riskScore: 60, completionRate: 0}, ...]

Section 4

Query Composition and Abstraction

Complex queries benefit from composition and abstraction techniques. Build reusable query components that can be combined to solve larger problems.

Query composition enables modular query development, making complex analysis tasks manageable and maintainable.

Step 1

Create reusable query components.

Build focused query components that solve specific analysis problems. These can be combined to create comprehensive analysis queries.

Terminal
1# Grouping and categorisation analysis
2# Group elements and analyse by category
3
4# Group employees by years of service bands
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let employees = organisation.departments.employees->flatten()
7 in Tuple{
8 junior = employees->select(e | e.yearsOfService <= 3)
9 ->collect(e | Tuple{name = e.name, years = e.yearsOfService}),
10 midLevel = employees->select(e | e.yearsOfService > 3 and e.yearsOfService <= 8)
11 ->collect(e | Tuple{name = e.name, years = e.yearsOfService}),
12 senior = employees->select(e | e.yearsOfService > 8)
13 ->collect(e | Tuple{name = e.name, years = e.yearsOfService})}"
14
15# Output: {junior: [{name: "Michael Brown", years: 3}, ...], midLevel: [...], senior: [...]}
16
17# Group projects by status with metrics
18swift-aql evaluate --model enterprise-data.xmi \
19 --expression "let projects = organisation.projects,
20 statuses = projects->collect(p | p.status)->asSet()
21 in statuses->collect(s | Tuple{
22 status = s,
23 count = projects->select(p | p.status = s)->size(),
24 totalBudget = projects->select(p | p.status = s)
25 ->collect(p | p.budget)->sum(),
26 avgTeamSize = projects->select(p | p.status = s)
27 ->collect(p | p.teamMembers->size())->sum()
28 / projects->select(p | p.status = s)->size()})"
29
30# Output: [{status: "Active", count: 3, totalBudget: 1050000, avgTeamSize: 8},
31# {status: "Planning", count: 1, totalBudget: 150000, avgTeamSize: 3}]
32
33# Group by location
34swift-aql evaluate --model enterprise-data.xmi \
35 --expression "let allDepts = organisation.departments
36 ->union(organisation.departments.subDepartments->flatten()),
37 locations = allDepts->collect(d | d.location)->asSet()
38 in locations->collect(loc | Tuple{
39 location = loc,
40 departments = allDepts->select(d | d.location = loc)->collect(d | d.name),
41 totalEmployees = allDepts->select(d | d.location = loc)
42 .employees->flatten()->size(),
43 totalBudget = allDepts->select(d | d.location = loc)
44 ->collect(d | d.budget)->sum()})"
45
46# Output: [{location: "Melbourne", departments: [...], totalEmployees: 11, totalBudget: 4500000}, ...]
47
48# Group employees by salary bands
49swift-aql evaluate --model enterprise-data.xmi \
50 --expression "let employees = organisation.departments.employees->flatten()
51 in Sequence{
52 Tuple{band = 'Under 100k',
53 count = employees->select(e | e.salary < 100000)->size(),
54 avgExperience = employees->select(e | e.salary < 100000)
55 ->collect(e | e.yearsOfService)->sum()
56 / employees->select(e | e.salary < 100000)->size().max(1)},
57 Tuple{band = '100k-130k',
58 count = employees->select(e | e.salary >= 100000 and e.salary < 130000)->size(),
59 avgExperience = employees->select(e | e.salary >= 100000 and e.salary < 130000)
60 ->collect(e | e.yearsOfService)->sum()
61 / employees->select(e | e.salary >= 100000 and e.salary < 130000)->size().max(1)},
62 Tuple{band = '130k-160k',
63 count = employees->select(e | e.salary >= 130000 and e.salary < 160000)->size(),
64 avgExperience = employees->select(e | e.salary >= 130000 and e.salary < 160000)
65 ->collect(e | e.yearsOfService)->sum()
66 / employees->select(e | e.salary >= 130000 and e.salary < 160000)->size().max(1)},
67 Tuple{band = 'Over 160k',
68 count = employees->select(e | e.salary >= 160000)->size(),
69 avgExperience = employees->select(e | e.salary >= 160000)
70 ->collect(e | e.yearsOfService)->sum()
71 / employees->select(e | e.salary >= 160000)->size().max(1)}}"
72
73# Output: [{band: "Under 100k", count: 4, avgExperience: 1.5}, ...]
74
75# Group milestones by completion status per project
76swift-aql evaluate --model enterprise-data.xmi \
77 --expression "organisation.projects
78 ->collect(p | Tuple{
79 project = p.name,
80 completed = p.milestones->select(m | m.completed)->collect(m | m.name),
81 pending = p.milestones->reject(m | m.completed)->collect(m | m.name),
82 completionPercentage = if p.milestones->notEmpty()
83 then p.milestones->select(m | m.completed)->size() * 100
84 / p.milestones->size()
85 else 100 endif})"
86
87# Output: [{project: "Customer Portal", completed: ["Requirements Complete", "Design Finalised"],
88# pending: ["Beta Release", "Production Launch"], completionPercentage: 50}]

Step 2

Compose queries for comprehensive analysis.

Combine multiple query components to perform comprehensive model analysis. This approach scales to complex enterprise analysis scenarios.

Terminal
1# Hierarchy and tree structure queries
2# Navigate and analyse hierarchical structures
3
4# Get full department hierarchy
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.departments
7 ->collect(d | Tuple{
8 parent = d.name,
9 children = d.subDepartments->collect(sd | sd.name),
10 depth = if d.subDepartments->isEmpty() then 0 else 1 endif})"
11
12# Output: [{parent: "Engineering", children: ["Platform Team", "Mobile Team"], depth: 1}, ...]
13
14# Find all descendants of a department (closure operation)
15swift-aql evaluate --model enterprise-data.xmi \
16 --expression "let engDept = organisation.departments->select(d | d.code = 'ENG')->first()
17 in engDept->closure(d | d.subDepartments)
18 ->collect(d | Tuple{name = d.name, code = d.code})"
19
20# Output: [{name: "Engineering", code: "ENG"},
21# {name: "Platform Team", code: "ENG-PLT"},
22# {name: "Mobile Team", code: "ENG-MOB"}]
23
24# Calculate hierarchy depth for each employee
25swift-aql evaluate --model enterprise-data.xmi \
26 --expression "organisation.departments.employees->flatten()
27 ->collect(e | let depth =
28 if e.supervisor = null then 0
29 else if e.supervisor.supervisor = null then 1
30 else if e.supervisor.supervisor.supervisor = null then 2
31 else 3 endif endif endif
32 in Tuple{employee = e.name, managementLevel = depth})"
33
34# Output: [{employee: "Sarah Mitchell", managementLevel: 0}, ...]
35
36# Find employees with deepest supervision chain
37swift-aql evaluate --model enterprise-data.xmi \
38 --expression "organisation.departments.employees->flatten()
39 ->select(e | e.supervisor <> null and e.supervisor.supervisor <> null)
40 ->collect(e | Tuple{
41 employee = e.name,
42 supervisor = e.supervisor.name,
43 grandSupervisor = e.supervisor.supervisor.name})"
44
45# Output: [{employee: "Michael Brown", supervisor: "James Wong", grandSupervisor: "Sarah Mitchell"}]
46
47# Build organisation tree with employee counts
48swift-aql evaluate --model enterprise-data.xmi \
49 --expression "organisation.departments
50 ->collect(d | Tuple{
51 department = d.name,
52 directEmployees = d.employees->size(),
53 subDepartments = d.subDepartments
54 ->collect(sd | Tuple{
55 name = sd.name,
56 employees = sd.employees->size()}),
57 totalEmployees = d.employees->size() +
58 d.subDepartments.employees->flatten()->size()})"
59
60# Output: [{department: "Engineering", directEmployees: 4,
61# subDepartments: [{name: "Platform Team", employees: 3}, ...],
62# totalEmployees: 10}]
63
64# Find leaf departments (no sub-departments)
65swift-aql evaluate --model enterprise-data.xmi \
66 --expression "let allDepts = organisation.departments
67 ->union(organisation.departments.subDepartments->flatten())
68 in allDepts->select(d | d.subDepartments->isEmpty())
69 ->collect(d | Tuple{
70 name = d.name,
71 isSubDept = organisation.departments->excludes(d),
72 employeeCount = d.employees->size()})"
73
74# Output: [{name: "Platform Team", isSubDept: true, employeeCount: 3}, ...]
75
76# Calculate total budget including sub-departments
77swift-aql evaluate --model enterprise-data.xmi \
78 --expression "organisation.departments
79 ->collect(d | Tuple{
80 department = d.name,
81 ownBudget = d.budget,
82 subDeptBudget = d.subDepartments->collect(sd | sd.budget)->sum(),
83 totalBudget = d.budget + d.subDepartments->collect(sd | sd.budget)->sum()})"
84
85# Output: [{department: "Engineering", ownBudget: 2500000, subDeptBudget: 1400000,
86# totalBudget: 3900000}]

Step 3

Build query libraries for domain-specific analysis.

Create libraries of domain-specific queries that can be reused across different models and analysis scenarios within the same domain.

Terminal
1# Transitive closure operations
2# Compute reachable elements through relationships
3
4# Transitive closure of project dependencies
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.projects
7 ->collect(p | Tuple{
8 project = p.name,
9 directDependencies = p.dependencies->collect(d | d.name),
10 allDependencies = p->closure(proj | proj.dependencies)
11 ->excluding(p)
12 ->collect(d | d.name)})"
13
14# Output: [{project: "Analytics Dashboard",
15# directDependencies: ["Customer Portal", "Infrastructure Modernisation"],
16# allDependencies: ["Customer Portal", "Infrastructure Modernisation"]}]
17
18# Transitive closure of supervision (all managers in chain)
19swift-aql evaluate --model enterprise-data.xmi \
20 --expression "organisation.departments.employees->flatten()
21 ->select(e | e.supervisor <> null)
22 ->collect(e | Tuple{
23 employee = e.name,
24 allSupervisors = e->closure(emp |
25 if emp.supervisor <> null
26 then Sequence{emp.supervisor}
27 else Sequence{} endif)
28 ->excluding(e)
29 ->collect(s | s.name)})"
30
31# Output: [{employee: "Michael Brown", allSupervisors: ["James Wong", "Sarah Mitchell"]}, ...]
32
33# Transitive closure of department containment
34swift-aql evaluate --model enterprise-data.xmi \
35 --expression "organisation.departments
36 ->collect(d | Tuple{
37 department = d.name,
38 allSubDepartments = d->closure(dept | dept.subDepartments)
39 ->excluding(d)
40 ->collect(sd | sd.name)})"
41
42# Output: [{department: "Engineering", allSubDepartments: ["Platform Team", "Mobile Team"]}, ...]
43
44# Find all reachable projects from a department
45swift-aql evaluate --model enterprise-data.xmi \
46 --expression "let startDept = organisation.departments->select(d | d.code = 'ENG')->first()
47 in let directProjects = organisation.projects
48 ->select(p | p.leadDepartment = startDept
49 or startDept.subDepartments->includes(p.leadDepartment))
50 in let dependentProjects = directProjects
51 ->collect(p | p->closure(proj |
52 organisation.projects->select(other | other.dependencies->includes(proj))))
53 ->flatten()
54 ->asSet()
55 in Tuple{
56 directProjects = directProjects->collect(p | p.name),
57 allRelatedProjects = dependentProjects->collect(p | p.name)}"
58
59# Output: {directProjects: ["Customer Portal", "Infrastructure Modernisation", "Mobile App Redesign"],
60# allRelatedProjects: [...]}
61
62# Transitive mentorship relationships
63swift-aql evaluate --model enterprise-data.xmi \
64 --expression "organisation.departments.employees->flatten()
65 ->select(e | e.mentors->notEmpty())
66 ->collect(e | Tuple{
67 mentee = e.name,
68 directMentors = e.mentors->collect(m | m.name),
69 allMentors = e->closure(emp | emp.mentors)
70 ->excluding(e)
71 ->asSet()
72 ->collect(m | m.name)})"
73
74# Output: [{mentee: "Tom Nguyen", directMentors: ["Anna Kowalski"],
75# allMentors: ["Anna Kowalski"]}]
76
77# Closure with depth tracking (simulated)
78swift-aql evaluate --model enterprise-data.xmi \
79 --expression "let root = organisation.departments->select(d | d.code = 'ENG')->first()
80 in Sequence{
81 Tuple{level = 0, departments = Sequence{root.name}},
82 Tuple{level = 1, departments = root.subDepartments->collect(d | d.name)},
83 Tuple{level = 2, departments = root.subDepartments.subDepartments
84 ->flatten()->collect(d | d.name)}}"
85
86# Output: [{level: 0, departments: ["Engineering"]},
87# {level: 1, departments: ["Platform Team", "Mobile Team"]},
88# {level: 2, departments: []}]

Step 4

Parameterize queries for flexibility.

Design flexible queries that can be adapted to different scenarios through parameterization, increasing reusability and maintainability.

Terminal
1# Dependency analysis patterns
2# Analyse dependencies and impacts
3
4# Direct and indirect project dependencies
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.projects
7 ->collect(p | Tuple{
8 project = p.name,
9 directDeps = p.dependencies->size(),
10 dependentOn = organisation.projects
11 ->select(other | other.dependencies->includes(p))
12 ->collect(o | o.name),
13 isCritical = organisation.projects
14 ->select(other | other.dependencies->includes(p))
15 ->size() >= 2})"
16
17# Output: [{project: "Customer Portal", directDeps: 0, dependentOn: ["Infrastructure...", "Analytics..."],
18# isCritical: true}]
19
20# Skill dependency analysis (what skills are most needed)
21swift-aql evaluate --model enterprise-data.xmi \
22 --expression "let allSkills = organisation.departments.employees
23 ->flatten()
24 ->collect(e | e.skills)
25 ->flatten()
26 in allSkills->asSet()
27 ->collect(s | Tuple{
28 skill = s,
29 employeeCount = allSkills->select(sk | sk = s)->size()})
30 ->sortedBy(t | -t.employeeCount)"
31
32# Output: [{skill: "Swift", employeeCount: 4}, {skill: "Figma", employeeCount: 3}, ...]
33
34# Department collaboration dependencies
35swift-aql evaluate --model enterprise-data.xmi \
36 --expression "organisation.departments
37 ->select(d | d.collaboratesWith->notEmpty())
38 ->collect(d | Tuple{
39 department = d.name,
40 collaborators = d.collaboratesWith->collect(c | c.name),
41 sharedProjects = organisation.projects
42 ->select(p | p.teamMembers
43 ->exists(e | e.eContainer() = d or
44 d.subDepartments.employees->flatten()->includes(e)) and
45 p.teamMembers->exists(e | d.collaboratesWith
46 ->exists(c | e.eContainer() = c or
47 c.subDepartments.employees->flatten()->includes(e))))
48 ->collect(p | p.name)})"
49
50# Output: [{department: "Engineering", collaborators: ["Product", "Design"],
51# sharedProjects: ["Customer Portal", "Mobile App Redesign"]}]
52
53# Employee dependency (who depends on whom via projects)
54swift-aql evaluate --model enterprise-data.xmi \
55 --expression "let criticalProject = organisation.projects->first()
56 in criticalProject.teamMembers
57 ->select(e | e.role.endsWith('Director') or e.role.endsWith('Lead'))
58 ->collect(e | Tuple{
59 keyPerson = e.name,
60 role = e.role,
61 directReports = e.directReports->collect(r | r.name),
62 projectTeamSize = criticalProject.teamMembers->size(),
63 impactIfLeaves = e.directReports
64 ->intersection(criticalProject.teamMembers)->size()})"
65
66# Output: [{keyPerson: "Sarah Mitchell", role: "Engineering Director", ...}]
67
68# Find bottleneck projects (many dependencies, few completed milestones)
69swift-aql evaluate --model enterprise-data.xmi \
70 --expression "organisation.projects
71 ->select(p | p.dependencies->notEmpty() or
72 organisation.projects->exists(other | other.dependencies->includes(p)))
73 ->collect(p | Tuple{
74 project = p.name,
75 blockedBy = p.dependencies
76 ->select(d | d.milestones->reject(m | m.completed)->notEmpty())
77 ->collect(d | d.name),
78 blocking = organisation.projects
79 ->select(other | other.dependencies->includes(p))
80 ->collect(o | o.name),
81 riskLevel = if p.dependencies
82 ->exists(d | d.milestones->reject(m | m.completed)->notEmpty())
83 then 'HIGH' else 'LOW' endif})"
84
85# Output: [{project: "Analytics Dashboard", blockedBy: ["Customer Portal", "Infrastructure..."],
86# blocking: [], riskLevel: "HIGH"}]
87
88# Resource allocation dependencies
89swift-aql evaluate --model enterprise-data.xmi \
90 --expression "organisation.departments.employees->flatten()
91 ->select(e | e.assignedProjects->size() >= 2)
92 ->collect(e | Tuple{
93 employee = e.name,
94 projectCount = e.assignedProjects->size(),
95 projects = e.assignedProjects->collect(p | p.name),
96 overallocationRisk = e.assignedProjects
97 ->select(p | p.priority = 1)->size() >= 2})"
98
99# Output: [{employee: "Sarah Mitchell", projectCount: 2, projects: [...],
100# overallocationRisk: true}]

Section 5

Advanced Analysis Patterns

Advanced AQL patterns enable sophisticated model analysis including graph traversal, pattern matching, and statistical analysis.

These patterns support complex modeling scenarios such as dependency analysis, impact assessment, and comprehensive model validation.

Step 1

Implement graph traversal algorithms.

Use recursive-style queries to traverse graph structures in models, finding paths, cycles, and connectivity patterns.

Terminal
1# Impact analysis queries
2# Assess the impact of changes or events
3
4# Impact of employee departure
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "organisation.departments.employees->flatten()
7 ->collect(e | Tuple{
8 employee = e.name,
9 role = e.role,
10 projectsAffected = e.assignedProjects->size(),
11 directReportsAffected = e.directReports->size(),
12 menteesAffected = organisation.departments.employees
13 ->flatten()
14 ->select(emp | emp.mentors->includes(e))->size(),
15 impactScore = e.assignedProjects->size() * 10
16 + e.directReports->size() * 20
17 + organisation.departments.employees->flatten()
18 ->select(emp | emp.mentors->includes(e))->size() * 5})
19 ->sortedBy(t | -t.impactScore)"
20
21# Output: [{employee: "Sarah Mitchell", role: "Engineering Director",
22# projectsAffected: 2, directReportsAffected: 1, menteesAffected: 1,
23# impactScore: 45}]
24
25# Budget cut impact analysis
26swift-aql evaluate --model enterprise-data.xmi \
27 --expression "let cutPercentage = 20
28 in organisation.departments
29 ->collect(d | let newBudget = d.budget * (100 - cutPercentage) / 100,
30 currentSalaryCost = d.employees->collect(e | e.salary)->sum()
31 in Tuple{
32 department = d.name,
33 currentBudget = d.budget,
34 proposedBudget = newBudget,
35 salaryCost = currentSalaryCost,
36 surplusAfterCut = newBudget - currentSalaryCost,
37 viable = newBudget >= currentSalaryCost})"
38
39# Output: [{department: "Engineering", currentBudget: 2500000, proposedBudget: 2000000,
40# salaryCost: 570000, surplusAfterCut: 1430000, viable: true}]
41
42# Project delay impact
43swift-aql evaluate --model enterprise-data.xmi \
44 --expression "organisation.projects
45 ->collect(p | Tuple{
46 project = p.name,
47 wouldDelay = organisation.projects
48 ->select(other | other.dependencies->includes(p))
49 ->collect(o | o.name),
50 cascadeDepth = organisation.projects
51 ->select(other | other.dependencies->includes(p))
52 ->collect(delayed | organisation.projects
53 ->select(further | further.dependencies->includes(delayed)))
54 ->flatten()
55 ->asSet()
56 ->collect(f | f.name)})"
57
58# Output: [{project: "Customer Portal", wouldDelay: ["Infrastructure...", "Analytics..."],
59# cascadeDepth: ["Analytics Dashboard"]}]
60
61# Skill gap impact if employees leave
62swift-aql evaluate --model enterprise-data.xmi \
63 --expression "let allEmployees = organisation.departments.employees->flatten(),
64 uniqueSkills = allEmployees
65 ->collect(e | e.skills)->flatten()->asSet()
66 in uniqueSkills
67 ->collect(skill | Tuple{
68 skill = skill,
69 holders = allEmployees->select(e | e.skills->includes(skill))
70 ->collect(e | e.name),
71 singlePointOfFailure = allEmployees
72 ->select(e | e.skills->includes(skill))->size() = 1})
73 ->select(t | t.singlePointOfFailure)"
74
75# Output: [{skill: "SupplyChain", holders: ["William Anderson"], singlePointOfFailure: true}]
76
77# Department reorganisation impact
78swift-aql evaluate --model enterprise-data.xmi \
79 --expression "let deptToMerge = organisation.departments
80 ->select(d | d.code = 'DES')->first()
81 in Tuple{
82 departmentToMerge = deptToMerge.name,
83 employeesAffected = deptToMerge.employees->size(),
84 projectsAffected = organisation.projects
85 ->select(p | p.teamMembers
86 ->exists(e | e.eContainer() = deptToMerge))
87 ->collect(p | p.name),
88 collaborationsAffected = organisation.departments
89 ->select(d | d.collaboratesWith->includes(deptToMerge))
90 ->collect(d | d.name)}"
91
92# Output: {departmentToMerge: "Design", employeesAffected: 4,
93# projectsAffected: ["Customer Portal", "Mobile App Redesign"],
94# collaborationsAffected: ["Engineering", "Product"]}
95
96# Priority change impact
97swift-aql evaluate --model enterprise-data.xmi \
98 --expression "organisation.projects->select(p | p.priority = 1)
99 ->collect(p | Tuple{
100 project = p.name,
101 currentTeam = p.teamMembers->collect(e | e.name),
102 conflictsWith = organisation.projects
103 ->select(other | other.priority = 1 and other <> p)
104 ->select(other | other.teamMembers
105 ->intersection(p.teamMembers)->notEmpty())
106 ->collect(other | Tuple{
107 project = other.name,
108 sharedResources = other.teamMembers
109 ->intersection(p.teamMembers)
110 ->collect(e | e.name)})})"
111
112# Output: [{project: "Customer Portal", currentTeam: [...],
113# conflictsWith: [{project: "Mobile App Redesign", sharedResources: [...]}]}]

Step 2

Build pattern matching queries.

Create queries that match complex structural patterns in models, enabling sophisticated model analysis and transformation planning.

Terminal
1# Validation and constraint checking queries
2# Verify model integrity and business rules
3
4# Validate all employees have valid supervisors (not self-referential)
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let employees = organisation.departments.employees->flatten()
7 in Tuple{
8 selfSupervision = employees
9 ->select(e | e.supervisor = e)
10 ->collect(e | e.name),
11 cyclicSupervision = employees
12 ->select(e | e.supervisor <> null and
13 e.supervisor.supervisor = e)
14 ->collect(e | e.name),
15 valid = employees->forAll(e | e.supervisor <> e and
16 (e.supervisor = null or e.supervisor.supervisor <> e))}"
17
18# Output: {selfSupervision: [], cyclicSupervision: [], valid: true}
19
20# Validate budget constraints (salary costs within budget)
21swift-aql evaluate --model enterprise-data.xmi \
22 --expression "organisation.departments
23 ->collect(d | let salaryCost = d.employees->collect(e | e.salary)->sum()
24 in Tuple{
25 department = d.name,
26 budget = d.budget,
27 salaryCost = salaryCost,
28 percentage = salaryCost * 100 / d.budget,
29 withinBudget = salaryCost <= d.budget,
30 warning = salaryCost > d.budget * 0.8})"
31
32# Output: [{department: "Engineering", budget: 2500000, salaryCost: 570000,
33# percentage: 22.8, withinBudget: true, warning: false}]
34
35# Validate project team composition
36swift-aql evaluate --model enterprise-data.xmi \
37 --expression "organisation.projects
38 ->collect(p | Tuple{
39 project = p.name,
40 hasLeadDept = p.leadDepartment <> null,
41 hasTeam = p.teamMembers->notEmpty(),
42 leadDeptRepresented = p.teamMembers
43 ->exists(e | e.eContainer() = p.leadDepartment or
44 p.leadDepartment.subDepartments.employees
45 ->flatten()->includes(e)),
46 valid = p.leadDepartment <> null and p.teamMembers->notEmpty() and
47 p.teamMembers->exists(e | e.eContainer() = p.leadDepartment or
48 p.leadDepartment.subDepartments.employees
49 ->flatten()->includes(e))})"
50
51# Output: [{project: "Customer Portal", hasLeadDept: true, hasTeam: true,
52# leadDeptRepresented: true, valid: true}]
53
54# Check for orphaned references
55swift-aql evaluate --model enterprise-data.xmi \
56 --expression "let allEmployees = organisation.departments.employees->flatten()
57 ->union(organisation.departments.subDepartments.employees->flatten())
58 in Tuple{
59 invalidSupervisors = allEmployees
60 ->select(e | e.supervisor <> null and
61 allEmployees->excludes(e.supervisor))
62 ->collect(e | e.name),
63 invalidMentors = allEmployees
64 ->select(e | e.mentors->exists(m | allEmployees->excludes(m)))
65 ->collect(e | e.name),
66 allReferencesValid = allEmployees
67 ->forAll(e | (e.supervisor = null or allEmployees->includes(e.supervisor))
68 and e.mentors->forAll(m | allEmployees->includes(m)))}"
69
70# Output: {invalidSupervisors: [], invalidMentors: [], allReferencesValid: true}
71
72# Validate milestone ordering (due dates should be sequential)
73swift-aql evaluate --model enterprise-data.xmi \
74 --expression "organisation.projects
75 ->collect(p | Tuple{
76 project = p.name,
77 milestonesOrdered = p.milestones
78 ->collect(m | m.dueDate)->sortedBy(d | d)
79 = p.milestones->collect(m | m.dueDate),
80 completedBeforeDue = p.milestones
81 ->forAll(m | m.completed implies true)})"
82
83# Output: [{project: "Customer Portal", milestonesOrdered: true, completedBeforeDue: true}]
84
85# Check for circular project dependencies
86swift-aql evaluate --model enterprise-data.xmi \
87 --expression "organisation.projects
88 ->collect(p | Tuple{
89 project = p.name,
90 selfDependency = p.dependencies->includes(p),
91 circularDependency = p.dependencies
92 ->exists(d | d.dependencies->includes(p)),
93 valid = not p.dependencies->includes(p) and
94 not p.dependencies->exists(d | d.dependencies->includes(p))})"
95
96# Output: [{project: "Customer Portal", selfDependency: false, circularDependency: false,
97# valid: true}]
98
99# Validate role hierarchy (directors manage leads, leads manage others)
100swift-aql evaluate --model enterprise-data.xmi \
101 --expression "let employees = organisation.departments.employees->flatten()
102 in employees
103 ->select(e | e.directReports->notEmpty())
104 ->collect(e | Tuple{
105 manager = e.name,
106 managerRole = e.role,
107 reportRoles = e.directReports->collect(r | r.role),
108 validHierarchy = if e.role.endsWith('Director')
109 then e.directReports->forAll(r |
110 r.role.endsWith('Lead') or r.role.startsWith('Senior'))
111 else true endif})"
112
113# Output: [{manager: "Sarah Mitchell", managerRole: "Engineering Director",
114# reportRoles: ["Senior Engineer"], validHierarchy: true}]

Step 3

Perform statistical analysis on models.

Apply statistical operations to model data to generate insights about model complexity, distribution patterns, and structural characteristics.

Terminal
1# Summary report generation
2# Create comprehensive summaries and overviews
3
4# Executive summary of the organisation
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let org = organisation,
7 allDepts = org.departments->union(org.departments.subDepartments->flatten()),
8 allEmps = org.departments.employees->flatten()
9 ->union(org.departments.subDepartments.employees->flatten())
10 in Tuple{
11 organisation = org.name,
12 founded = org.founded,
13 headquarters = org.headquarters,
14 totalDepartments = allDepts->size(),
15 totalEmployees = allEmps->size(),
16 totalProjects = org.projects->size(),
17 totalBudget = allDepts->collect(d | d.budget)->sum(),
18 totalSalaries = allEmps->collect(e | e.salary)->sum()}"
19
20# Output: {organisation: "Acme Technologies", founded: 1995, headquarters: "Melbourne",
21# totalDepartments: 6, totalEmployees: 21, totalProjects: 4,
22# totalBudget: 5300000, totalSalaries: 2670000}
23
24# Department summary report
25swift-aql evaluate --model enterprise-data.xmi \
26 --expression "organisation.departments
27 ->collect(d | Tuple{
28 name = d.name,
29 location = d.location,
30 budget = d.budget,
31 employeeCount = d.employees->size() +
32 d.subDepartments.employees->flatten()->size(),
33 avgSalary = (d.employees->collect(e | e.salary)
34 ->union(d.subDepartments.employees->flatten()
35 ->collect(e | e.salary)))->sum()
36 / (d.employees->size() + d.subDepartments.employees->flatten()->size()),
37 subDepartmentCount = d.subDepartments->size(),
38 projectInvolvement = organisation.projects
39 ->select(p | p.leadDepartment = d or
40 d.subDepartments->includes(p.leadDepartment))
41 ->size()})"
42
43# Output: [{name: "Engineering", location: "Melbourne", budget: 2500000,
44# employeeCount: 10, avgSalary: 133400, subDepartmentCount: 2,
45# projectInvolvement: 3}]
46
47# Project portfolio summary
48swift-aql evaluate --model enterprise-data.xmi \
49 --expression "let projects = organisation.projects
50 in Tuple{
51 totalProjects = projects->size(),
52 byStatus = Tuple{
53 active = projects->select(p | p.status = 'Active')->size(),
54 planning = projects->select(p | p.status = 'Planning')->size(),
55 completed = projects->select(p | p.status = 'Completed')->size()},
56 totalBudget = projects->collect(p | p.budget)->sum(),
57 avgTeamSize = projects->collect(p | p.teamMembers->size())->sum()
58 / projects->size(),
59 highPriority = projects->select(p | p.priority = 1)
60 ->collect(p | p.name),
61 milestoneProgress = Tuple{
62 total = projects.milestones->flatten()->size(),
63 completed = projects.milestones->flatten()
64 ->select(m | m.completed)->size()}}"
65
66# Output: {totalProjects: 4, byStatus: {active: 3, planning: 1, completed: 0},
67# totalBudget: 1200000, avgTeamSize: 6, highPriority: [...],
68# milestoneProgress: {total: 12, completed: 5}}
69
70# Workforce summary
71swift-aql evaluate --model enterprise-data.xmi \
72 --expression "let employees = organisation.departments.employees
73 ->flatten()
74 ->union(organisation.departments.subDepartments.employees->flatten())
75 in Tuple{
76 totalHeadcount = employees->size(),
77 avgSalary = employees->collect(e | e.salary)->sum() / employees->size(),
78 avgTenure = employees->collect(e | e.yearsOfService)->sum() / employees->size(),
79 salaryRange = Tuple{
80 min = employees->collect(e | e.salary)->min(),
81 max = employees->collect(e | e.salary)->max()},
82 tenureRange = Tuple{
83 min = employees->collect(e | e.yearsOfService)->min(),
84 max = employees->collect(e | e.yearsOfService)->max()},
85 managementRatio = employees->select(e | e.directReports->notEmpty())->size()
86 * 100 / employees->size()}"
87
88# Output: {totalHeadcount: 21, avgSalary: 127142.86, avgTenure: 6.19,
89# salaryRange: {min: 85000, max: 185000},
90# tenureRange: {min: 1, max: 14}, managementRatio: 38}
91
92# Location-based summary
93swift-aql evaluate --model enterprise-data.xmi \
94 --expression "let allDepts = organisation.departments
95 ->union(organisation.departments.subDepartments->flatten()),
96 locations = allDepts->collect(d | d.location)->asSet()
97 in locations->collect(loc | Tuple{
98 location = loc,
99 departmentCount = allDepts->select(d | d.location = loc)->size(),
100 employeeCount = allDepts->select(d | d.location = loc)
101 .employees->flatten()->size(),
102 totalBudget = allDepts->select(d | d.location = loc)
103 ->collect(d | d.budget)->sum()})"
104
105# Output: [{location: "Melbourne", departmentCount: 3, employeeCount: 11, totalBudget: 4500000},
106# {location: "Sydney", departmentCount: 2, employeeCount: 7, totalBudget: 1500000}, ...]

Step 4

Create comprehensive model reports.

Combine all advanced query patterns to generate comprehensive model analysis reports that provide deep insights into model structure and quality.

Terminal
1# Comprehensive reports combining multiple analyses
2# Full organisational intelligence reports
3
4# Complete organisational health report
5swift-aql evaluate --model enterprise-data.xmi \
6 --expression "let org = organisation,
7 allEmps = org.departments.employees->flatten()
8 ->union(org.departments.subDepartments.employees->flatten()),
9 allDepts = org.departments->union(org.departments.subDepartments->flatten())
10 in Tuple{
11 overview = Tuple{
12 name = org.name,
13 age = 2024 - org.founded,
14 headquarters = org.headquarters},
15 workforce = Tuple{
16 total = allEmps->size(),
17 avgTenure = allEmps->collect(e | e.yearsOfService)->sum() / allEmps->size(),
18 avgSalary = allEmps->collect(e | e.salary)->sum() / allEmps->size(),
19 managersToEmployees = allEmps->select(e | e.directReports->notEmpty())->size()
20 + ':' + allEmps->size()},
21 finance = Tuple{
22 totalBudget = allDepts->collect(d | d.budget)->sum(),
23 totalSalaries = allEmps->collect(e | e.salary)->sum(),
24 budgetUtilisation = allEmps->collect(e | e.salary)->sum() * 100
25 / allDepts->collect(d | d.budget)->sum()},
26 projects = Tuple{
27 active = org.projects->select(p | p.status = 'Active')->size(),
28 totalBudget = org.projects->collect(p | p.budget)->sum(),
29 onTrack = org.projects->select(p | p.milestones
30 ->forAll(m | m.completed or m.dueDate >= '2024-06-01'))->size()}}"
31
32# Output: {overview: {...}, workforce: {...}, finance: {...}, projects: {...}}
33
34# Risk assessment report
35swift-aql evaluate --model enterprise-data.xmi \
36 --expression "let allEmps = organisation.departments.employees->flatten()
37 ->union(organisation.departments.subDepartments.employees->flatten())
38 in Tuple{
39 keyPersonRisk = allEmps
40 ->select(e | e.directReports->size() >= 2 or
41 e.assignedProjects->size() >= 2)
42 ->collect(e | Tuple{
43 name = e.name,
44 role = e.role,
45 reportsCount = e.directReports->size(),
46 projectsCount = e.assignedProjects->size()}),
47 singlePointOfFailure = allEmps
48 ->collect(e | e.skills)->flatten()->asSet()
49 ->select(skill | allEmps
50 ->select(e | e.skills->includes(skill))->size() = 1)
51 ->collect(skill | Tuple{
52 skill = skill,
53 holder = allEmps->select(e | e.skills->includes(skill))
54 ->first().name}),
55 projectDependencyRisks = organisation.projects
56 ->select(p | p.dependencies->size() >= 2)
57 ->collect(p | Tuple{
58 project = p.name,
59 dependencyCount = p.dependencies->size(),
60 blockedMilestones = p.milestones
61 ->reject(m | m.completed)->size()})}"
62
63# Output: {keyPersonRisk: [...], singlePointOfFailure: [...], projectDependencyRisks: [...]}
64
65# Cross-departmental collaboration report
66swift-aql evaluate --model enterprise-data.xmi \
67 --expression "organisation.projects
68 ->collect(p | let depts = p.teamMembers
69 ->collect(e | e.eContainer())
70 ->asSet()
71 in Tuple{
72 project = p.name,
73 leadDepartment = p.leadDepartment.name,
74 participatingDepartments = depts->collect(d | d.name),
75 crossDepartmental = depts->size() > 1,
76 collaborationScore = depts->size() * p.teamMembers->size()})"
77
78# Output: [{project: "Customer Portal", leadDepartment: "Engineering",
79# participatingDepartments: [...], crossDepartmental: true, collaborationScore: 36}]
80
81# Career progression and mentorship report
82swift-aql evaluate --model enterprise-data.xmi \
83 --expression "let allEmps = organisation.departments.employees->flatten()
84 ->union(organisation.departments.subDepartments.employees->flatten())
85 in Tuple{
86 mentorshipPairs = allEmps
87 ->select(e | e.mentors->notEmpty())
88 ->collect(e | Tuple{
89 mentee = e.name,
90 mentors = e.mentors->collect(m | m.name)}),
91 potentialLeaders = allEmps
92 ->select(e | e.yearsOfService >= 5 and
93 e.directReports->isEmpty() and
94 e.assignedProjects->size() >= 2)
95 ->collect(e | Tuple{
96 name = e.name,
97 tenure = e.yearsOfService,
98 projects = e.assignedProjects->size()}),
99 successionPaths = allEmps
100 ->select(e | e.directReports->notEmpty())
101 ->collect(e | Tuple{
102 manager = e.name,
103 potentialSuccessors = e.directReports
104 ->select(r | r.yearsOfService >= 3)
105 ->collect(r | r.name)})}"
106
107# Output: {mentorshipPairs: [...], potentialLeaders: [...], successionPaths: [...]}
108
109# Complete project status dashboard
110swift-aql evaluate --model enterprise-data.xmi \
111 --expression "organisation.projects
112 ->collect(p | Tuple{
113 project = p.name,
114 status = p.status,
115 priority = p.priority,
116 budget = Tuple{
117 allocated = p.budget,
118 team = p.teamMembers->collect(e | e.salary)->sum() / 12},
119 timeline = Tuple{
120 start = p.startDate,
121 end = p.endDate,
122 milestonesTotal = p.milestones->size(),
123 milestonesComplete = p.milestones->select(m | m.completed)->size()},
124 team = Tuple{
125 size = p.teamMembers->size(),
126 departments = p.teamMembers
127 ->collect(e | e.eContainer().name)->asSet()->size(),
128 avgExperience = p.teamMembers
129 ->collect(e | e.yearsOfService)->sum() / p.teamMembers->size()},
130 risks = Tuple{
131 blockedByDependencies = p.dependencies
132 ->exists(d | d.milestones->reject(m | m.completed)->notEmpty()),
133 understaffed = p.teamMembers->size() < 3,
134 overdue = p.milestones
135 ->exists(m | not m.completed and m.dueDate < '2024-06-01')}})"
136
137# Output: [{project: "Customer Portal", status: "Active", priority: 1,
138# budget: {...}, timeline: {...}, team: {...}, risks: {...}}]

Check Your Understanding

Question 1 of 4

What is the primary benefit of using let bindings in complex AQL queries?

Question 2 of 4

When would you use nested iterations in AQL queries?

Question 3 of 4

How do cross-model queries differ from single-model queries?

Question 4 of 4

What makes a query pattern “reusable”?

OCL Constraints and Validation

Learn to define and validate OCL constraints on Ecore models.