I'm developing a personal project backed by NestJS and EdgeDB. I'd like to take advantage of their new feature called 'access policies' which requires re-initializing a database client with a config that contains current user's ID. Initially I thought that I could simply call a special method which is designed to overwrite existing database client, however this approach didn't work since the injected provider is seemingly unaffected by any of the attempted mutations after the initialization. Here are code snippets to demonstrate:
Database provider
@Injectable()
export class EdgeDBService implements OnModuleInit {
client = edgedb.createClient()
async onModuleInit() {
await this.client.ensureConnected()
}
public async setGlobals(globals: { current_user_id: string }) {
// Attempting to tack on current user ID to all future queries
this.client = this.client.withGlobals(globals)
// `current_user_id` returns correct value here
console.log(await this.client.query(`select global current_user_id;`))
}
public async query<Expr extends EdgeQLTypes.Expression>(expression: Expr): Promise<$infer<Expr>> {
return await expression.run(this.client)
}
}
Hypothetical provider for retrieving books
@Injectable()
export class PetsService {
constructor(private edgedb: EdgeDBService) {}
getPets() {
// Getting nothing here.
console.log(await this.client.query(`select global current_user_id;`))
// This query returns nothing since `current_user_id` is not set.
return this.edgedb.query(
e.select(e.Pets, (item) => ({
...e.Pets['*'],
}))
)
}
So it seems like it's not really possible to simply re-write the this.client
property in EdgeDBService
, or am I wrong? Is it possible to alter a provider after the initialization at all, or the singleton injection scope prevents that?
Any help with figuring this out is highly appreciated
Eventually figured this out on my own going off a clue related to injection scope. By default, a single provider instance (singleton) is shared across the entire app. Attempting to mutate its properties at runtime won't reflect in the already injected instances (
PetsService
in the example above). Turns out that the way the provider is injected could be adjusted by specifying a differentscope
(docs). I went with withREQUEST
as it perfectly fits my use case:Switching over to
REQUEST
scope allowed me to grab therequest
object in the constructor (docs), extract JWT, decode it and re-initialize EdgeDB client with a global variable required for access policies to work. Here's the code: