Joins require a context
miniscruff opened this issue · 1 comments
Recently updated and was trying to use the new join work and I am wondering if this is a typo or I am missing something. The docs have:
// SELECT * FROM "jets"
// INNER JOIN "pilots" ON "pilots"."id" = "jets"."pilot_id"
// INNER JOIN "airports" ON "airports"."id" = "jets"."airport_id"
models.Jets(
ctx, db,
models.SelectJoins.Jets.InnerJoin.Pilots,
models.SelectJoins.Jets.InnerJoin.Airports,
).All()
But the generated "getJoins" function looks like:
func getJoins[Q dialect.Joinable](ctx context.Context) joins[Q] {
which also takes a context.
This call eventually makes its way to "Name" in psql/view.go that looks like:
func (v *View[T, Tslice]) Name(ctx context.Context) Expression {
// schema is not empty, never override
if v.schema != "" {
return Quote(v.schema, v.name)
}
schema, _ := ctx.Value(orm.CtxUseSchema).(string)
return Quote(schema, v.name)
}
So for the join to work it looks like you need to do:
ctx := context.TODO() // not sure if this matters
_ = models.SelectJoins(ctx).Jets.LeftJoin.Pilots
Not sure if this was the intention, it seems a little weird to me to pass a context here but maybe I am using it wrong.
This is intentional and the docs should be updated accordingly. The reason is not yet documented, but it is for multi-tenant support through schemas.
Imagine a situation where an application serves multiple tenants all with isolated schemas. For example,
customer1.blogs
customer1.posts
customer2.blogs
customer2.posts
With bob, at the top level context, one can do ctx = psql.UseSchema("customer1")
and this will prefix all table names with customer1
.
I understand that it feels a bit weird, but to fully support this, it is necessary to pass a context to any mod that needs a table name.