stephenafamo/bob

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.