Skip to content

ExprNumericOps is not typesafe with PostgreSQL #103

@bishabosha

Description

@bishabosha

The signature of Numeric ops e.g. that RHS adapts to LHS type is wrong:
e.g. using

class ExprNumericOps[T: Numeric](v: Expr[T]) {
  def *[V: Numeric](x: Expr[V]): Expr[T] // note that rhs is Expr[V] that gets co-erced to Expr[T]
}

incorrect version:
(type checks but runtime error: org.postgresql.util.PSQLException: Bad value for type int : 16750695023.881126)

val tenLanguagesSpokenByLargestPopulation: Seq[(String, Int)] = db.run(
  City.select
    .join(CountryLanguage.select)((city, lang) => city.cc === lang.cc)
    .map((city, lang) => (lang.lang, lang.pct, city.pop))
    .groupBy((lang, pct, pop) => lang)(agg => agg.sumBy((_, pct, pop) => pop * pct))
    .sortBy((lang, pc) => pc).desc
    .take(10)
)

correct version (swap multiplication):

-val tenLanguagesSpokenByLargestPopulation: Seq[(String, Int)] = db.run(
+val tenLanguagesSpokenByLargestPopulation: Seq[(String, Double)] = db.run(
   City.select
     .join(CountryLanguage.select)((city, lang) => city.cc === lang.cc)
     .map((city, lang) => (lang.lang, lang.pct, city.pop))
-    .groupBy((lang, pct, pop) => lang)(agg => agg.sumBy((_, pct, pop) => pop * pct))
+    .groupBy((lang, pct, pop) => lang)(agg => agg.sumBy((_, pct, pop) => pct * pop)) // swap to `pct * pop`
     .sortBy((lang, pc) => pc).desc
     .take(10)
 )

Either there could be some hardcoded overloads for various float/integral combinations, or there chould be some typelevel gymnastics to return the "greedy" type so order does not matter, or there could be implicit evidence that prevents incorrect combinations of numeric types, and suggest to swap the arguments

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions