# API Reference: SOrchestrator

`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](/apex-stem/docs/apex-blueprint-sorchestrator-guide).

## Static Factory

| Method | Purpose |
|---|---|
| `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

| Method | Purpose |
|---|---|
| `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

| Method | Purpose |
|---|---|
| `getByAlias(String aliasName)` | After `create()`, retrieve the created SObject by alias. Returns `SObject` (caller casts) |

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)

| Situation | Exception 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 chain | `ApexBlueprintException`: `Duplicate alias detected` |
| Duplicate alias across different `.add(...)` calls | `ApexBlueprintException`: `Duplicate alias detected` |
| Reference to a non-existent alias via `.use(...)` | `ApexBlueprintException`: `Circular or invalid reference detected` (internally the same category) |
| Child has multiple lookups but no `parentIdField` | `ApexBlueprintException`: `multiple parent relationships with the same parent object` |
| 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 `DmlException`s, so existing `catch (DmlException)` blocks will no longer catch them.

## Related Documents

- [Resolving Dependencies and Executing DML with SOrchestrator](/apex-stem/docs/apex-blueprint-sorchestrator-guide): How to use start / add / create / getByAlias
- [API Reference: SBlueprint](/apex-stem/docs/apex-blueprint-api-sblueprint): The API for the blueprints you pass to `.add(...)`
- [Relations, Bulk Generation, and Reference Patterns](/apex-stem/docs/apex-blueprint-relations-and-bulk): Applications of `withChildren` / `times` / `{P0}` etc.
- [Back to the ApexBlueprint Guide](/apex-stem/docs/apex-blueprint-guide)
