fix(persistence): 差删先按 FDAY 圈定删除成员,修复保留航班明细误删 (ACM2-30)

This commit is contained in:
windyboy
2026-09-08 18:50:02 +08:00
parent 7c2d22e8f1
commit 1fc2b2c895
9 changed files with 56 additions and 65 deletions
@@ -112,7 +112,6 @@ class FlightStateEngineTest {
val commands = FlightStateEngine.commandsFromFields(
"F1",
mapOf("GTDT" to """[{"GTNO":"0"}]"""),
snapshotReplace = false,
)
assertEquals(CollectionCommand.Clear, commands.collections["GTDT"])
}
@@ -123,7 +122,6 @@ class FlightStateEngineTest {
FlightStateEngine.commandsFromFields(
"F1",
mapOf("GTDT" to """[{"GTNO":"1","GATE":"A1"},{"GTNO":"0"}]"""),
snapshotReplace = false,
)
}.exceptionOrNull()
assertTrue(error is IllegalArgumentException)
@@ -138,7 +136,7 @@ class FlightStateEngineTest {
1L,
"m1",
)
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("GTDT" to "[]"), snapshotReplace = false)
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("GTDT" to "[]"))
val next = FlightStateEngine.apply(current, commands, "m2", bumpVersion = true)
assertEquals(emptyList<Map<String, String>>(), next.collections["GTDT"])
}
@@ -175,7 +173,7 @@ class FlightStateEngineTest {
3L,
"m1",
)
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("FRET" to "null"), snapshotReplace = false)
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("FRET" to "null"))
assertEquals(ScalarCommand.Clear, commands.scalars["FRET"])
val next = FlightStateEngine.apply(current, commands, "m2", bumpVersion = true)
@@ -186,7 +184,7 @@ class FlightStateEngineTest {
// 非空载荷仍为 Set,且清空后的下一跳 Set 恢复键(clearedKeys 不跨消息携带)
val restored = FlightStateEngine.apply(
next,
FlightStateEngine.commandsFromFields("F1", mapOf("FRET" to """{"REID":"R2"}"""), snapshotReplace = false),
FlightStateEngine.commandsFromFields("F1", mapOf("FRET" to """{"REID":"R2"}""")),
"m3",
bumpVersion = true,
)
@@ -197,7 +195,7 @@ class FlightStateEngineTest {
@Test
fun `exception clear accepts null literal empty object and empty string`() {
for (payload in listOf("null", "{}", "")) {
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("FDIV" to payload), snapshotReplace = false)
val commands = FlightStateEngine.commandsFromFields("F1", mapOf("FDIV" to payload))
assertEquals(ScalarCommand.Clear, commands.scalars["FDIV"], "payload=[$payload] must be Clear")
}
}
@@ -89,12 +89,36 @@ class FlightSchdJdbcPgTest {
) = flights.map { (flid, fields) ->
com.gzzn.omms.msgexchange.domain.flight.FlightStateEngine.apply(
null,
com.gzzn.omms.msgexchange.domain.flight.FlightStateEngine.commandsFromFields(flid, fields, snapshotReplace = true),
com.gzzn.omms.msgexchange.domain.flight.FlightStateEngine.commandsFromFields(flid, fields),
messageId,
bumpVersion = false,
).copy(stateVersion = version)
}
@Test
fun `day diff preserves all details of migrated and unowned flights`() {
val day = "2026-09-07"
val otherDay = "2026-09-08"
val fields = mapOf("GTDT" to """[{"GTNO":"3","GATE":"G23"}]""")
val removed = "TEST_DIFF_REMOVED"
val moved = "TEST_DIFF_MOVED"
val unowned = "TEST_DIFF_ADFT"
repo.persistNextStates(day, snapshotStates(day, listOf(removed to fields)), snapshotReplace = true)
repo.persistNextStates(otherDay, snapshotStates(otherDay, listOf(moved to fields)), snapshotReplace = true)
repo.persistNextStates(null, snapshotStates(day, listOf(unowned to fields)), snapshotReplace = false)
val beforeMoved = repo.findByFlid(moved)
val beforeUnowned = repo.findByFlid(unowned)
JdbcPipelineTransactionManager(ds).inTransaction {
assertEquals(1, repo.deleteDiffByDay(day, listOf(removed, moved, unowned)))
}
assertNull(repo.findByFlid(removed))
assertTrue(FlightDetailTables.loadCollections(ds, removed).isEmpty())
assertEquals(beforeMoved, repo.findByFlid(moved))
assertEquals(beforeUnowned, repo.findByFlid(unowned))
}
@Test
fun `PG dialect - snapshot batch upsert, find, and domain diff delete`() {
val day = "2026-09-07"
@@ -142,7 +166,7 @@ class FlightSchdJdbcPgTest {
com.gzzn.omms.msgexchange.domain.flight.FlightStateEngine.apply(
null,
com.gzzn.omms.msgexchange.domain.flight.FlightStateEngine.commandsFromFields(
flid, mapOf("FLID" to flid, "REMC" to remc), snapshotReplace = false,
flid, mapOf("FLID" to flid, "REMC" to remc),
),
"msg-inc-01",
bumpVersion = true,
@@ -183,7 +207,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
null,
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"1","GATE":"A1"},{"GTNO":"2","GATE":"A2"}]"""), snapshotReplace = true),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"1","GATE":"A1"},{"GTNO":"2","GATE":"A2"}]""")),
"msg-res-1", bumpVersion = true,
),
),
@@ -206,7 +230,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
repo.findNextStateByFlid(flid),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"3","GATE":"B1"}]"""), snapshotReplace = false),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"3","GATE":"B1"}]""")),
"msg-res-2", bumpVersion = true,
),
),
@@ -223,7 +247,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
repo.findNextStateByFlid(flid),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"0"}]"""), snapshotReplace = false),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"0"}]""")),
"msg-res-3", bumpVersion = true,
),
),
@@ -251,7 +275,6 @@ class FlightSchdJdbcPgTest {
"ABTM" to """[{"ASNO":"1","ABDG":"B01","ABOP":"A","AOTM":"07SEP261700"}]""",
"FDIV" to """{"DDES":"PEK","DDIR":"TO","REMC":"weather"}""",
),
snapshotReplace = true,
),
"msg-scalar-1", bumpVersion = true,
),
@@ -304,7 +327,6 @@ class FlightSchdJdbcPgTest {
"DELY" to "[]",
"ROUT" to """[{"RTNO":"1","APCD":"CTU"}]""",
),
snapshotReplace = false,
),
"msg-scalar-2", bumpVersion = true,
),
@@ -638,7 +660,6 @@ class FlightSchdJdbcPgTest {
"CLDT" to """[{"CLNO":"1","BELT":"B01"}]""",
"DELY" to """[{"CODE":"YY","STRT":"07SEP261605","DURA":"0200"}]""",
),
snapshotReplace = true,
),
"msg-display-1", bumpVersion = true,
),
@@ -677,7 +698,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
repo.findNextStateByFlid(flid),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"5","GATE":"Z1"}]"""), snapshotReplace = false),
engine.commandsFromFields(flid, mapOf("GTDT" to """[{"GTNO":"5","GATE":"Z1"}]""")),
"msg-display-2", bumpVersion = true,
),
),
@@ -702,7 +723,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
null,
engine.commandsFromFields(flid, mapOf("FRET" to """{"REID":"CA108","RSN":"diverted"}"""), snapshotReplace = true),
engine.commandsFromFields(flid, mapOf("FRET" to """{"REID":"CA108","RSN":"diverted"}""")),
"msg-exc-1", bumpVersion = true,
),
),
@@ -720,7 +741,7 @@ class FlightSchdJdbcPgTest {
listOf(
engine.apply(
repo.findNextStateByFlid(flid),
engine.commandsFromFields(flid, mapOf("FRET" to "null"), snapshotReplace = false),
engine.commandsFromFields(flid, mapOf("FRET" to "null")),
"msg-exc-2", bumpVersion = true,
),
),
@@ -755,7 +776,7 @@ class FlightSchdJdbcPgTest {
"FDIV" to """{"DDES":"PEK","DDIR":"TO"}""",
"SRVT" to """[{"SRTC":"WHEEL"}]""",
)
val state = engine.apply(null, engine.commandsFromFields(flid, fields, snapshotReplace = true), "msg-matrix-1", bumpVersion = true)
val state = engine.apply(null, engine.commandsFromFields(flid, fields), "msg-matrix-1", bumpVersion = true)
repo.persistNextStates(day, listOf(state), snapshotReplace = true)
@@ -18,7 +18,7 @@ fun seedSnapshot(
flights.map { (flid, fields) ->
FlightStateEngine.apply(
null,
FlightStateEngine.commandsFromFields(flid, fields, snapshotReplace = true),
FlightStateEngine.commandsFromFields(flid, fields),
"seed-$day",
bumpVersion = false,
).copy(stateVersion = 1L)
@@ -34,7 +34,7 @@ fun seedIncremental(repo: FlightSchdRepository, changes: List<FlightChange>, mes
changes.map { change ->
FlightStateEngine.apply(
repo.findNextStateByFlid(change.flid),
FlightStateEngine.commandsFromFields(change.flid, change.fields, snapshotReplace = false),
FlightStateEngine.commandsFromFields(change.flid, change.fields),
messageId,
bumpVersion = true,
)