у нас есть
private def insertUpdateDeleteFormDsList(dsList : List[FormDefinitionDataSourceRequestModel])(implicit formDefId:Int,subject:Subject,session: Session) : (List[(Int,Int)],Seq[FormDefinitionDataSourceRequestModel],Seq[FormDefinitionDataSourceRequestModel]) = {
val incomingIds = dsList.map( ds => (ds.dataSourceId,ds.dsTypeId) )
val existingIds = formDefinitionDatasources.filter(_.tenantId === subject.tenantId).filter(_.formDefId === formDefId).map( ds => (ds.dataSourceId,ds.dataSourceTypeId) ).list
val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion
val insertList = dsList.flatMap{ t => idsForInsertion collectFirst{ case (dsId,dsType) if(dsId == t.dataSourceId && dsType == t.dsTypeId)=> t} }
val updateList = dsList.flatMap{t=>idsForUpdate collectFirst {case (dsId,dsType) if(dsId == t.dataSourceId && dsType == t.dsTypeId)=> t}}
(idsForDeletion,updateList,insertList)
}
И другие подобные методы, как
private def insertUpdateDelDataInstances(instances: List[Instance])(implicit subject: Subject, session: Session): (Seq[Instance], Seq[Instance], Seq[Instance]) = {
val incomingIds = instances.map(_.id)
val existingIds = dataSourceInstanceNew.filter(_.tenantId === subject.tenantId).map(_.id).list
val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion
val deleteList = instances.flatMap{ t => idsForDeletion collectFirst{ case id if(id == t.id)=> t} }
val insertList = instances.flatMap{ t => idsForInsertion collectFirst{ case id if(id == t.id)=> t} }
val updateList = instances.flatMap{t=>idsForUpdate collectFirst {case id if(id === t.id)=> t}}
(deleteList,updateList,insertList)
}
Подобные методы встречаются и в других местах. Каждый раз List[T]
будет передаваться в качестве аргумента метода, где T
всегда будет case class
. теперь то, как создается val incomingIds
, зависит от конкретных атрибутов case class
.
Мы хотим создать обобщенную функцию, которая может принимать List[T]
и, возможно, incomingIds
и возвращать желаемый кортеж, чтобы каждый раз не писать одинаково выглядящий шаблон.
Если бы логика заключалась в том, чтобы «всегда» использовать атрибут id
T
case class
, то я мог бы легко создать родителя trait
с id
и смешать все case class
es с чертой, но здесь это не тот случай. подготовка val incomingIds
зависит от разных атрибутов case class
в зависимости от того, откуда в коде они вызываются.
Иллюстрация ниже
def generalizedInsertUpdateDeleteList[T](data:List[T],incomingIds:List[Int], existingIds:List[Int] )(implicit subject: Subject, session:Session) = {
val idsForDeletion = existingIds diff incomingIds
val idsForInsertion = incomingIds diff existingIds
val idsForUpdate = existingIds diff idsForDeletion
/*
//what's the best way to generalize comparison inside collectFirst?
//to use case class attribute names from `T`. Was thinking if Structural type can help but not sure if that
//can quite work unless there is a way to pass in arguments in a structural type?
val deleteList = data.flatMap{ t => idsForDeletion collectFirst{ case id if(id == t.id)=> t} }
val insertList = data.flatMap{ t => idsForInsertion collectFirst{ case id if(id == t.id)=> t} }
val updateList = data.flatMap{ t => idsForUpdate collectFirst {case id if(id === t.id)=> t}}
*/
Может ли shapeless помочь здесь, если нет другого более чистого способа добиться этого с использованием стандартных API-интерфейсов scala/scalaz?