crud icon indicating copy to clipboard operation
crud copied to clipboard

Avoid duplicating Services and Controllers when using multiple connections with the same set of tables

Open FredericLatour opened this issue 4 years ago • 4 comments

Hi, I have a use case where I have multiple databases (alias connections) that have the exact same set of tables. Basically, I would like to use a specific connection depending on a "param" or a "query variable". Is there any way to have a single "CRUD" controller instead of one controller for each connection?

Basically I would have 2 services like that:

@Injectable()
export class CampaignsServiceConnA extends TypeOrmCrudService<Campaigns> {
  constructor(@InjectRepository(Campaigns, 'ConnA') repo) {
    super(repo);
  }
}
@Injectable()
export class CampaignsServiceConnB extends TypeOrmCrudService<Campaigns> {
  constructor(@InjectRepository(Campaigns, 'ConnB') repo) {
    super(repo);
  }
}

And a controller like the following:

@Crud({
  model: {
    type: Campaigns
  }
})
@Controller('campaigns/:conn')
export class CampaignsController implements CrudController<Campaigns> {
  constructor(public service: CampaignsServiceConnA OR CampaignsServiceConnB depending on the value of :conn param) {}
}

If I could even have only one parameterized CampaignService, that would be even better. Does anybody know it there is a more elegant approach than have as many services and controllers as the number of connections?

Thanks in advance

FredericLatour avatar Apr 07 '20 14:04 FredericLatour

Anyone? This feature makes sense considering it's possible to handle multiple typeorm connections at nestjs level. Could sponsor this feature depending on the pricing.

FredericLatour avatar Apr 09 '20 12:04 FredericLatour

Hi, As you've mentioned, the current functionality almost totally relies on a repository. So, I don't think it's possible to do this currently. But it definitely looks like a cool possible feature. I'll think about it and hope someone will have some time to work on this too.

michaelyali avatar Apr 20 '20 05:04 michaelyali

@zMotivat0r I believe there would be an easy solution. At least not that difficult. In the current implementation, CrudController<T> expects a TypeOrmCrudService<T> service that expects a Repository<T>.

This can be summarized like that:

@Crud( {model: { type: Log, },})
@Controller('log/:somevalue')
export class LogController implements CrudController<Log> {
  public service
  constructor() {
    const repo = getConnection('connectionName').getRepository<Log>(Log)
    this.service = new TypeOrmCrudService<Log>(repo)
  }
}

For simplification, I instantiated TypeOrmCrudService service directly instead of injecting it.

Now, if instead of relying solely on a Repository<T>, TypeOrmCrudService would accept the following structure :

interface IMultiRepos<T> {
  /** type for discriminating - though not really useful here */
  kind: 'MULTI_REPOS'

  /** multiple named repositories */
  namedRepos: { [key: string]:  Repository<T>} 

  /** default repository name */
  defaultRepoName: string

  /** function that receives a Request/Context object and returns the repository name that is to be used */
  getRepoName: (req) => string
}

Then I could initialize my my TypeOrmCrudService the following way

@Crud( {model: { type: Log, },})
@Controller('log/:somevalue')
export class LogController implements CrudController<Log> {
  public service
  constructor() {
    const multiRepos: IMultiRepos<Log> = {
      kind: 'MULTI_REPOS',
      namedRepos: {
        repo01: getConnection('connectionName01').getRepository<Log>(Log),
        repo02: getConnection('connectionName01').getRepository<Log>(Log),
      },
      defaultRepoName: 'repo01',
      getRepoName: (req) => req.params.somevalue
    }

    this.service = new TypeOrmCrudService<Log>(multiRepos)
    }
}

Of course, it's easy to keep backward compatibility by accepting both Repository<T> | IMultiRepos<T>.

A bit of refactoring is necessary in TypeOrmCrudService but not much, it's just a matter of delegating the proper repository depending on the Request.

What do you think?

FredericLatour avatar Apr 20 '20 14:04 FredericLatour

I have the same request. Is there any progress on this?

aleho70 avatar Sep 14 '22 19:09 aleho70