Skip to main content

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​

YAML
"@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
JSON
[
{
"@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. @plan references @scope, @suite references @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.
  • @copy must 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:1538 appears in both assetsCreated and assetsOperatedOn, 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. assetsCreated reports assets created by your create commands, not side effects of an operation.
  • Status comes back as { "_oid": "NULL" }, not null — an unset single-value relation is an object with the sentinel OID token NULL.
  • The downcast key is preserved. Children:Test is both the from value and the response key.
note

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.