BookshelfJs failing to bring in nested relationship on create

1.4k Views Asked by At

Let's say we have a Join table vehicle_inspections and another join table inspection_actions, as well as basic tables for actions, vehicles, andinspections`.

Lets say I desire the following DB entries:

 vehicles
 ----------------------------
 id        make
 ----------------------------
 1         Toyota



actions
-------------------------------
id        description
-------------------------------
2         Check Tire Pressue

inspections
-------------------------------
id        location        date
-------------------------------
3         New York      tomorrow

vehicle_inspections
--------------------------------
vehicle_id      inspection_id   
--------------------------------
1                3

inspection_actions
--------------------------------
inspection_id     action_id
--------------------------------
3                 2

and the following bookshelf classes

inspection_actions.js

(function () {
    'use strict';
     var Repository = require('../repository');
     module.exports = Repository.Model.extend({
       tableName: 'inspection_actions',
     });  
})();

vehicle_inspections.js

(function () {
    'use strict';
     var Repository = require('../repository');

     module.exports = Repository.Model.extend({
       tableName = 'vehicle_inspections',
       inspection: function () {
         return this.belongsTo(require('inspection'));
       },
       fetchOrCreate: function(vehicleId, inspectionId, options) {
         var self = this;
         return self.query(function (qb) {
           qb.where({
             vehicle_id: vehicleId,
             inspection_id: inspectionId
           });
         )}.fetch(options || {}).then(function (model) {
           if (!model) {
             model.save({
               vehicle_id: vehicleId,
               inspection_id: inspectionId
             });
           return model;
         };
       }
     };
});

inspection.js

...
module.exports = Repository.Model.extend(_.extend({
   tableName: 'inspections',
   actions: function () {
     return this.hasMany(require('./inspection-action'));
   }
}));

And a route:

 new VehicleInspection().fetchOrCreate(req.params.vehicle_id, req.params.inspection_id, {withRelated: ['inspection.actions']})
 .then(function (vehicleInspection) {
    var inspection = vehicleInspection.related('inspection');
    console.log( inspection);
    console.log(inspection.related(actions);
  })

The inspection console log prints out the correct inspection, however, irrelevantly of what is in the database the second console.log prints out an empty result

 { length: 0,
  models: [],
 _byId: {},
   ...
  targetIdAttribute: 'id',
 foreignKey: undefined,
 parentId: undefined,
 parentTableName: 'tasks',
 parentIdAttribute: 'id',
 parentFk: undefined } }

This "bad" behaviour only occurs the first time a projectTasks entry is being created. What appears to be happening is that the inspection_action table is not being populated through the nested withRelated. How could I get this working nested create working?

1

There are 1 best solutions below

4
Allie Hoch Janoch On BEST ANSWER

I'm not completely clear what you are trying to achieve, but here is how I would generally set things up. First I'd create a base model (assuming its saved as base.js), I think you are going to have some problems with circular dependencies, so using the Bookshelf registry plugin would be good:

var config = {
  client: // whatever client you are using,
  connection: // url to your database
};
var db = require('knex')(config);
var Bookshelf = require('bookshelf')(db);
var Base = Bookshelf.Model.extend({
   // Put anything here that will be helpful for your use case
});
Bookshelf.plugin('registry');

Base.model = Bookshelf.model.bind(Bookshelf);
module.exports = Base;

Next create your Vehicle model:

 require('inspection');
 require('action');
 var Base = require('base');

 var Vehicle = Base.Model.extend({
   tableName = 'vehicles',
   inspections: function () {
     return this.belongsToMany('Inspection',
       'inspections_vehicles', 'vehicle_id', 'inspection_id');
   },
   actions: function() {
     return this.belongsToMany('Action',
       'actions_vehicles', 'vehicle_id', 'action_id');

   }
 };
 module.exports = Base.model('Vehicle', Vehicle);

Then an inspection model:

 require('vehicle');
 var Base = require('base');

 var Inspection = Base.Model.extend({
   tableName = 'inspection',
   vehicles: function () {
     return this.belongsToMany('Vehicle',
       'inspections_vehicles', 'inspection_id', 'vehicle_id');
     }
 };
 module.exports = Base.model('Inspection', Inspection);

Finally an action model:

 var Base = require('base');

 var Action = Base.Model.extend({
   tableName = 'actions',
 };
 module.exports = Base.model('Action', Action);

Now assuming that the database isn't already filled in with the data you supplied, we can populate it:

var Inspection = require('inspection');
var Vehicle = require('vehicle');
var Action = require('action');
var toyota;
var newYorkInspection

Vehicle.forge().save({name: 'Toyota'})
  .then(function(vehicle) {
    toyota = vehicle;   
    return Inspection.forge().save({location: 'New York', date: 'Tomorrow'});      
  }).then(function(inspection){
    newYorkInspection = inspection;
    return toyota.inspections().attach(newYorkInspection);
  }).then(function() {
    return Action.forge().save({description: 'Check Tire Pressure'});
  }).then(function(tirePressureAction) {
    return toyota.actions().attach(tirePressureAction);
  });

Now I can fetch the toyota vehicle with the related actions and inspections:

var Vehicle = require('vehicle');
return Vehicle.forge({'name': 'Toyota'}).fetch({
  withRelated: ['inspections', 'actions']
}).then(function(toyota){
  var toyotaInspections = toyota.related('inspections');
  var toyotaActions = toyota.related('actions');
});