typeorm-typedi-extensions
typeorm-typedi-extensions copied to clipboard
Question: Scoped Containers and "default" connection
Trying to follow the below guideline from #39:
import { createConnection, useContainer } from 'typeorm';
import { Container } from 'typedi';
/** Tell TypeORM to use the TypeDI container to resolve it's dependencies. */
useContainer(Container);
/** Create a connection and start using TypeORM. */
createConnection({
/* <connection options> */
}).catch(error => {
console.error(`Couldn't connect to the database!`);
console.error(error);
});
Originally posted by @NoNameProvided in https://github.com/typeorm/typeorm-typedi-extensions/issues/39#issuecomment-761127675
and I get the new serviceNotFound: MaybeConstructable error. So I try using the Container exported from typeorm-typedi-extensions, and I get the "cannot get connection default" error.
Any guidance here on how to properly use scoped containers with TypeORM & TypeDI?
Full reproduction repo HERE
Ok after some fun debugging last night I found the issue.
The current TypeDI integration sets the ConnectionManager service for use by TypeORM, but doesnt set it as a global type. When we are in a scoped container, TypeDI goes through the below steps:
- Try to resolve @InjectRepository. As a custom injector, it uses the handler registered in the typeDI container below:
//...
typedi_1.Container.registerHandler({
object: object,
index: index,
propertyName: propertyName,
value: containerInstance => getRepositoryHelper(connectionName, repositoryType, entityType, containerInstance),
});
- Get repository helper now goes into the container instance and tries to get the TypeORM.ConnectionManager
function getRepositoryHelper(connectionName, repositoryType, entityType, containerInstance) {
const connectionManager = containerInstance.get(typeorm_1.ConnectionManager);
if (!connectionManager.has(connectionName)) {
throw new manager_not_found_error_1.ConnectionNotFoundError(connectionName);
}
- Our Container Instance (scoped), grabs the global container, finds the service in the global container, and also checks if the service is already in the scoped container. Here we do find the ConnectionManager in the global container and not in the scoped container, but its .global setting is not true. As such, we DO NOT return the globalService as is (//*1) which would include the required connections values. Instead, we create a cloned service (//*2), set the value to EMPTY, instantiate a new type and use that as the value (//*3). This creates a cloned ConnectionManager that is new, so it has no connections in it.
get(identifier) {
const globalContainer = container_class_1.Container.of(undefined);
const globalService = globalContainer.findService(identifier);
const scopedService = this.findService(identifier);
if (globalService && globalService.global === true)
return this.getServiceValue(globalService); //*1
if (scopedService)
return this.getServiceValue(scopedService);
if (globalService && this !== globalContainer) { //*2
const clonedService = { ...globalService };
clonedService.value = empty_const_1.EMPTY_VALUE;
this.set(clonedService);
const value = this.getServiceValue(clonedService); //*3
this.set({ ...clonedService, value });
return value;
}
if (globalService)
return this.getServiceValue(globalService);
throw new service_not_found_error_1.ServiceNotFoundError(identifier);
}
Changing the initial TypeDI Container.set to set ConnectionManager as global: true fixes all of this as it would then return that global service as found in //*1
@NoNameProvided @pleerock Creating a PR to fix the above. Please let me know if there is a use case for non-global ConnectionManager that I am not correctly anticipating.
PR #53
@NoNameProvided @pleerock, any input on this?
@Xzas22 any work around on this? I'm facing the same issue
My work around was unfortunately to drop TypeORM until this got traction...
Gonna go ahead and drop another BUMP here as I think now more than every this package needs some attention. I did submit a PR with this change. See #53
out of curiosity, rather than dropping TypeORM altogether did you consider dropping this package / the TypeDI integration and just manually resolving your repositories? That's where I'm thinking about going currently. TypeDI seems pretty stable, and TypeORM seems at least actively used.