Josuto / monguito

Lightweight MongoDB Abstract Repository implementation for Node.js apps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Improve input domain model definition

Josuto opened this issue · comments

Is your feature request related to a problem? Please describe.

Several developers have expressed that they find the current domain model map definition cumbersome and confusing, which in turn degrades Developer Experience.

The constructor of every custom repository extending MongooseRepository or MongooseTransactionalRepository must pass an object map defining a persistable domain model as input parameter to its parent constructor. This map must specify a Default domain model supertype definition and, optionally, one or more domain model subtype definitions.

The origin of the confusion is on the fact that the key of each subtype definition must match the name of a domain model subtype. Many developers are unaware of this requirement and provide an arbitrary name for such keys, causing the initialisation of their custom repository to fail.

Here is an example that illustrates the issue:

export class MongooseBookRepository
  extends MongooseRepository<Book>
  implements BookRepository
{
  constructor() {
    super({
      Default: { type: Book, schema: BookSchema },
      // Good subtype definition; the key matches the type name
      PaperBook: { type: PaperBook, schema: PaperBookSchema },
      // Bad subtype definition; the key does not match the type name
      Audio: { type: AudioBook, schema: AudioBookSchema },
    });
  }
}

Moreover, reality shows that many custom repositories encompass a domain model that includes a single type. In the previous example, MongooseBookRepository would only deal with instances of type Book. In such cases, the key Default is superfluous; super({ type: Book, schema: BookSchema }) would do.

Describe the solution you'd like

Simplify the structure of the domain model type map so that its semantics are clearer, and thus, easier. Also, it must work well for the implementation of custom repositories that encompass any single or multiple type domain model.

Describe alternatives you've considered

We have considered two approaches. The first one consists of keeping the Default key to specify supertype definition and aggregating all subtype definitions in an optional JS array. The following piece of code, that is based on the previous example, illustrates the proposal:

export class MongooseBookRepository
  extends MongooseRepository<Book>
  implements BookRepository
{
  constructor() {
    super({
      Default: { type: Book, schema: BookSchema },
      subtypes: [
        { type: PaperBook, schema: PaperBookSchema },
        { type: AudioBook, schema: AudioBookSchema }
      ]
    });
  }
}

This approach is clearer than the original and it most likely cause the least impact on custom repositories that address a single type domain model. However, such custom repositories must still explicitly declare a Default domain type definition.

An alternative to further simplify the domain model type map would consist of removing the Default key entirely and define all domain subtypes via an optional subtypes property. Consider the following example:

export class MongooseBookRepository
  extends MongooseRepository<Book>
  implements BookRepository
{
  constructor() {
    super({ 
      type: Book, 
      schema: BookSchema, 
      subtypes: [
        { type: PaperBook, schema: PaperBookSchema },
        { type: AudioBook, schema: AudioBookSchema }
      ]
    });
  }
}

This is the cleanest possible way to define a domain model, independently from its nature (standalone or composed). Furthermore, this approach enables recursive (sub)type definition, although this is a feature to be explored in the future.

Additional context

The adoption of this feature by current monguito users is to be explored. Thus, it is a great canary candidate.

A solution for this issue has been released in version 6.0.0.