Skip to content

Support repository mixins when scaffolding repositories and rest-crud APIs #5565

Open
@bajtos

Description

@bajtos

Suggestion

At the moment, we allow sharing of repository code via Repository Base Classes only. The command lb4 repository looks for src/repositories/*.repository.base.ts and treat them as repository base classes to offer in the prompt:

$ lb4 repository
? Please select the datasource DbDatasource
? Select the model(s) you want to generate a repository for Product
? Please select the repository base class (Use arrow keys)
  DefaultCrudRepository (Legacy juggler bridge)
  ----- Custom Repositories -----
❯ AuditingRepository

While easy to use, Repository Base Classes have few shortcomings too.

  1. JavaScript does not support multiple inheritance, thus it's not possible to combine behavior from multiple repository base classes in the same model-specific repository class.

  2. Inheritance-based reuse is considered as an anti-pattern in Object Oriented Design, it's recommended to use composition instead ("prefer composition over inheritance").

Let's enhance lb4 repository and lb4 rest-crud commands to all allow the user to choose which Repository Mixins to apply.

Examples

Model-specific repository class:

$ lb4 repository
? Please select the datasource DbDatasource
? Select the model(s) you want to generate a repository for Product
? Please select the repository base class DefaultCrudRepository (Legacy juggler bridge)
? Select the mixin(s) you want to apply (Press <space> to select, <a> to toggle all, <i> to invert 
selection)
❯◉ AuditingMixin (src/mixins/auditing.repository-mixin.ts)
 ◯ TimeStampMixin (src/mixins/timestamp.repository-mixin.ts)

Emitted code:

// src/repositories/product.repository.ts
import {Constructor, inject} from '@loopback/core';
import {DefaultCrudRepository} from '@loopback/repository';
import {DbDataSource} from '../datasources';
import {AuditingRepositoryMixin} from '../mixins/auditing.repository-mixin';
import {Product, ProductRelations} from '../models';

export class ProductRepository extends AuditingRepositoryMixin<
  Product,
  Constructor<
    DefaultCrudRepository<
      Product,
      typeof Product.prototype.id,
      ProductRelations
    >
  >
>(DefaultCrudRepository) {
  constructor(@inject('datasources.db') dataSource: DbDataSource) {
    super(Product, dataSource);
  }
}

Model API booter (rest-crud)

$ lb4 rest-crud
? Please select the datasource DbDatasource
? Select the model(s) you want to generate a CRUD REST endpoint Category
? Select the mixin(s) you want to apply (Press <space> to select, <a> to toggle all, <i> to invert 
selection)
❯◉ AuditingMixin (src/mixins/auditing.repository-mixin.ts)
 ◯ TimeStampMixin (src/mixins/timestamp.repository-mixin.ts)

Emitted code:

// src/model-endpoints/category.rest-config.ts
import {ModelCrudRestApiConfig} from '@loopback/rest-crud';
import {AuditingRepositoryMixin} from '../mixins/auditing.repository-mixin';
import {Category} from '../models';

const config: ModelCrudRestApiConfig = {
  model: Category,
  pattern: 'CrudRest',
  dataSource: 'db',
  basePath: '/categories',
  repositoryMixins: [
    AuditingRepositoryMixin
  ],
};
module.exports = config;

(This will require us to enhance Model API booters to support the new config option repositoryMixins.)

Acceptance criteria

  • Documentation to show how to create repository mixins. At the moment, Key concepts >> Mixins does not provide any information specific to repositories. There are detailed instructions in our migration guide, see Defining A Repository Mixin Class Factory Function. It's time to reorganize and clean up this area of our docs.

  • The API contract for repository mixins to allow them to be picked applied by our CLI. For repository base classes, the convention is that the class must accept the same generic parameters and constructor arguments as DefaultCrudRepository. We need to come up with a similar convention for repository mixins.

    The tricky part is how to support mixins that rely on Model and CrudRepository features vs. mixins that require Entity-specific things. For the initial version, I think it's fine to support Entity-based mixins only.

  • A new generator lb4 repository-mixin to scaffold a new repository mixin

  • A new helper function in packages/cli/lib to find all repository mixins. I am proposing to use the following file naming convention:

    • src/mixins/{name}.repository-mixin.ts
  • Enhance lb4 repository to ask the user which mixins to apply and apply them in the scaffolded repository class.

  • A new prompt in lb4 rest-crud to ask the user which mixins to apply and apply them in the scaffolded model-api config.

  • Update the relevant documentation

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions