in scio-core/src/main/scala/com/spotify/scio/util/MultiJoin.scala [2812:2867]
def outer[KEY, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V](a: SCollection[(KEY, A)], b: SCollection[(KEY, B)], c: SCollection[(KEY, C)], d: SCollection[(KEY, D)], e: SCollection[(KEY, E)], f: SCollection[(KEY, F)], g: SCollection[(KEY, G)], h: SCollection[(KEY, H)], i: SCollection[(KEY, I)], j: SCollection[(KEY, J)], k: SCollection[(KEY, K)], l: SCollection[(KEY, L)], m: SCollection[(KEY, M)], n: SCollection[(KEY, N)], o: SCollection[(KEY, O)], p: SCollection[(KEY, P)], q: SCollection[(KEY, Q)], r: SCollection[(KEY, R)], s: SCollection[(KEY, S)], t: SCollection[(KEY, T)], u: SCollection[(KEY, U)], v: SCollection[(KEY, V)]): SCollection[(KEY, (Option[A], Option[B], Option[C], Option[D], Option[E], Option[F], Option[G], Option[H], Option[I], Option[J], Option[K], Option[L], Option[M], Option[N], Option[O], Option[P], Option[Q], Option[R], Option[S], Option[T], Option[U], Option[V]))] = {
implicit val keyCoder = a.keyCoder
implicit val (coderA, coderB, coderC, coderD, coderE, coderF, coderG, coderH, coderI, coderJ, coderK, coderL, coderM, coderN, coderO, coderP, coderQ, coderR, coderS, coderT, coderU, coderV) = (a.valueCoder, b.valueCoder, c.valueCoder, d.valueCoder, e.valueCoder, f.valueCoder, g.valueCoder, h.valueCoder, i.valueCoder, j.valueCoder, k.valueCoder, l.valueCoder, m.valueCoder, n.valueCoder, o.valueCoder, p.valueCoder, q.valueCoder, r.valueCoder, s.valueCoder, t.valueCoder, u.valueCoder, v.valueCoder)
val (tagA, tagB, tagC, tagD, tagE, tagF, tagG, tagH, tagI, tagJ, tagK, tagL, tagM, tagN, tagO, tagP, tagQ, tagR, tagS, tagT, tagU, tagV) = (new TupleTag[A](), new TupleTag[B](), new TupleTag[C](), new TupleTag[D](), new TupleTag[E](), new TupleTag[F](), new TupleTag[G](), new TupleTag[H](), new TupleTag[I](), new TupleTag[J](), new TupleTag[K](), new TupleTag[L](), new TupleTag[M](), new TupleTag[N](), new TupleTag[O](), new TupleTag[P](), new TupleTag[Q](), new TupleTag[R](), new TupleTag[S](), new TupleTag[T](), new TupleTag[U](), new TupleTag[V]())
val keyed = KeyedPCollectionTuple
.of(tagA, a.toKV.internal)
.and(tagB, b.toKV.internal)
.and(tagC, c.toKV.internal)
.and(tagD, d.toKV.internal)
.and(tagE, e.toKV.internal)
.and(tagF, f.toKV.internal)
.and(tagG, g.toKV.internal)
.and(tagH, h.toKV.internal)
.and(tagI, i.toKV.internal)
.and(tagJ, j.toKV.internal)
.and(tagK, k.toKV.internal)
.and(tagL, l.toKV.internal)
.and(tagM, m.toKV.internal)
.and(tagN, n.toKV.internal)
.and(tagO, o.toKV.internal)
.and(tagP, p.toKV.internal)
.and(tagQ, q.toKV.internal)
.and(tagR, r.toKV.internal)
.and(tagS, s.toKV.internal)
.and(tagT, t.toKV.internal)
.and(tagU, u.toKV.internal)
.and(tagV, v.toKV.internal)
.apply(s"CoGroupByKey@$tfName", CoGroupByKey.create())
a.context.wrap(keyed).withName(tfName).flatMap { kv =>
val (key, result) = (kv.getKey, kv.getValue)
for {
v <- toOptions(result.getAll(tagV).asScala.iterator)
u <- toOptions(result.getAll(tagU).asScala.iterator)
t <- toOptions(result.getAll(tagT).asScala.iterator)
s <- toOptions(result.getAll(tagS).asScala.iterator)
r <- toOptions(result.getAll(tagR).asScala.iterator)
q <- toOptions(result.getAll(tagQ).asScala.iterator)
p <- toOptions(result.getAll(tagP).asScala.iterator)
o <- toOptions(result.getAll(tagO).asScala.iterator)
n <- toOptions(result.getAll(tagN).asScala.iterator)
m <- toOptions(result.getAll(tagM).asScala.iterator)
l <- toOptions(result.getAll(tagL).asScala.iterator)
k <- toOptions(result.getAll(tagK).asScala.iterator)
j <- toOptions(result.getAll(tagJ).asScala.iterator)
i <- toOptions(result.getAll(tagI).asScala.iterator)
h <- toOptions(result.getAll(tagH).asScala.iterator)
g <- toOptions(result.getAll(tagG).asScala.iterator)
f <- toOptions(result.getAll(tagF).asScala.iterator)
e <- toOptions(result.getAll(tagE).asScala.iterator)
d <- toOptions(result.getAll(tagD).asScala.iterator)
c <- toOptions(result.getAll(tagC).asScala.iterator)
b <- toOptions(result.getAll(tagB).asScala.iterator)
a <- toOptions(result.getAll(tagA).asScala.iterator)
} yield (key, (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v))
}
}