Compound Requests
The features on the preceding pages compose. This page works through the suite's capstone example, which creates six assets across five asset types, invokes an operation on one of them, and queries the outcome — all in a single round trip.
Scenario
Automate regression-test setup end to end: create a Scope, a Regression Plan, a
Regression Suite and two Regression Tests, then create a Test Set bound to the
Suite, run CopyAcceptanceTestsFromRegressionSuite to generate Tests from the
Regression Tests, and read back what was produced.
The Request
"@scope":
AssetType: Scope
Name: Scope for Regression Test
Parent: Scope:0
BeginDate: 12/31/2019
---
"@plan":
AssetType: RegressionPlan
Name: Plan
Scope: "@scope"
---
"@suite":
AssetType: RegressionSuite
RegressionPlan: "@plan"
Name: Regression Suite
---
AssetType: RegressionTest
Name: Regression Test 1
Scope: "@scope"
RegressionSuites: "@suite"
---
AssetType: RegressionTest
Name: Regression Test 2
Scope: "@scope"
RegressionSuites: "@suite"
---
"@test-set":
AssetType: TestSet
Name: New TestSet
Scope: "@scope"
RegressionSuite: "@suite"
---
"@copy":
from: "@test-set"
execute: CopyAcceptanceTestsFromRegressionSuite
---
from: "@test-set"
select:
- Name
- Scope
- from: RegressionSuite
select:
- RegressionPlan
- from: Children:Test
select:
- Name
- GeneratedFrom
- Status
[
{
"@scope": {
"AssetType": "Scope", "Name": "Scope for Regression Test",
"Parent": "Scope:0", "BeginDate": "12/31/2019"
}
},
{ "@plan": { "AssetType": "RegressionPlan", "Name": "Plan", "Scope": "@scope" } },
{
"@suite": {
"AssetType": "RegressionSuite", "RegressionPlan": "@plan",
"Name": "Regression Suite"
}
},
{
"AssetType": "RegressionTest", "Name": "Regression Test 1",
"Scope": "@scope", "RegressionSuites": "@suite"
},
{
"AssetType": "RegressionTest", "Name": "Regression Test 2",
"Scope": "@scope", "RegressionSuites": "@suite"
},
{
"@test-set": {
"AssetType": "TestSet", "Name": "New TestSet",
"Scope": "@scope", "RegressionSuite": "@suite"
}
},
{ "@copy": { "from": "@test-set", "execute": "CopyAcceptanceTestsFromRegressionSuite" } },
{
"from": "@test-set",
"select": [
"Name",
"Scope",
{ "from": "RegressionSuite", "select": ["RegressionPlan"] },
{ "from": "Children:Test", "select": ["Name", "GeneratedFrom", "Status"] }
]
}
]
The Response
{
"assetsCreated": {
"oidTokens": [
"Scope:1533", "RegressionPlan:1534", "RegressionSuite:1535",
"RegressionTest:1536", "RegressionTest:1537", "TestSet:1538"
],
"count": 6
},
"assetsModified": { "oidTokens": [], "count": 0 },
"assetsOperatedOn": { "oidTokens": ["TestSet:1538"], "count": 1 },
"commandFailures": { "commands": [], "count": 0 },
"queryResult": {
"results": [
[
{
"_oid": "TestSet:1538",
"Name": "New TestSet",
"Children:Test": [
{
"_oid": "Test:1539",
"Name": "Regression Test 1",
"GeneratedFrom": { "_oid": "RegressionTest:1536" },
"Status": { "_oid": "NULL" }
},
{
"_oid": "Test:1540",
"Name": "Regression Test 2",
"GeneratedFrom": { "_oid": "RegressionTest:1537" },
"Status": { "_oid": "NULL" }
}
]
}
]
],
"count": 1
}
}
What to Notice
- Aliases chain.
@planreferences@scope,@suitereferences@plan, and the Regression Tests and Test Set reference both. None of these assets exists when the request is sent. - Mixed aliasing is fine. The two Regression Tests are left unaliased and are auto-aliased by the server; nothing else in the request needs to refer back to them.
@copymust be user-aliased. The operation targets@test-set, which does not exist at projection time. Aliasing the execute command defers it to the processing phase.- The query needs no alias. Queries are already evaluated after the commands preceding them.
TestSet:1538appears in bothassetsCreatedandassetsOperatedOn, because the request both created it and invoked an operation on it.- Assets created by the operation are not in
assetsCreated. The two generated Tests (Test:1539,Test:1540) appear only in the query result.assetsCreatedreports assets created by your create commands, not side effects of an operation. Statuscomes back as{ "_oid": "NULL" }, notnull— an unset single-value relation is an object with the sentinel OID tokenNULL.- The downcast key is preserved.
Children:Testis both thefromvalue and the response key.
An unset single-value relation selects back as { "_oid": "NULL" } — a string
sentinel, not JSON null.
A Smaller Variant
If the Regression Suite and its Regression Tests already exist, the request collapses to three commands:
[
{
"@test-set": {
"AssetType": "TestSet", "Name": "Tests",
"Scope": "Scope:1503", "RegressionSuite": "RegressionSuite:1505"
}
},
{ "@copy": { "from": "@test-set", "execute": "CopyAcceptanceTestsFromRegressionSuite" } },
{
"from": "@test-set",
"select": [
"Name",
{ "from": "Children:Test", "select": ["Name", "GeneratedFrom", "Status"] }
]
}
]
This is the same pattern — create, defer an operation onto the created asset, read back — and it is the shape most system-to-system synchronisation code ends up with.