Loopback-next: Allow configuration for relation properties

Created on 16 Jan 2019  路  10Comments  路  Source: strongloop/loopback-next

Description

When defining a new relation in a model file, the relation property is also decorated with the @property decorator called inside the relation decorator.
The problem when creating a relation property this way is that it cannot be configured the same as a standard property.

Current Behavior

For example in the Order model, the property customerId from the @belongsTo relation cannot be configured to be of type UUID (the same type as the defined Customer model id property):

@belongsTo(() => Customer, {keyTo: 'id'})
customerId: string;

For example, when trying to create a foreign key for "customerId", it fails with an incompatible type error:

detail: 'Key columns "customerid" and "id" are of incompatible types: text and uuid.'

Expected Behavior (proposal)

I think that implementing support for property configuration in relation decorators is required.
Ability to config relation properties, kind of:

@belongsTo(() => Customer, {keyTo: 'id'}, {
    type: 'string',
    defaultFn: 'uuid',
    required: true})
customerId: string;
2019Q2 Relations bug community-contribution needs grooming

All 10 comments

It might be possible to add the @property annotation in addition to @belongsTo to specify the datatype for the DB?

answer: it's not possible to add @property with @belongsTo as shown in #2345

answer: it's not possible to add @property with @belongsTo as shown in #2345

You are correct. The @property decorator is nested within the @belongsTo decorator (or any other relational decorator). This exactly is the problem with trying to configure a relational property.

@elv1s, thanks for taking this. I just assigned it to you. Thanks!

Re-posting https://github.com/strongloop/loopback-next/pull/2442#issuecomment-470559945:

It sounds like we don't want to mix the property and belongsTo decorators. The solution provided by @raymondfeng might work but it adds redundant info to the db and schema which will be confusing to the user.

Here is one reason why we should not mix the property and the relation decorator:

  • When creating a new model instance, or updating an existing model instance, we don't want the data type to include the navigational property. addressRepo.create(data) does not support updating the AddressBook instance we are belonging to, therefore data type should exclude addressBook property.

    • Navigational properties are needed only when querying data via repo.find.

    • This difference must be propagated to OpenAPI schemas used by REST API endpoints.

For long term, I would like to propose following API at conceptual level (implementation details will be most likely different):

// Relations are defined at model-level
@belongsTo(() => AddressBook)
@model()
class Address extends Entity {
  // the foreign key is defined explicitly
  @foreignKey(() => AddressBook, 'id')
  @property({
    length: 36,
    postgresql: {
      dataType: 'uuid',
    },
  })
  addressBookId: string;
}

// A custom class or interface describes format
// of data returned by a query
@model()
class AddressWithRelations extends Address {
  @property()
  addressBook?: AddressBook;
}

// Repository API
class DefaultCrudRepository {
  find(filter: Filter<Address>): Promise<AddressWithRelations>;
  create(data: Address): Promise<Address>;
  // ...
}

Related: in https://github.com/strongloop/loopback-next/issues/2152, we will be investigating how to best represent navigational properties in model classes.

When creating a new model instance, or updating an existing model instance, we don't want the data type to include the navigational property. addressRepo.create(data) does not support updating the AddressBook instance we are belonging to, therefore data type should exclude addressBook property.

IIUC, using the current implementation, AddressBookId would be decorated with belongsTo() and is actually part of the model definition. As a short term fix, I thought we want to remove the call to the property decorator inside belongsTo() decorator. Thoughts?

@b-admike See https://github.com/strongloop/loopback-next/pull/2442#issuecomment-470826266

The short term fix would be to land the belongsTo() property decorator allow optional property definitions (https://github.com/strongloop/loopback-next/pull/2442)

The next, backward-compatible update would be to move relationship decorators to the model and deprecate use on property.

This issue is essentially a dupe of https://github.com/strongloop/loopback-next/issues/2345 and can be closed

Let's keep this issue, it has been opened first and there is already discussion unfolding here. I am going to close #2345.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mightytyphoon picture mightytyphoon  路  3Comments

acrodrig picture acrodrig  路  3Comments

milindsingh picture milindsingh  路  3Comments

half-blood-programmer picture half-blood-programmer  路  3Comments

rexliu0715 picture rexliu0715  路  3Comments