Цепочка фьючерсов с типами кортежей - PullRequest
0 голосов
/ 27 июня 2018

Мне часто нужно пропустить несколько объектов через ряд связанных Фьючерсов. Я решил проблему с кодом, похожим на приведенный ниже, но он не кажется «правильным». Есть ли лучший способ написать это?

В частности, строки, начинающиеся с return map(to:, не имеют правильного запаха, поскольку я беру фактическое значение a, а затем превращаю его в будущее conn.future(a), чтобы потом снова снова отобразить плоскую карту на следующем шаге.

В нижеприведенном надуманном примере мы создаем A со связанным объектом B и, необязательно, C, который связан с B, поэтому B должен быть пропущен через цепь.

class A {
  id: Int?
}
class B {
  id: Int?
  aId: Int?
}
class C {
  id: Int?
  bId: Int?
}

/// Creates an A and B, with an optionally attached C. Returns the A.
func create(withC: Bool, on conn: MySQLConnection) throws -> Future<A> {
  return try A.create(on: conn)
    // Returning two futures
    .flatMap(to: (A, B).self) { a in
      let futureB = try B(aId: a.requireID()).create(on: conn)
      return map(to: (A, B).self, conn.future(a), futureB) { ($0, $1) }
    }
    // Returning two futures, one optional
    .flatMap(to: (A, C?).self) { a, b in
      guard withC else {
        return map(to: (A, C?).self, conn.future(a), conn.future(nil)) { ($0, $1) }
      }
      let futureC = try C(bId: b.requireId()).create(on: conn)
      return map(to: (A, C?).self, conn.future(a), futureC) { ($0, $1) }
    }
    // Convert back to the future we care about
    .map(to: A.self) { a, _ in return a }
}
...