# API リファレンス: SBlueprint

`SBlueprint` は ApexBlueprint で **単一レコードの設計図** を宣言するメソッドチェーンクラス。`of(...)` で起点を作り、値・identifier・親子関係・量産・参照などをチェーンで積み重ねて、最終的に `SOrchestrator` に渡して実行します。

使い方や典型シナリオは [SBlueprint で単一レコードを宣言する](/ja/apex-stem/docs/apex-blueprint-sblueprint-guide) と [親子・量産・参照のパターン](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk) を参照してください。

## Static ファクトリ

| メソッド | 用途 |
|---|---|
| `SBlueprint.of(System.Type recordType)` | SBlueprint の起点。`SBlueprint.of(Account.class)` の形式で、対象 SObject タイプを宣言 |

`recordType` に `null` や非 SObject 型を渡すと例外が投げられます。

## 値設定 (Set & Template)

| メソッド | 用途 |
|---|---|
| `set(String fieldName, Object value)` | 単一フィールドに値をセット。同じフィールドへの再呼び出しは last wins。`template` の値も上書き可能 |
| `set(String fieldName, Object value, Integer startAt, Integer interval)` | `{#}` プレースホルダの **起点** と **刻み** を指定。`set('Name', 'Acc-{#}', 10, 2)` → `'Acc-10'` / `'Acc-12'` / `'Acc-14'` |
| `template(Map<String, Object> templateMap)` | デフォルト値の Map をまとめて適用。RecordType / 必須項目などの共通設定を `Blueprints.cls` に集約する運用との組み合わせを推奨 |

`startAt` / `interval` に **負の値** を渡すと例外が投げられます。

```apex
SBlueprint accountBp = SBlueprint.of(Account.class)
    .template(Blueprints.accBasic())     // 共通デフォルト
    .set('Name', 'CustomName')              // 個別上書き
    .set('Index', 'No.{#}', 1, 1);          // {#} 連番
```

## 識別子 (Alias)

| メソッド | 用途 |
|---|---|
| `alias(String aliasName)` | この blueprint に一意な参照名を付ける。後で `.use(alias, ...)` や `SOrchestrator.getByAlias(alias)` から参照可能 |
| `alias(String aliasName, Integer startAt)` | `{#}` を含む alias で、展開の起点を指定 |
| `alias(String aliasName, Integer startAt, Integer interval)` | 起点 + 刻みを指定 |

alias は `SOrchestrator` 内で **一意である必要** があり、重複すると `Duplicate alias detected` で実行時エラーになります。`.times(n)` と組み合わせる場合は `'con_{#}'` のような `{#}` 付き alias を使って、展開後に一意な値が払い出されるようにします。

```apex
SBlueprint.of(Contact.class)
    .alias('con_{#}')        // con_1 / con_2 / con_3
    .times(3);
```

## 参照 (Use)

別の blueprint からの値を、自分のフィールドにマッピングする多目的 API。「Id を子の lookup に転記する (リレーション作成)」と「任意のフィールド値を引き写す」の両方に使えます。

| メソッド | 用途 |
|---|---|
| `use(String aliasName, String fromField, String toField)` | 基本形。`aliasName` blueprint の `fromField` を、自分の `toField` にコピー |
| `use(String aliasName, String fromField, String toField, Integer startAt)` | `{#}` プレースホルダ付きの alias を参照する場合の起点を指定 |
| `use(String aliasName, String fromField, String toField, Integer startAt, Integer interval)` | 起点 + 刻みを指定 |

`startAt` / `interval` に **負の値** を渡すと例外が投げられます。詳細な使い方や「不揃いな対応」のパターンは [親子・量産・参照のパターン](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk) を参照してください。

```apex
SBlueprint.of(Contact.class)
    .use('acc_{#}', 'Id', 'AccountId', 6)   // acc_6 〜 acc_10 を参照
    .alias('con_{#}', 6)                    // 子側も 6 始まり
    .times(5);
```

## 量産 (Times)

| メソッド | 用途 |
|---|---|
| `times(Integer n)` | 同じ blueprint を `n` 件生成。`n <= 0` を渡すと例外 |

`.times(n)` を **`.withChildren(...)` のネスト内** で使うと、件数は階層をまたいで掛け算で増えます (親 2 × 子 2 = 子 4 件)。詳細は [親子・量産・参照のパターン > Multiplication](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk) を参照。

## 順序だけの依存 (After)

| メソッド | 用途 |
|---|---|
| `after(String alias)` | 値のコピーなしに「この alias より後のレイヤーで insert する」とだけ宣言 |
| `after(String alias, Integer startAt)` | `{#}` を含む alias を参照する場合の起点を指定 |
| `after(String alias, Integer startAt, Integer interval)` | 起点 + 刻みを指定 |

`use()` は「参照を作る」ため、値のコピーが伴います。**値は要らないが順序だけ守りたい**とき、たとえばトリガーの都合で「A が入ってから B を入れたい」ようなケースに `after()` を使います。

```apex
SOrchestrator.start()
  .add(SBlueprint.of(Account.class).template(Blueprints.accBasic()).alias('acc'))
  .add(
    SBlueprint.of(Contact.class)
      .set('LastName', 'Yamada')
      .after('acc')   // acc より後のレイヤーに置くだけ。値は引かない
  );
```

## 所有者と共有 (Owner & Share)

