Skip to content

Instantly share code, notes, and snippets.

@mattboutet
Created June 9, 2017 02:02
Show Gist options
  • Save mattboutet/17c0789563732b8bcba98056b72315e0 to your computer and use it in GitHub Desktop.
Save mattboutet/17c0789563732b8bcba98056b72315e0 to your computer and use it in GitHub Desktop.
Strange relate behavior with objection
//From https://www.vincit.fi/en/blog/effortless-eager-loading-nested-inserts-objection-js/
//There's a bunch of code here that's not needed for this example, but I was trying to keep edits to a minimum
//Stick this in a directory, then `npm install objection knex sqlite3`
//to run: node app.js
//Changing reviewerId to reviewer in the code below will cause the problem I'm talking about
'use strict';
const objection = require('objection');
const Promise = objection.Promise;
const Model = objection.Model;
const knex = require('knex')({
client: 'sqlite3',
connection: {
filename: './test.db'
}
});
// Make all models use the same database.
Model.knex(knex);
// Create the tables. Normally this would be
// done using migration files. For simplicity,
// we create them in this same file.
const createSchema = Promise.coroutine(function *() {
yield knex.schema.dropTableIfExists('Movie');
yield knex.schema.dropTableIfExists('Person');
yield knex.schema.dropTableIfExists('Review');
yield knex.schema.dropTableIfExists('Movie_Person');
yield knex.schema.createTable('Movie', function (table) {
table.bigincrements('id').primary();
table.string('name');
});
yield knex.schema.createTable('Person', function (table) {
table.bigincrements('id').primary();
table.string('firstName');
table.string('lastName');
table.biginteger('parentId')
.references('id')
.inTable('Person')
.index();
});
yield knex.schema.createTable('Review', function (table) {
table.bigincrements('id').primary();
table.string('title');
table.integer('stars');
table.string('text');
table.biginteger('movieId')
.references('id')
.inTable('Movie')
.index();
table.biginteger('reviewerId')
.references('id')
.inTable('Person')
.index();
});
yield knex.schema.createTable('Movie_Person',function(table){
table.biginteger('movieId')
.references('id')
.inTable('Movie')
.index();
table.biginteger('personId')
.references('id')
.inTable('Person')
.index();
});
});
class Movie extends Model {
static get tableName() {
return 'Movie';
}
static get relationMappings() {
return {
actors: {
relation: Model.ManyToManyRelation,
modelClass: Person,
join: {
from: 'Movie.id',
through: {
from: 'Movie_Person.movieId',
to: 'Movie_Person.personId'
},
to: 'Person.id'
}
},
reviews: {
relation: Model.HasManyRelation,
modelClass: Review,
join: {
from: 'Movie.id',
to: 'Review.movieId'
}
}
};
}
}
class Review extends Model {
static get tableName() {
return 'Review';
}
static get relationMappings() {
return {
reviewer: {
relation: Model.BelongsToOneRelation,
modelClass: Person,
join: {
from: 'Review.reviewerId',
to: 'Person.id'
}
},
movie: {
relation: Model.BelongsToOneRelation,
modelClass: Movie,
join: {
from: 'Review.movieId',
to: 'Movie.id'
}
}
};
}
}
class Person extends Model {
static get tableName() {
return 'Person';
}
static get relationMappings() {
return {
parent: {
relation: Model.BelongsToOneRelation,
modelClass: Person,
join: {
from: 'Person.parentId',
to: 'Person.id'
}
},
reviews: {
relation: Model.HasManyRelation,
modelClass: Review,
join: {
from: 'Person.id',
to: 'Review.reviewerId'
}
},
movies: {
relation: Model.ManyToManyRelation,
modelClass: Movie,
join: {
from: 'Person.id',
through: {
from: 'Movie_Person.personId',
to: 'Movie_Person.movieId'
},
to: 'Movie.id'
}
}
};
}
}
const runQueries = Promise.coroutine(function *() {
yield Movie.query().insertWithRelated([{
name: 'The terminator',
actors: [{
"#id": 'arnold',
firstName: 'Arnold',
lastName: 'Schwarzenegger',
parent: {
firstName: 'Gustav',
lastName: 'Schwarzenegger'
}
}, {
firstName: 'Michael',
lastName: 'Biehn'
}],
reviews: [{
title: 'Great movie',
stars: 5,
text: 'Awesome',
reviewer: {
firstName: 'Some',
lastName: 'Random-Dude'
}
}]
}, {
name: 'Terminator 2: Judgment Day',
actors: [{
"#ref": 'arnold'
}]
}, {
name: 'Predator',
actors: [{
"#ref": 'arnold'
}]
}]);
let reviews = yield Review
.query()
.eager('reviewer');
console.log(JSON.stringify(reviews, null, 2));
});
// Run the whole thing.
createSchema()
.then(runQueries)
.finally(() => knex.destroy());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment