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!
@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!
Most helpful comment
@xvaldetaro As you thought, this is a javascript thing, not an
objectionthing. 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
relationMappingsis becauserelationMappingsisn't really "code" -- it's only an object that describes your model relations. So, the error actually comes from theobjectioncode 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...)