| メソッド | 用途 |
|---|---|
| `owner(User user)` | レコードの所有者を設定。`set('OwnerId', user.Id)` の糖衣 |
| `sharedWith(User user, String accessLevel)` | **手動共有を最終状態として宣言**。`accessLevel` は `'Read'` / `'Edit'` |

`sharedWith` を書くと、`create()` の際に `Foo__Share` / `AccountShare` といった**兄弟 blueprint が自動生成**され、そのレコードの 1 レイヤー後に insert されます。親 Id の配線も自動です。

「誰がこのレコードを持っていて、誰から見えるのか」は項目値と同じく**宣言された最終状態の一部**、という考え方から blueprint 側に置かれています。

```apex
// 管理者が所有し、rep には Read だけ与える = runAs 監査テストの「敵対的データ」
SOrchestrator.start()
  .add(
    SBlueprint.of(Invoice__c.class).alias('inv')
      .owner(admin)
      .sharedWith(rep, 'Read')
  );
```

`times` / ネスト / `{Pn}` と合成できます (子の共有は子と一緒に増殖します)。OWD が Public のオブジェクト、所有者自身への共有、不正な `accessLevel` は **fail-fast** で弾かれます。

## 親子関係

| メソッド | 用途 |
|---|---|
| `withChildren(SBlueprint child)` | 親 blueprint の中に子をネストする。子の lookup には親 Id が自動転記される。同じ親に異なる SObject 型の子を並べる場合は `.withChildren(...).withChildren(...)` のように複数回呼べる |
| `parentIdField(String fieldName)` | 子が複数の lookup を持っているとき、親 Id を入れるフィールドを明示。曖昧でない場合は不要 |

```apex
SBlueprint.of(Account.class)
    .alias('acc')
    .withChildren(
        SBlueprint.of(Contact.class)
            .parentIdField('AccountId')      // 複数 lookup を持つ場合に明示
            .set('LastName', 'TestContact')
    );
```

## プレースホルダ

`.set` / `.alias` / `.use` の文字列引数の中で使える特殊プレースホルダ。

| プレースホルダ | 展開ルール |
|---|---|
| `{#}` | `1`, `2`, `3`, ... の数値連番。`.times(n)` で n 件分展開される。`startAt` / `interval` を指定すると起点・刻みを変えられる |
| `{A}` | `'A'`, `'B'`, `'C'`, ... の大文字アルファベット連番 |
| `{a}` | `'a'`, `'b'`, `'c'`, ... の小文字アルファベット連番 |
| `{P0}` / `{P1}` / `{P2}` / ... | **ルートから数えた絶対深度** で、自分にとっての真の親を階層的に解決。主に `.use('{P1}', ...)` のように `use` の第 1 引数で「自分の真の親」を参照するのに使う |

`{P0}` 〜 `{Pn}` は `.times(...)` で量産された親階層を持つネスト構造で、alias の `{#}` 展開だけでは「自分の真の親」を特定できない問題への構造的な解決手段です。動機と仕組みは [親子・量産・参照のパターン > {P0} / {P1} / ...](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk) を参照してください。

## 主な例外

フレームワークが検出したエラーは **`ApexBlueprintException`** として投げられます。

| 状況 | 例外型 / メッセージ (抜粋) |
|---|---|
| `of(...)` に null や非 SObject 型 | `ApexBlueprintException`: invalid type |
| `times(0)` 以下 | `ApexBlueprintException`: `Times must be greater than 0` |
| `set` / `alias` / `use` の `startAt` / `interval` に負の値 | `ApexBlueprintException`: negative value not allowed |
| alias 重複 (`create()` 時) | `ApexBlueprintException`: `Duplicate alias detected` |
| 存在しない alias 参照 (`use` の typo など、`create()` 時) | `ApexBlueprintException`: `Circular or invalid reference detected` |
| 複数 lookup の曖昧 (`parentIdField` 未指定、`create()` 時) | `ApexBlueprintException`: `multiple parent relationships with the same parent object` |
| 項目適用の失敗 (存在しない / 数式 / 自動採番 / 作成不可 / 型不一致) | `ApexBlueprintException`: 診断つき (`Reason:` に理由、`Provided:` に値) |
| 必須項目の欠落・入力規則違反 | **通常の `DmlException` がそのまま** |

### 例外型で原因を切り分けられる

`create()` が失敗したとき、**例外の型がそのまま原因の切り分けになります**。

- **`ApexBlueprintException`** = 宣言のミス。**テストコードを直す**
- **`DmlException`** = org が insert を拒否した。**template か org 設定を直す**

項目適用のエラーは「どの blueprint (alias) の・どの経路 (`set` / `template` / `use`) で・なぜ (存在しない / 数式 / 自動採番 / 作成不可 / 型不一致)」まで自動で診断されます。

> ⚠️ v2.0.0 の破壊的変更です。それ以前は素の `DmlException` が投げられていたため、**既存の `catch (DmlException)` では捕まらなくなります**。移行時は catch 節の見直しが必要です。

## 関連ドキュメント

- [SBlueprint で単一レコードを宣言する](/ja/apex-stem/docs/apex-blueprint-sblueprint-guide): 基本 5 メソッドの使い方
- [親子・量産・参照のパターン](/ja/apex-stem/docs/apex-blueprint-relations-and-bulk): `withChildren` / `times` / `{P0}` 等の応用
- [API リファレンス: SOrchestrator](/ja/apex-stem/docs/apex-blueprint-api-sorchestrator): 実行エンジン側の API
- [ApexBlueprint ガイドへ戻る](/ja/apex-stem/docs/apex-blueprint-guide)
