ApexBlueprint API reference: SOrchestrator

•Apex Stem Docs
Apex StemApexBlueprintSOrchestratorAPI Reference
Complete API reference for the SOrchestrator execution engine. Covers the static factory (including MockDmlOperator injection), add / create / getByAlias, and the exceptions raised on circular references, duplicate aliases, invalid references, and ambiguous lookups.

SOrchestrator is the execution engine of ApexBlueprint. It takes the blueprints assembled by SBlueprint, analyzes their dependencies via topological sort, and runs DML inserts in the correct order. The API is intentionally limited to just four methods.

For usage and typical scenarios, see Resolving Dependencies and Executing DML with SOrchestrator.

Static Factory

MethodPurpose
SOrchestrator.start()For normal use. Uses the standard DML executor internally
SOrchestrator.start(IDmlOperator dmlOperator)Swap out the DML execution layer. In tests, pass new MockDmlOperator() to verify behavior without firing real DML
APEX
// Production (real DML)
SOrchestrator orchestrator = SOrchestrator.start();
 
// Tests (no DML — the pattern used inside ApexBlueprint's own tests)
SOrchestrator orchestrator = SOrchestrator.start(new MockDmlOperator());

MockDmlOperator is included inside the ApexBlueprint OSS (DmlOperators/) and is used primarily when writing ApexBlueprint's own tests. For ordinary test data generation, use SOrchestrator.start() (no arguments).

Registration and Execution

MethodPurpose
add(SBlueprint blueprint)Register a single SBlueprint into the queue. Addition order is ignored (internal topological sort determines the insertion order)
create()Analyze all registered blueprints and run DML inserts after dependency resolution. Returns void — capture the SOrchestrator first, then call create() on it
APEX
SOrchestrator orchestrator = SOrchestrator.start()
    .add(SBlueprint.of(Account.class).alias('parentAccount').template(Blueprints.accBasic()))
    .add(
        SBlueprint.of(Opportunity.class)
            .set('Name', 'Test Opportunity')
            .use('parentAccount', 'Id', 'AccountId')
            .alias('targetOpp')
    );
orchestrator.create();

Retrieving Results

MethodPurpose
getByAlias(String aliasName)After create(), retrieve the created SObject by alias. Returns SObject (caller casts)

Every returned record holds its Id and the fields set in the blueprint; fields you did not set are null. A record whose non-Id field was read by a later layer's use() also holds the saved values of the fields read back (v2.2.0+). Other values filled on save are not there, so query the record again if you need them.

Passing a non-existent alias returns null (not an exception), so if typos are easy to miss, guard with Assert.isNotNull(...) right after retrieval.

APEX
Account parent = (Account) orchestrator.getByAlias('parentAccount');
Opportunity opp = (Opportunity) orchestrator.getByAlias('targetOpp');

Blueprints bulked via .times(...) can be retrieved individually by their post-expansion alias names ('con_1' / 'con_2' / ...). Blueprints nested via withChildren are assigned auto-generated aliases like __Account_0_1_____Contact_1_1__, so attach an explicit .alias(...) whenever you need to retrieve them.

Common Exceptions (at create() Time)

SituationException type / message (excerpt)
Circular dependency (both A.use('B', ...) and B.use('A', ...) hold)ApexBlueprintException: Circular or invalid reference detected
Duplicate alias within the same blueprint chainApexBlueprintException: Duplicate alias detected
Duplicate alias across different .add(...) callsApexBlueprintException: Duplicate alias detected
Reference to a non-existent alias via .use(...)ApexBlueprintException: Circular or invalid reference detected (internally the same category)
A {#}-expanded alias that does not exist (shifted startAt or too few records)ApexBlueprintException: Alias '...' not found. Available aliases: ...
Child has multiple lookups but no parentIdFieldApexBlueprintException: multiple parent relationships with the same parent object
No lookup at all between a withChildren parent and childApexBlueprintException: No parent relationship field found between ...
The source record of a use() cannot be read back to copy its saved values (deleted by a trigger, a custom IDmlOperator that does not write to the database, etc.)ApexBlueprintException: could not be read back (v2.2.0+)
A saved value copied by use() does not fit the type of the target fieldApexBlueprintException: could not be copied (v2.2.0+)
Conditions that fail standard Apex DML (missing required fields, validation rule violations, etc.)A plain DmlException, unchanged

The type of the exception is itself the diagnosis. ApexBlueprintException means a mistake in the declaration (fix the test code); DmlException means the org refused the insert (fix the template or the org configuration).

⚠️ This is a breaking change in v2.0.0. Framework validation errors used to be plain DmlExceptions, so existing catch (DmlException) blocks will no longer catch them.

Large Layers Are Split Automatically (v2.2.0+)

Salesforce does not accept a single insert with more than 10 object types, or more than 10 chunks (a chunk ends where the type changes, and in a list of mixed types, also every 200 records of the same type). Up to v2.1.0, all records of a layer were inserted at once, so it failed when 11 types were lined up, when 2 types were added alternately, or when 6 types were created with 201 records each. From v2.2.0, records keep the order they were added in, and the insert is split only where a limit would be exceeded. A layer that passed before is still one insert, in the same order.