-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
145 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
extensions-api/src/main/scala/pl/touk/nussknacker/engine/migration/ProcessMigrations.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package pl.touk.nussknacker.engine.migration | ||
|
||
import cats.data.NonEmptyList | ||
import cats.syntax.functor._ | ||
import pl.touk.nussknacker.engine.migration.ProcessMigrations.CombineError.OverlappingMigrations | ||
import pl.touk.nussknacker.engine.migration.ProcessMigrations.MigrationNumber | ||
|
||
object ProcessMigrations { | ||
|
||
type MigrationNumber = Int | ||
|
||
def empty: ProcessMigrations = new ProcessMigrations { | ||
override def processMigrations: Map[MigrationNumber, ProcessMigration] = Map() | ||
} | ||
|
||
def combine(processMigrationsList: List[ProcessMigrations]): Either[CombineError, ProcessMigrations] = { | ||
processMigrationsList match { | ||
case Nil => Right(empty) | ||
case one :: Nil => Right(one) | ||
case many => combineAtLeastTwoListOfMigrations(many) | ||
} | ||
} | ||
|
||
private def combineAtLeastTwoListOfMigrations(processMigrationsList: List[ProcessMigrations]) = { | ||
val migrationNumberToOrigins: Map[MigrationNumber, List[ProcessMigrations]] = | ||
processMigrationsList | ||
.flatMap(pm => pm.processMigrations.keys.toList.tupleRight(pm)) | ||
.groupBy(_._1) | ||
.map { case (migrationNumber, migrationNumberAndOriginList) => | ||
migrationNumber -> migrationNumberAndOriginList.map(_._2) | ||
} | ||
val overlappingMigrationNumbers = migrationNumberToOrigins.filter { case (_, origins) => origins.size >= 2 } | ||
if (overlappingMigrationNumbers.nonEmpty) { | ||
Left(OverlappingMigrations(overlappingMigrationNumbers)) | ||
} else { | ||
val combined = processMigrationsList | ||
.map(_.processMigrations) | ||
.reduceLeft((combinedMigrations, migrations) => combinedMigrations ++ migrations) | ||
Right(new ProcessMigrations { | ||
override def processMigrations: Map[MigrationNumber, ProcessMigration] = combined | ||
}) | ||
} | ||
} | ||
|
||
sealed trait CombineError | ||
|
||
object CombineError { | ||
case class OverlappingMigrations(migrationNumberToOrigins: Map[MigrationNumber, List[ProcessMigrations]]) | ||
extends CombineError | ||
} | ||
|
||
} | ||
|
||
trait ProcessMigrations extends Serializable { | ||
|
||
def processMigrations: Map[MigrationNumber, ProcessMigration] | ||
|
||
// we assume 0 is minimal version | ||
def version: MigrationNumber = (processMigrations.keys.toSet + 0).max | ||
|
||
} |
65 changes: 65 additions & 0 deletions
65
...sions-api/src/test/scala/pl/touk/nussknacker/engine/migration/ProcessMigrationsTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package pl.touk.nussknacker.engine.migration | ||
|
||
import cats.data.NonEmptyList | ||
import org.scalatest.Inside.inside | ||
import org.scalatest.funsuite.AnyFunSuite | ||
import org.scalatest.matchers.should.Matchers | ||
import pl.touk.nussknacker.engine.canonicalgraph.CanonicalProcess | ||
import pl.touk.nussknacker.test.EitherValuesDetailedMessage | ||
|
||
class ProcessMigrationsTest extends AnyFunSuite with Matchers with EitherValuesDetailedMessage { | ||
|
||
test("should combine non overlapping migrations") { | ||
val migrations1 = createMigrations(100, 200) | ||
val migrations2 = createMigrations(101, 102, 103) | ||
val migrations3 = createMigrations(110, 120) | ||
|
||
val combined = ProcessMigrations.combine(migrations1 :: migrations2 :: migrations3 :: Nil) | ||
|
||
combined.rightValue.processMigrations.keySet should contain only (100, 101, 102, 103, 110, 120, 200) | ||
} | ||
|
||
test("should combine single migrations list") { | ||
val migrations = createMigrations(100, 200) | ||
|
||
val combined = ProcessMigrations.combine(migrations :: Nil) | ||
|
||
combined.rightValue shouldBe theSameInstanceAs(migrations) | ||
} | ||
|
||
test("should combine empty migrations list") { | ||
val combined = ProcessMigrations.combine(Nil) | ||
|
||
combined.rightValue.version shouldBe 0 | ||
combined.rightValue.processMigrations shouldBe Symbol("empty") | ||
} | ||
|
||
test("should return error with overlapping migrations") { | ||
val migrations1 = createMigrations(100, 200, 300, 400, 500) | ||
val migrations2 = createMigrations(101, 200, 201, 202, 203, 300, 301) | ||
val migrations3 = createMigrations(200, 210) | ||
|
||
val combined = ProcessMigrations.combine(migrations1 :: migrations2 :: migrations3 :: Nil) | ||
|
||
inside(combined.leftValue) { case ProcessMigrations.CombineError.OverlappingMigrations(overlappingMigrations) => | ||
overlappingMigrations.keySet should contain only (200, 300) | ||
overlappingMigrations(200) should contain only (migrations1, migrations2, migrations3) | ||
overlappingMigrations(300) should contain only (migrations1, migrations2) | ||
} | ||
} | ||
|
||
private def createMigrations(migrationIds: Int*): ProcessMigrations = { | ||
new ProcessMigrations { | ||
override def processMigrations: Map[Int, ProcessMigration] = { | ||
migrationIds.map(id => id -> EmptyMigration).toMap | ||
} | ||
} | ||
} | ||
|
||
private object EmptyMigration extends ProcessMigration { | ||
override def description: String = ??? | ||
|
||
override def migrateProcess(canonicalProcess: CanonicalProcess, category: String): CanonicalProcess = ??? | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters