loopbackio / loopbackio/loopback-next

Support repository mixins when scaffolding repositories and rest-crud APIs

Open
#5,565 2 comments 2 reactions 1 assignee View on GitHub

@jimmy1wu is already working on this.

Since Jul 14, 2020.

CLI developer-experience epic feature help wanted
Dominant language
TypeScript
Stars
5.1k
Forks
1.1k
Avg merge
2d 21h
Merged PRs (30d)
27

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.