Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't write double left join using Esqueleto

I have a database schema with teachers, schools, and districts. The TEACHERS table has a nullable SCHOOL_ID column (a teacher may or may not belong to a school) and the SCHOOLS table has a nullable DISTRICT_ID column (a school may or may not belong to a district).

Using Esqueleto, I want a list of teachers, each with a school (if they belong to one) and a district (if they belong to a school that belongs to a district). It took a little while to figure out the right expression just for the teacher->school left join, but I eventually got it right:

select $
from $ \(teacher `LeftOuterJoin` school) -> do
  on (teacher ^. TeacherSchoolId  ==. school ?. SchoolId)
  return (teacher, school)

I tried adding another left join on DISTRICTS using an analogous expression:

select $
from $ \(teacher `LeftOuterJoin` school `LeftOuterJoin` district) -> do
  on (school  ^. SchoolDistrictId ==. district ?. DistrictId)
  on (teacher ^. TeacherSchoolId  ==. school   ?. SchoolId)
  return (teacher, school, district)

But I get an error:

Couldn't match type ‘Entity School’ with ‘Maybe (Entity School)’
Expected type: SqlExpr (Maybe (Entity School))
  Actual type: SqlExpr (Entity School)
In the first argument of ‘(?.)’, namely ‘school’
In the second argument of ‘(==.)’, namely ‘school ?. SchoolId’

Can this double join be expressed using Esqueleto? If so, how?

like image 525
Sean Avatar asked Jan 24 '15 01:01

Sean


1 Answers

Try changing

 on (teacher ^. TeacherSchoolId  ==. school   ?. SchoolId)

To

 on (teacher ^. TeacherSchoolId  ==. just (school   ?. SchoolId))

If that doesn't work, slap 'just' on other components of the query expression until it works.

Reference: used Esqueleto recently on a commercial project

Update, 2016/10/26:

I recently encountered this problem. I think it's a Persistent serialization problem interacting with Esqueleto's willingness to pretend the join doesn't produce nullable results.

I recently changed a fragment of a query from:

  person  `LeftOuterJoin`
  personExtra
 ) -> do
  on ((personExtra ^. PersonExtraPerson) ==. (person ^. PersonId))

to:

  person  `LeftOuterJoin`
  personExtra
 ) -> do
  on ((personExtra ?. PersonExtraPerson) ==. just (person ^. PersonId))

I also changed the return type of my query from Entity PersonExtra to Maybe (Entity PersonExtra).

Now Persistent expects the possibility of a PersistNull and the query works fine for me.

like image 77
bitemyapp Avatar answered Sep 23 '22 15:09

bitemyapp