Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoopBack models should inherit config.options from the parent #157

Closed
bajtos opened this issue Jan 28, 2014 · 12 comments
Closed

LoopBack models should inherit config.options from the parent #157

bajtos opened this issue Jan 28, 2014 · 12 comments

Comments

@bajtos
Copy link
Member

bajtos commented Jan 28, 2014

When LB developer wants to access built-in LB models via app.models, he has to define subclasses in models.json. The current implementation requires that a lot of config options of the base model must be repeated in the subclass definition.

This has several disadvantages:

  1. It's difficult to add a built-in model to your app, especially if you are new to loopback.
  2. If we modify the built-in model (e.g. by adding another relation), existing application will break after upgrade.

Below are the use cases I discovered while writing E2E tests for loopback-angular.

datasource

app.model('MyUser', {
  options: { base: 'User' },
  dataSource: 'db'
});

Result:

assert.js:92
  throw new assert.AssertionError({
        ^
AssertionError: MyUser is referencing a dataSource that does not exist: "undefined"
    at modelFromConfig (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/application.js:545:3)
    at Function.app.model (/Users/bajtos/src/loopback/loopback/node_modules/loopback/lib/application.js:115:38)
    [etc.]

Since the new model is a subclass of a built-in model, it should use the same datasource that was configured for the User model.

If the datasource of the base class was not resolved yet, but it has autoAttach property, then the process of attaching the subclass to a datasource should be deferred to loopback.autoAttach.

relations

var user = app.model('user', {
  options: {
    base: 'User',
  },
  dataSource: 'db'
});

app.enableAuth();

var credentials = { email: 'foo@foo.com', password: 'password'};
user.create(credentials, function(err) {
  if (err) throw err;
  user.login(credentials, function(err) {
    if (err) throw err;
    console.log('login passed');
  });
});

Result:

/Users/bajtos/src/loopback/loopback/lib/models/user.js:152
          user.accessTokens.create({
                            ^
TypeError: Cannot call method 'create' of undefined
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:152:29
    at /Users/bajtos/src/loopback/loopback/lib/models/user.js:202:7
    at /Users/bajtos/src/loopback/loopback/node_modules/bcryptjs/bcrypt.min.js:40:101
    [etc]

To fix this problem, one has to re-define User relations:

var user = app.model('user', {
  options: {
    base: 'User',
    relations: {
      accessTokens: {
        model: 'AccessToken',
        type: 'hasMany',
        foreignKey: 'userId'
      }
    }
  },
  dataSource: 'db'
});
@raymondfeng
Copy link
Member

The requirement seems to boil down to dependencies between models and have a systematic way to resolve/inject the dependencies.

@raymondfeng raymondfeng added this to the 2.0.0 milestone Feb 28, 2014
@glesage
Copy link

glesage commented Apr 24, 2014

Any updates on this? Is the manual way still the best way?

@bajtos
Copy link
Member Author

bajtos commented Apr 24, 2014

@glesage No updates so far.

@bajtos bajtos mentioned this issue Sep 30, 2014
47 tasks
@bajtos bajtos modified the milestone: #Rel lb 2.0.0 Sep 30, 2014
@bajtos bajtos added this to the LoopBack 3.0 milestone Nov 26, 2014
@bajtos
Copy link
Member Author

bajtos commented Nov 26, 2014

Since the new model is a subclass of a built-in model, it should use the same datasource that was configured for the User model.

This is no longer relevant, LoopBack 2.0 decoupled datasources config from model definition.

The current implementation requires that a lot of config options of the base model must be repeated in the subclass definition.

This is still relevant. The implementation would most likely break backwards compatibility.

Related issue: #397 A better way for customizing built-in models and models from components

@bajtos
Copy link
Member Author

bajtos commented Feb 4, 2016

Let's bring this issue back to life. For the upcoming 3.0 release, I am proposing to modify juggler's model builder to inherit model settings when subclassing a new model.

app.model('MyUser', {
  options: { base: 'User' },
  dataSource: 'db'
});
// expected outcome:
assert(MyUser.settings.__proto__ === User.settings);

@shyd0w
Copy link

shyd0w commented Feb 4, 2016

I think that would be great! Options is the inheritance of the setting?

@bajtos bajtos added the 3.0 label Apr 7, 2016
@bajtos bajtos added the #plan label Apr 28, 2016
@bajtos
Copy link
Member Author

bajtos commented Apr 28, 2016

/cc @davidcheung

@davidcheung
Copy link
Contributor

Loosely related #1485

@bajtos
Copy link
Member Author

bajtos commented May 2, 2016

ACLs are not inherited either, see #2270.

As for inheriting relations, pure prototypal inheritance may not be enough. Consider this scenario:

We have a parent model User which has a relation

accessTokens: {
  model: 'AccessToken',
  type: 'hasMany',
  // this is omitted: foreignKey: 'userId'
}

When attached to a datasource, foreignKey property is automatically inferred and AccessToken.userId property is defined by juggler.

Now when we create Customer extending User, the foreign key for relation accessTokens will be generated as AccessToken.customerId, which may break code relying on userId property name.

A possible solution is to always fill in foreignKey before inheriting model settings.

@bajtos bajtos added #tob and removed #plan labels May 3, 2016
@bajtos bajtos removed the #tob label May 12, 2016
@bajtos bajtos removed 3.0 labels May 12, 2016
@bajtos bajtos removed this from the #Epic: Compat Flags Cleanup milestone May 12, 2016
@bajtos
Copy link
Member Author

bajtos commented May 12, 2016

We agreed this required a bit of research to find out what and how should be inherited when subclassing a model. We don't have bandwidth to address it in 3.0 time.

@stale
Copy link

stale bot commented Aug 23, 2017

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot closed this as completed Sep 6, 2017
@stale
Copy link

stale bot commented Sep 6, 2017

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants