diff --git a/db/src/main/scala/org/updraft0/controltower/db/query/map.scala b/db/src/main/scala/org/updraft0/controltower/db/query/map.scala index a5d45f0..d054d4f 100644 --- a/db/src/main/scala/org/updraft0/controltower/db/query/map.scala +++ b/db/src/main/scala/org/updraft0/controltower/db/query/map.scala @@ -106,6 +106,36 @@ object map: .run(quote { mapSystem.filter(ms => ms.mapId == lift(mapId) && ms.systemId == lift(systemId)) }) .map(_.headOption) + private inline def findWormholeMapSignatures(mapId: MapId, systemId: SystemId) = + quote( + mapSystemSignature + .filter(_.mapId == lift(mapId)) + .filter(_.systemId == lift(systemId)) + .filter(_.isDeleted == lift(false)) + .filter(_.wormholeConnectionId.nonEmpty) + ) + + private inline def joinConnectionIds(inline mssq: Quoted[Query[MapSystemSignature]]) = + mssq + .join(mapWormholeConnection) + .on((mss, mwc) => mss.wormholeConnectionId.contains(mwc.id) && mwc.isDeleted == lift(false)) + .map((_, mwc) => mwc.id) + + def getSystemConnectionIdsInSignatures( + mapId: MapId, + systemId: SystemId, + sigIds: Option[Chunk[SigId]] + ): DbOperation[List[ConnectionId]] = + sigIds match + case Some(sigIds) => + ctx.run( + joinConnectionIds( + findWormholeMapSignatures(mapId, systemId).filter(mss => liftQuery(sigIds).contains(mss.signatureId)) + ) + ) + case None => + ctx.run(joinConnectionIds(findWormholeMapSignatures(mapId, systemId))) + // inserts def insertMapWormholeConnection(value: MapWormholeConnection): DbOperation[MapWormholeConnection] = ctx @@ -304,32 +334,55 @@ object map: ) .map(_.sum) - def deleteMapSystemSignatures( + def deleteSignaturesWithConnectionIds(ids: Chunk[ConnectionId], byCharacterId: CharacterId): DbOperation[Long] = + ctx + .run( + quote( + liftQuery(ids).foreach(id => + mapSystemSignature + .filter(_.wormholeConnectionId.exists(_ == id)) + .update( + _.isDeleted -> lift(true), + _.updatedByCharacterId -> lift(byCharacterId), + _.updatedAt -> unixepoch + ) + ) + ) + ) + .map(_.sum) + + def deleteMapSystemSignaturesAll( mapId: MapId, systemId: SystemId, now: Instant, byCharacterId: CharacterId ): DbOperation[Long] = ctx.run( - mapSystemSignature - .filter(_.mapId == lift(mapId)) - .filter(_.systemId == lift(systemId)) - .update(_.isDeleted -> lift(true), _.updatedByCharacterId -> lift(byCharacterId), _.updatedAt -> lift(now)) + quote( + mapSystemSignature + .filter(_.mapId == lift(mapId)) + .filter(_.systemId == lift(systemId)) + .update(_.isDeleted -> lift(true), _.updatedByCharacterId -> lift(byCharacterId), _.updatedAt -> lift(now)) + ) ) - def deleteMapSystemSignature( + def deleteMapSystemSignatures( mapId: MapId, systemId: SystemId, - signatureId: SigId, + signatureIds: Chunk[SigId], byCharacterId: CharacterId ): DbOperation[Long] = - ctx.run( - mapSystemSignature - .filter(_.mapId == lift(mapId)) - .filter(_.systemId == lift(systemId)) - .filter(_.signatureId == lift(signatureId)) - .update(_.isDeleted -> lift(true), _.updatedByCharacterId -> lift(byCharacterId), _.updatedAt -> unixepoch) - ) + ctx + .run( + liftQuery(signatureIds).foreach(sigId => + mapSystemSignature + .filter(_.mapId == lift(mapId)) + .filter(_.systemId == lift(systemId)) + .filter(_.signatureId == sigId) + .update(_.isDeleted -> lift(true), _.updatedByCharacterId -> lift(byCharacterId), _.updatedAt -> unixepoch) + ) + ) + .map(_.sum) def deleteMapSystemNote(id: Long, byCharacterId: CharacterId): DbOperation[Long] = ctx.run( diff --git a/server/src/main/scala/org/updraft0/controltower/server/map/MapReactive.scala b/server/src/main/scala/org/updraft0/controltower/server/map/MapReactive.scala index 6aa0dc2..f9d69ab 100644 --- a/server/src/main/scala/org/updraft0/controltower/server/map/MapReactive.scala +++ b/server/src/main/scala/org/updraft0/controltower/server/map/MapReactive.scala @@ -576,9 +576,7 @@ object MapEntity extends ReactiveEntity[MapEnv, MapId, MapState, Identified[MapR ) = // TODO: signature updates cannot currently change connection ids so only a single system needs to be reloaded for - _ <- - if (uss.replaceAll) query.map.deleteMapSystemSignatures(mapId, uss.systemId, now, sessionId.characterId) - else ZIO.succeed(0) + _ <- query.map.deleteMapSystemSignaturesAll(mapId, uss.systemId, now, sessionId.characterId).when(uss.replaceAll) mapSystemId = (mapId, uss.systemId) mapSystem = state.getSystem(uss.systemId).get _ <- ZIO.foreachDiscard( @@ -586,10 +584,12 @@ object MapEntity extends ReactiveEntity[MapEnv, MapId, MapState, Identified[MapR .map(lookupExisting(mapSystem, _)) .map((prevOpt, newSig) => toModelSignature(now, sessionId, mapSystemId, prevOpt, newSig)) )(query.map.upsertMapSystemSignature) + // reload the whole system sys <- loadSingleSystem(mapId, uss.systemId) conns <- MapQueries.getWormholeConnectionsWithSigsBySystemId(mapId, uss.systemId) - yield withState(state.updateOne(sys.sys.systemId, sys, conns, Nil))(nextState => - nextState -> broadcast(nextState.systemSnapshot(sys.sys.systemId)) + ranks <- MapQueries.getWormholeConnectionRanksForSystem(mapId, uss.systemId) + yield withState(state.updateOne(sys.sys.systemId, sys, conns, ranks))(s => + s -> broadcast(s.systemSnapshot(sys.sys.systemId)) ) private def removeSystemAndConnection( @@ -605,6 +605,8 @@ object MapEntity extends ReactiveEntity[MapEnv, MapId, MapState, Identified[MapR for // mark connections as removed _ <- query.map.deleteMapWormholeConnections(connectionIds, sessionId.characterId) + // remove signatures that have those connections + _ <- query.map.deleteSignaturesWithConnectionIds(connectionIds, sessionId.characterId) // remove the display of the system _ <- query.map.deleteMapSystemDisplay(mapId, rs.systemId) // recompute all the connection ranks @@ -651,14 +653,19 @@ object MapEntity extends ReactiveEntity[MapEnv, MapId, MapState, Identified[MapR now: Instant, rss: MapRequest.RemoveSystemSignatures ) = + // TODO need to recompute state for all the connection ids :) <-- aka if the connection is being deleted, + // remove the whole connection on both sides! for + connectionIds <- query.map.getSystemConnectionIdsInSignatures(mapId, rss.systemId, rss.signatures.map(_.toChunk)) + _ <- query.map.deleteMapWormholeConnections(Chunk.fromIterable(connectionIds), sessionId.characterId) _ <- rss.signatures match - case None => query.map.deleteMapSystemSignatures(mapId, rss.systemId, now, sessionId.characterId) - case Some(ids) => - ZIO.foreach(ids)(id => query.map.deleteMapSystemSignature(mapId, rss.systemId, id, sessionId.characterId)) + case None => query.map.deleteMapSystemSignaturesAll(mapId, rss.systemId, now, sessionId.characterId) + case Some(ids) => query.map.deleteMapSystemSignatures(mapId, rss.systemId, ids, sessionId.characterId) + // reload the whole system sys <- loadSingleSystem(mapId, rss.systemId) conns <- MapQueries.getWormholeConnectionsWithSigsBySystemId(mapId, rss.systemId) - yield withState(state.updateOne(sys.sys.systemId, sys, conns, Nil))(s => + ranks <- MapQueries.getWormholeConnectionRanksForSystem(mapId, rss.systemId) + yield withState(state.updateOne(sys.sys.systemId, sys, conns, ranks))(s => s -> broadcast(s.systemSnapshot(sys.sys.systemId)) )