esqueleto icon indicating copy to clipboard operation
esqueleto copied to clipboard

Using `from` from the experimental DSL can lead to "unknown column" errors (on MySQL/MariaDB)

Open isomorpheme opened this issue 1 year ago • 0 comments

Suppose this toy schema:

share
  [mkPersist sqlSettings]
  [persistLowerCase|
    User

    Post
      author (UserId)
|]

And this query code:

import Database.Esqueleto.Experimental

userPosts :: SqlExpr (Value UserId) -> SqlQuery (SqlExpr (Entity Post))
userPosts userId = do
  post <- from $ table @Post
  where_ $ post.author ==. userId
  pure post

userPostCount :: SqlExpr (Value UserId) -> SqlExpr (Value Word)
userPostCount userId =
  coalesceDefault
    [ subSelect $ do
        -- The `from` is unnecessary here, but not in the code where I ran into this bug
        -- (because it also involves a join).
        post <- from $ userPosts userId
        pure $ count post.id
    ]
    (val 0)

usersWithPostCounts :: SqlQuery (SqlExpr (Entity User), SqlExpr (Value Word))
usersWithPostCounts = do
  user <- from $ table @User
  pure (user, userPostCount user.id)

Printing userWithPostCounts produces SQL that looks like this:

SELECT
  `user`.`id`,
  COALESCE(
    (SELECT COUNT(`q`.`v_id`)
      FROM
        (SELECT `post`.`id` AS `v_id`, `post`.`author` AS `v_author`
          FROM `post`
          WHERE `post`.`author` = `user`.`id`
        ) AS `q`
      LIMIT 1
    ),
    0
  )
FROM `user`

For me on MariaDB at least, running this produces an error:

ERROR 1054 (42S22): Unknown column 'user.id' in 'where clause'

(The where clause being WHERE `post`.`author` = `user`.`id`.)

So it seems like using from with a subquery doesn't always produce well-scoped code: user.id isn't in scope in the subquery in the FROM clause.

isomorpheme avatar Jun 08 '23 15:06 isomorpheme