Objection.js: modelClass is not a subclass of Model or a file path to a module that exports one

Created on 19 Dec 2017  路  4Comments  路  Source: Vincit/objection.js

I am having issue inserting an element that has a foreign key.

I have a model Person and a table Nickname. A person can have multiple nicknames and a nickname is owned by one person only. Both models inherit from a common BaseModel class which is there to managa timestamps (updated_at and created_at). Their relationMappngs are defined as follows:

person.js

const Nickname = require('./Nickname');
class Person extends BaseModel {
// model definition here, table name, $parseJson, jsonSchema

// relation mappings
static get relationMappings() {
    return {
      nicknames: {
        relation: Model.HasManyRelation,
        // The related model. This can be either a Model subclass constructor or an
        // absolute file path to a module that exports one.
        modelClass: Nickname,
        join: {
          from: 'person.id',
          to: 'nickname.owner_id'
        }
      }
    };
  }
}
module.exports = Person;

nickname.js

const Person= require('./Person');
class Nickname extends BaseModel {
// model definition here, table name, $parseJson, jsonSchema

// relation mappings
  static get relationMappings() {
    return {
      owner: {
        relation: Model.BelongsToOneRelation,
        // The related model. This can be either a Model subclass constructor or an
        // absolute file path to a module that exports one.
        modelClass: Person,
        join: {
          from: 'nickname.owner_id',
          to: 'person.id',
        }
      }
    };
  }
}
module.exports = Nickname;

Then I have an API POST /nicknames which should allow to create a nickname related to an existing person.

router.post('/', async (req, res) => {
  try {
    var d = await Nickname.query()
      .insertAndFetch(req.body);
    res.send(d)
  } catch (err) {
    console.log(err);
    res.send(err);
  }
});

I keep getting the error: Nickname.relationMappings.owner: modelClass is not a subclass of Model or a file path to a module that exports one. and I don't know how to solve it. I created the models looking at the examples and they seem ok..

Most helpful comment

@koskimas thx, lazy evaluation works well, just one thing - I believe it should be:

    const Person = require('./Person').default;

All 4 comments

You have a circular dependency (aka. require loop). Person requires Nickname and Nickname requires person. That cannot work (and it is not an objection.js issue, but an issue in the synchronous way commonjs modules work). One way to solve this is to move other require to the relationMappings getter that gets called lazily.

class Nickname extends BaseModel {
// model definition here, table name, $parseJson, jsonSchema

// relation mappings
  static get relationMappings() {
    const Person = require('./Person');

    return {
      owner: {
        relation: Model.BelongsToOneRelation,
        // The related model. This can be either a Model subclass constructor or an
        // absolute file path to a module that exports one.
        modelClass: Person,
        join: {
          from: 'nickname.owner_id',
          to: 'person.id',
        }
      }
    };
  }
}
module.exports = Nickname;

@koskimas thank you, that solves the problem.

[...] that gets called lazily.

Could you please explain me what this means and/or point me to some resources I can study to understand this issue and the circular dependency problem better?

@honestserpent This is a basic programming thing and not related to objection or databases. Just google circular dependency, or play around with node. stackoverflow is a better place for generic programming advice.

@koskimas thx, lazy evaluation works well, just one thing - I believe it should be:

    const Person = require('./Person').default;
Was this page helpful?
0 / 5 - 0 ratings