Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fragments.setOpt removed #1893

Open
Fristi opened this issue Jul 11, 2023 · 3 comments
Open

Fragments.setOpt removed #1893

Fristi opened this issue Jul 11, 2023 · 3 comments

Comments

@Fristi
Copy link
Contributor

Fristi commented Jul 11, 2023

This was quite useful for dynamic updates:

final case class StationUpdate(
                                name: Option[String],
                                location: Option[String],
                                description: Option[String],
                                waterSchedule: Option[WateringSchedule]
                              ) 

 val update: StationUpdate = ???

      val fragments = Fragments.setOpt(
        update.name.map(n => fr"name = $n"),
        update.location.map(n => fr"location = $n"),
        update.description.map(n => fr"description = $n"),
        update.waterSchedule.map(n => fr"watering_schedule = $n"),
        Option(fr"updated = $now")
      )

andOpt does not work with updates as it's comma based in Postgres

@jatcwang
Copy link
Collaborator

Oh interesting I was not aware it ever existed 😮
I think for fragment helpers the aim is to help users construct SQL queries that will never fail at runtime as long as the code compiles. Which is why andOpt/orOpt returns Option. However I'm not sure how we can do that for SET because unlike boolean operations we always need at least one column modified?

We can add a Fragments.set that takes a non-empty collection of fragments though and it's up to the user to supply that.

@Fristi
Copy link
Contributor Author

Fristi commented Jul 12, 2023

That's a thing I've came across in the past, runtime errors because all the options were empty in the update case class and therefore it yielded a invalid query.

With RC4 I've coded this

    val updateAttributes = {
      val updates = List(
          update.name.map(n => fr"name = $n"),
          update.location.map(n => fr"location = $n"),
          update.description.map(n => fr"description = $n"),
          update.waterSchedule.map(n => fr"watering_schedule = $n")
      )

      NonEmptyList.fromList(updates.flatten) match {
        case Some(update) =>
          fr"UPDATE stations ${Fragments.set(update :+ fr"updated = $now")} WHERE id = $id AND user_id = $userId".update.run
        case None =>
          Applicative[ConnectionIO].pure(0)
      }
    }
    

Which does the job, but I'm sure it can be prettier with specific function for this case

@jatcwang
Copy link
Collaborator

Perhaps something like updateSetOpt[F: Foldable](tableName: Fragment, columnUpdates: F[Fragment]): Option[Fragment]

So if columnUpdates is empty then it'll return None so the user knows to deal with when no columns are updated.
Can probably even add another Fragment parameter for the where clause. Users can then use whereAndOpt/whereAnd etc here which I think is still quite readable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants