( workflowId: string, state: WorkflowState, externalTx?: DbOrTx )
| 13 | type SubflowInsert = InferInsertModel<typeof workflowSubflows> |
| 14 | |
| 15 | export async function saveWorkflowToNormalizedTables( |
| 16 | workflowId: string, |
| 17 | state: WorkflowState, |
| 18 | externalTx?: DbOrTx |
| 19 | ): Promise<{ success: boolean; error?: string }> { |
| 20 | const blockRecords = state.blocks as Record<string, BlockState> |
| 21 | const canonicalLoops = generateLoopBlocks(blockRecords) |
| 22 | const canonicalParallels = generateParallelBlocks(blockRecords) |
| 23 | |
| 24 | const execute = async (tx: DbOrTx) => { |
| 25 | await Promise.all([ |
| 26 | tx.delete(workflowBlocks).where(eq(workflowBlocks.workflowId, workflowId)), |
| 27 | tx.delete(workflowEdges).where(eq(workflowEdges.workflowId, workflowId)), |
| 28 | tx.delete(workflowSubflows).where(eq(workflowSubflows.workflowId, workflowId)), |
| 29 | ]) |
| 30 | |
| 31 | if (Object.keys(state.blocks).length > 0) { |
| 32 | const blockInserts = Object.values(state.blocks).map((block) => ({ |
| 33 | id: block.id, |
| 34 | workflowId, |
| 35 | type: block.type, |
| 36 | name: block.name || '', |
| 37 | positionX: String(block.position?.x || 0), |
| 38 | positionY: String(block.position?.y || 0), |
| 39 | enabled: block.enabled ?? true, |
| 40 | horizontalHandles: block.horizontalHandles ?? true, |
| 41 | advancedMode: block.advancedMode ?? false, |
| 42 | triggerMode: block.triggerMode ?? false, |
| 43 | height: String(block.height || 0), |
| 44 | subBlocks: block.subBlocks || {}, |
| 45 | outputs: block.outputs || {}, |
| 46 | data: block.data || {}, |
| 47 | parentId: block.data?.parentId || null, |
| 48 | extent: block.data?.extent || null, |
| 49 | locked: block.locked ?? false, |
| 50 | })) |
| 51 | |
| 52 | await tx.insert(workflowBlocks).values(blockInserts) |
| 53 | } |
| 54 | |
| 55 | if (state.edges.length > 0) { |
| 56 | const edgeInserts = state.edges.map((edge) => ({ |
| 57 | id: edge.id, |
| 58 | workflowId, |
| 59 | sourceBlockId: edge.source, |
| 60 | targetBlockId: edge.target, |
| 61 | sourceHandle: edge.sourceHandle || null, |
| 62 | targetHandle: edge.targetHandle || null, |
| 63 | })) |
| 64 | |
| 65 | await tx.insert(workflowEdges).values(edgeInserts) |
| 66 | } |
| 67 | |
| 68 | const subflowInserts: SubflowInsert[] = [] |
| 69 | |
| 70 | Object.values(canonicalLoops).forEach((loop) => { |
| 71 | subflowInserts.push({ |
| 72 | id: loop.id, |
nothing calls this directly
no test coverage detected