Reputation: 8068
The below function has a UUID param and then two optional parameters. Depending on the state of the two optional parameters will determine whether or not they are included in the update query.
def updateChunkState(chunkId: UUID, state: ChunkState, comment: Option[String], sourceLanguage: Option[String]): Either[ChunkNotFoundError, Unit] = {
val result = (comment, sourceLanguage) match {
case (c: Some[String], s: Some[String]) => {
val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.comment, c.sourceLanguage))
exec(query.update(state, comment, sourceLanguage))
}
case (c: Some[String], None) => {
val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.comment))
exec(query.update(state, comment))
}
case (None, s: Some[String]) => {
val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state, c.sourceLanguage))
exec(query.update(state, sourceLanguage))
}
case (None, None) => {
val query = ChunkTable.query.filter(_.id === chunkId.toString).map(c => (c.state))
exec(query.update(state))
}
}
result match {
case 0 => Left(ChunkNotFoundError(chunkId))
case n if n > 0 => Right(())
}
}
I believe there should be a way to compose my query/update a bit more elegantly than my brute force attempt above and I would be grateful if someone could enlighten me.
Upvotes: 0
Views: 69
Reputation: 51
I think the way you are doing it atm is fine. There is no way out of the 4 matches. Maybe a way of making it more elegant would be to collect the duplicate code to only one place, ie. instead of calling exec(query.update(...)) in 4 places, you could call it in one. Here I just call it as a list of strings, i dont know how the function takes the variable number of arguments. And instead of filtering it in 4 different places you could filter it once, before you start the pattern match. Just makes it a bit easier to read, as it is not a large block of code.
And if you are not using the tuple variables you match on, there is no need for giving them names, c and s that is. And also the type is not needed, you know it is a string from the funtions signature. I prefer Some(_) in that case (where i dont need the variable), and if you match the correct way, from (Some, Some) to (None, None), use _ (wildcard) for the None cases, and _ for the (None, None) case
I made a list of all the arguments that you use for query.update() and put them in a list. Wrapped state in a Some() and used flatten to remove the Nones. Then applied these to the function with _* operator.
I think the code is fine as is, but you could cut off 10 lines like this.
def updateChunkState(chunkId: UUID, state: ChunkState, comment: Option[String], sourceLanguage: Option[String]): Either[ChunkNotFoundError, Unit] = {
val updateParams = List(Some(state), comment, sourceLanguage).flatten
val queryFiltered = ChunkTable.query.filter(_.id === chunkId.toString)
val query = (comment, sourceLanguage) match {
case (Some(_), Some(_)) => queryFiltered.map(c => (c.state, c.comment, c.sourceLanguage))
case (Some(_), _) => queryFiltered.map(c => (c.state, c.comment))
case (_, Some(_)) => queryFiltered.map(c => (c.state, c.sourceLanguage))
case _ => queryFiltered.map(c => (c.state))
}
exec(query.update(updateParams:_*)) match {
case 0 => Left(ChunkNotFoundError(chunkId))
case n if n > 0 => Right(())
}
Upvotes: 2