(routine: Routine, args: Record<string, unknown> = {}, ctx?: Transaction)
| 93 | } |
| 94 | |
| 95 | override async callRoutine<T>(routine: Routine, args: Record<string, unknown> = {}, ctx?: Transaction): Promise<T> { |
| 96 | if (routine.type === 'function') { |
| 97 | return this.callRoutineFunction(routine, args, ctx); |
| 98 | } |
| 99 | |
| 100 | const name = this.platform.quoteIdentifier(routine.name); |
| 101 | |
| 102 | const callPlaceholders: string[] = []; |
| 103 | const callValues: unknown[] = []; |
| 104 | const outVarParams: { name: string; varName: string; param: (typeof routine.params)[number] }[] = []; |
| 105 | |
| 106 | routine.params.forEach((p, i) => { |
| 107 | if (p.direction === 'in') { |
| 108 | callPlaceholders.push('?'); |
| 109 | callValues.push(this.convertRoutineInbound(args[p.name as string], p)); |
| 110 | return; |
| 111 | } |
| 112 | |
| 113 | const varName = `@_mikro_orm_routine_${i}`; |
| 114 | outVarParams.push({ name: p.name as string, varName, param: p }); |
| 115 | callPlaceholders.push(varName); |
| 116 | }); |
| 117 | |
| 118 | // MySQL `@var`s are connection-scoped, so SET + CALL + SELECT must share one physical |
| 119 | // connection — wrap in an implicit transaction when the caller didn't supply one. |
| 120 | const needsConnectionAffinity = outVarParams.length > 0 && !ctx; |
| 121 | const runSteps = async (sharedCtx: Transaction | undefined): Promise<T> => { |
| 122 | for (let i = 0; i < routine.params.length; i++) { |
| 123 | const p = routine.params[i]; |
| 124 | if (p.direction === 'inout') { |
| 125 | const varName = `@_mikro_orm_routine_${i}`; |
| 126 | await this.execute( |
| 127 | `set ${varName} := ?`, |
| 128 | [this.convertRoutineInbound(args[p.name as string], p)], |
| 129 | 'run', |
| 130 | sharedCtx, |
| 131 | ); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // mysql2 trails the result sets with an OK packet (non-array); filter to row arrays. |
| 136 | const callResult = (await this.execute( |
| 137 | `call ${name}(${callPlaceholders.join(', ')})`, |
| 138 | callValues, |
| 139 | 'all', |
| 140 | sharedCtx, |
| 141 | )) as unknown[]; |
| 142 | const resultSets = callResult.filter(Array.isArray) as Dictionary[][]; |
| 143 | |
| 144 | if (outVarParams.length > 0) { |
| 145 | const selectClause = outVarParams |
| 146 | .map(o => `${o.varName} as ${this.platform.quoteIdentifier(o.name)}`) |
| 147 | .join(', '); |
| 148 | const rows = (await this.execute(`select ${selectClause}`, [], 'all', sharedCtx)) as Dictionary[]; |
| 149 | this.applyRoutineOutParams( |
| 150 | rows[0] ?? {}, |
| 151 | outVarParams.map(o => o.param), |
| 152 | args, |
nothing calls this directly
no test coverage detected