Objection.js: Question: How to get the caller on eager queries?

Created on 12 Feb 2017  路  5Comments  路  Source: Vincit/objection.js

This is probably more of a JS question than an objection question, but I would really like to know why it happens and maybe some material reference for me to get some deeper understanding of it.

When I erroneously set my model's relationshipMappings to join with an inexistent table, e.g.:

class User extends Model {
  static tableName = 'users';

  static relationMappings = {
    photos: {
      relation: Model.HasManyRelation,
      modelClass: Photo,
      join: {
        from: 'users.id',
        to: 'WRONG_TABLE.user_id', // should be photos.user_id
      },
    },
}

and run a simple eager query:

try {
    await User
      .query()
      .where('id', 1)
      .eager('photos');
  } catch (e) {
    console.log(e);
  }

I get a stack trace that doesn't start or end in my code:

Error: User.relationMappings.photos: join: either `from` or `to` must point to the related model table.
    at HasManyRelation.throwError (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/relations/Relation.js:605:13)
    at HasManyRelation.setMapping (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/relations/Relation.js:186:12)
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/model/Model.js:617:33
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:935:11
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:4970:15
    at baseForOwn (/Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:3020:24)
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:4939:18
    at baseReduce (/Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:932:5)
    at Function.reduce (/Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:9683:14)
    at Function.getRelations (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/model/Model.js:615:21)
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/operations/WhereInEagerOperation.js:17:43
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/RelationExpression.js:153:9
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:4970:15
    at baseForOwn (/Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:3020:24)
    at Function.forOwn (/Users/xvaldetaro/code/sampleApp/node_modules/objection/node_modules/lodash/lodash.js:12985:24)
    at RelationExpression.forEachChild (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/RelationExpression.js:151:7)
    at WhereInEagerOperation.onAfterInternal (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/operations/WhereInEagerOperation.js:16:21)
    at Object.eval (eval at createHookCaller (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1163:18), <anonymous>:6:19)
From previous event:
    at eval (eval at createHookCaller (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1163:18), <anonymous>:5:22)
    at /Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1175:17
    at Object.<anonymous> (/Users/xvaldetaro/code/sampleApp/node_modules/objection/lib/queryBuilder/QueryBuilder.js:588:17)
    at runCallback (timers.js:637:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)

I am already using bluebird's long stack. I am new to node development and have never seen this kind of thing happening. I.e. there is always some piece of my code in the stack somewhere.

My questions are:
1) Is this something common? If so, could you point me towards an article/post to get deeper understanding on the subject?
2) Is there a way to avoid it? I.e.: add the line of my code that created the promise to the stack.

Thanks for the awesome library!

Most helpful comment

@xvaldetaro As you thought, this is a javascript thing, not an objection thing. It's due to the asynchronous nature of javascript. It's not easy getting good stack traces, although setting bluebird's long stack trace usually helps.

I believe the reason you don't see an error referencing the relationMappings is because relationMappings isn't really "code" -- it's only an object that describes your model relations. So, the error actually comes from the objection code when it uses that object and tries to find your non-existent table. I hope that makes sense.

(If I'm wrong here, somebody else please chime in...)

All 5 comments

@xvaldetaro As you thought, this is a javascript thing, not an objection thing. It's due to the asynchronous nature of javascript. It's not easy getting good stack traces, although setting bluebird's long stack trace usually helps.

I believe the reason you don't see an error referencing the relationMappings is because relationMappings isn't really "code" -- it's only an object that describes your model relations. So, the error actually comes from the objection code when it uses that object and tries to find your non-existent table. I hope that makes sense.

(If I'm wrong here, somebody else please chime in...)

Because javascript is asynchronous. It just convey objection error to console.log. So try this.

js function MyError(deepMessage){ this.deepMessage = deepMessage; } MyError.prototype = new Error();

js console.log(new MyError(e))

Making new Error makes new stack from your code. For saving before stack, I just create MyError

I can see that the relationMappings would not be referenced in the stack, makes sense. What is really weird to me is that none of my code would be there. So there is no way to track what line of code started an asynchronous call?

Javascript is runtime language. Interpreter doesn't know what your code meaning. When you excute your source just v8 interpret your code(object) when it approach the object.

So javascript assume your 'WRONG_TABLE' is correct and just execute table query. But in objection catch table is not exist and throw error.

As @Jeff-Kilbride said, is not code it's object. You can't know it's correct until code is executed. That's why you need the test suit.

And maybe this is not appropriate here. Ask more in stackoverflow about javascript

Sure, makes sense. You are right, it is totally unrelated, but thanks a lot for taking the time to explain. I really appreaciate!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

purepear picture purepear  路  3Comments

zuck picture zuck  路  4Comments

rickmed picture rickmed  路  4Comments

mycahjay-nms picture mycahjay-nms  路  4Comments

chen7david picture chen7david  路  3Comments