(sql: SqlClient, org: OrgPlan)
| 233 | `${operationStorageKey(integration, "").split(".").slice(0, 2).join(".")}.%`; |
| 234 | |
| 235 | export const applyOrg = async (sql: SqlClient, org: OrgPlan): Promise<void> => { |
| 236 | if (org.completed) return; |
| 237 | if (org.hardErrors.length > 0) { |
| 238 | throw new Error(`org ${org.tenantHash} has unresolved hard errors; apply is blocked`); |
| 239 | } |
| 240 | await sql.begin(async (tx) => { |
| 241 | const now = new Date(); |
| 242 | for (const copy of org.blobCopies.filter((item) => item.backend === "database")) { |
| 243 | const [source] = await tx.unsafe<{ readonly value: string }[]>( |
| 244 | "SELECT value FROM blob WHERE namespace = $1 AND key = $2 LIMIT 1", |
| 245 | [copy.sourceNamespace, copy.key], |
| 246 | ); |
| 247 | if (!source) { |
| 248 | throw new Error(`Missing source blob ${copy.sourceNamespace}/${copy.key}`); |
| 249 | } |
| 250 | await tx.unsafe( |
| 251 | ` |
| 252 | INSERT INTO blob (namespace, key, value, row_id, id) |
| 253 | VALUES ($1, $2, $3, $4, $5) |
| 254 | ON CONFLICT (id) DO NOTHING |
| 255 | `, |
| 256 | [ |
| 257 | copy.targetNamespace, |
| 258 | copy.key, |
| 259 | source.value, |
| 260 | stableId("blob", org.tenant, copy.targetNamespace, copy.key), |
| 261 | JSON.stringify([copy.targetNamespace, copy.key]), |
| 262 | ], |
| 263 | ); |
| 264 | } |
| 265 | |
| 266 | for (const row of org.integrations.filter((item) => item.action === "create")) { |
| 267 | await tx.unsafe( |
| 268 | ` |
| 269 | INSERT INTO integration ( |
| 270 | slug, plugin_id, name, description, config, health_check, config_revised_at, |
| 271 | can_remove, can_refresh, created_at, updated_at, row_id, tenant |
| 272 | ) |
| 273 | VALUES ($1, $2, $3, $4, $5::json, $6::json, NULL, true, true, $7, $7, $8, $9) |
| 274 | ON CONFLICT (tenant, slug) DO NOTHING |
| 275 | `, |
| 276 | [ |
| 277 | row.target.slug, |
| 278 | row.target.pluginId, |
| 279 | row.target.name, |
| 280 | row.target.description, |
| 281 | JSON.stringify(scrubJson(row.config)), |
| 282 | row.healthCheck ? JSON.stringify(scrubJson(row.healthCheck)) : null, |
| 283 | now, |
| 284 | stableId("integration", org.tenant, row.target.slug), |
| 285 | org.tenant, |
| 286 | ], |
| 287 | ); |
| 288 | } |
| 289 | |
| 290 | for (const row of org.connections.filter((item) => item.action === "clone")) { |
| 291 | await tx.unsafe( |
| 292 | ` |
no test coverage detected