| 1 | /** |
| 2 | * Adds the nullable `provider_instance_id` routing column to |
| 3 | * `provider_session_runtime`. |
| 4 | * |
| 5 | * Slice D of the provider-array refactor splits "driver kind" from |
| 6 | * "configured instance". Existing rows have only the driver name in |
| 7 | * `provider_name`; new rows additionally carry the user-defined instance |
| 8 | * routing key. The column remains nullable so legacy rows can still decode; |
| 9 | * the persistence boundary is responsible for materializing a concrete |
| 10 | * instance id before any hot routing path sees the binding. |
| 11 | * |
| 12 | * The column is nullable on purpose — backfilling it during the migration |
| 13 | * would require knowing which configured instance "owned" each historical |
| 14 | * session, and that mapping is ambiguous when the user later configures |
| 15 | * multiple instances of the same driver. Keeping that compatibility at the |
| 16 | * persistence boundary keeps the fallback out of active routing code. |
| 17 | */ |
| 18 | import * as SqlClient from "effect/sql/SqlClient"; |
| 19 | import * as Effect from "effect/Effect"; |
| 20 | |
| 21 | export default Effect.gen(function* () { |
| 22 | const sql = yield* SqlClient.SqlClient; |
| 23 | |
| 24 | const columns = yield* sql<{ readonly name: string }>` |
| 25 | PRAGMA table_info(provider_session_runtime) |
| 26 | `; |
| 27 | if (!columns.some((column) => column.name === "provider_instance_id")) { |
| 28 | yield* sql` |
| 29 | ALTER TABLE provider_session_runtime |
| 30 | ADD COLUMN provider_instance_id TEXT |
| 31 | `; |
| 32 | } |
| 33 | |
| 34 | yield* sql` |
| 35 | CREATE INDEX IF NOT EXISTS idx_provider_session_runtime_instance |
| 36 | ON provider_session_runtime(provider_instance_id) |
| 37 | `; |
| 38 | }); |