bredikhin / barrels

Simple DB Fixtures for Sails.js
MIT License
85 stars 34 forks source link

Many to Many relations no longer working #44

Open dlangerenken opened 8 years ago

dlangerenken commented 8 years ago

After updating all libraries, it seems like the many to many relations are no longer working for me. Do you happen to know if any lib-update might effect barrels?

These are my dependencies:


  "dependencies": {
    "async": "1.5.2",
    "barrels": "1.6.4",
    "bcryptjs": "2.3.0",
    "bluebird": "3.2.2",
    "include-all": "0.1.6",
    "jsonwebtoken": "5.5.4",
    "lodash": "4.3.0",
    "moment-timezone": "0.5.0",
    "passport": "0.3.2",
    "passport-facebook": "2.1.0",
    "passport-github": "1.1.0",
    "passport-google": "0.3.0",
    "passport-local": "1.0.0",
    "passport-twitter": "1.0.4",
    "passport-custom": "1.0.5",
    "rc": "1.1.6",
    "sails": "0.12.0",
    "sails-disk": "0.10.9",
    "sails-hook-apianalytics": "0.3.0",
    "sails-mysql": "0.11.4",
    "sails-fixtures": "1.0.8",
    "ua-parser": "0.3.5",
    "validator": "4.7.1",
    "request": "2.69.0",
    "request-promise": "2.0.0",
    "winston": "^2.1.1",
    "q": "1.4.1"
  }

I populate all models before my 'main'-model is populated. This 'main'-model contains all references to the other models, e.g:

{ "id": 1, "title": "13In est risus, auctor sed,", "clearance": 1, "project": 13, "ipType": 0, "createdUser": 12, "authors": [ 10, 6 ], "published": "1997-01-25", "type": 5, "files": 627, "released": false },

My other json files (such as Project, Clearance, ...) do not contain any information about this 'main' model. I did not need it before the update.

One-To-One relations work fine, one-to-many as well. Only many-to-many don't seem to work anymore.

Do you have any workaround?

neonexus commented 8 years ago

@Dalanie, hopefully this isn't still an issue for you, but I had this problem as well. I can't find the issue, but it seems to be in the Waterline core, as I have issues with .add() manually. The fix, seems to be to use the "through" associations. Minor bugs there too, in that, autoCreatedAt and autoUpdatedAt can not be turned off on the middle-man table... But everything else works as intended otherwise.

aayush-practo commented 8 years ago

@neonexus @Dalanie I got the same error while writing fixtures for unit test, here are my fixtures, Project and student have many to many association:

Project.json:
[{
   id: 1,
   name: 'abc',
   students: [1]
}]

Student.json: 
[{
  id: 1,
  name: 'xyz',
  projects: [1]
}]

I get the following error:

Details:  [ { type: 'insert',
    collection: 'project_students__student_projects',
    criteria: { student_projects: 1, project_students: 1 },
    values: { student_projects: 1, project_students: 1 },
    err: [Error: Associated Record For student with id = 1 No Longer Exists] } ]

my bootstrap.spec.js is as follows:

var Sails = require('sails'),
  Barrels = require('barrels'),
  sails;

before(function(done) {

  // Increase the Mocha timeout so that Sails has enough time to lift.
  this.timeout(30000);

  Sails.lift({
    // configuration for testing purposes
    log: {
      level: 'error'
    },
     models: {
      connection: 'test',
      migrate: 'drop'
    }
  }, function(err, server) {
    sails = server;
    if (err) return done(err);
    // here you can load fixtures, etc.
     // Load fixtures
    var barrels = new Barrels();

    // Save original objects in `fixtures` variable
    fixtures = barrels.data;
    // Populate the DB
    barrels.populate(['project', 'student'], function(err) {
      if (err){
        return done(err);
      }
      else {
        return done(null, sails)
      }
    }, false);
  });
});

after(function(done) {
  // here you can clear fixtures, etc.
  // console.log('\n');
  Sails.lower(done);
});

What is the possible solution for this, I am using mocha@2.3.3, barrels@1.5.0, sails@0.12.3

neonexus commented 8 years ago

@aayush-practo Can I see your models?

aayush-practo commented 8 years ago

@neonexus, here are the models

Project.js

module.exports = {
  autoPK       : true,
  migrate      : 'safe',
  autoCreatedAt: true,
  autoUpdatedAt: true,
  attributes: {
     name: {
       type: 'string'
     },
     students: {
       collection: 'student',
       via       : 'projects'
     }
  },

  tableName: 'projects'
}

Student.js

module.exports = {
  autoPK       : true,
  migrate      : 'safe',
  autoCreatedAt: true,
  autoUpdatedAt: true,
  attributes: {
     name: {
       type: 'string'
     },
     projects: {
       collection: 'project',
       via       : 'students'
     }
  },

  tableName: 'students'
}
neonexus commented 8 years ago

@aayush-practo, you need to use "through" associations as I mentioned previously. There is a bug down in the Waterline core that needs to be addressed, and this is the way around that.

In other words, add the following model to your set (name it ProjectStudent.js):

module.exports = {
    attributes: {
        // force ID as first column, autoPk in Sails adds it to the end
        id: {
            type: 'int',
            primaryKey: true,
            autoIncrement: true
        },

        project: {
            model: 'project'
        },

        student: {
            model: 'student'
        }
    }
};

Then Project.js:

module.exports = {
  autoPK       : true,
  migrate      : 'safe',
  autoCreatedAt: true,
  autoUpdatedAt: true,
  attributes: {
     name: {
       type: 'string'
     },
     students: {
       collection: 'student',
       via       : 'project',
       through   : 'projectstudent'
     }
  },

  tableName: 'projects'
}

And Student.js:

module.exports = {
  autoPK       : true,
  migrate      : 'safe',
  autoCreatedAt: true,
  autoUpdatedAt: true,
  attributes: {
     name: {
       type: 'string'
     },
     projects: {
       collection: 'project',
       via       : 'student',
       through   : 'projectstudent'
     }
  },

  tableName: 'students'
}
mikedevita commented 8 years ago

is this still a bug in waterline and a requirement today? I tried doing as @neonexus suggested, but getting this error Error: Trying to associate a collection attribute to a model that doesn't have a Foreign Key. server is trying to reference a foreign key in servercomponent

models/ServerComponent.js

var ServerComponent = {
  name: 'ServerComponent',
  attributes: {
    id: {
      type: 'int',
      primaryKey: true,
      autoIncrement: true
    },
    server: {
      model: 'server'
    },
    component: {
      model: 'component'
    }
  }
};
module.export = ServerComponent;

models/Server.js

/**
 * Server.js
 *
 * @description :: TODO: You might write a short summary of how this model works and what it represents here.
 * @docs        :: http://sailsjs.org/documentation/concepts/models-and-orm/models
 */

var Server = {
  name: 'Server',
  autoPK: true,
  autoCreatedBy: true,
  attributes: {
    schema: true,
    hostname: {
      type: 'string',
      required: true,
      unique: true
    },

    cpu: {
      type: 'integer',
      required: true
    },

    ram: {
      type: 'float',
      required: true
    },

    swap: {
      type: 'float',
      required: true
    },
    dns: {
      type: 'json'
    },

    sid: {
      type: 'string',
      required: true
    },

    // associations
    roles: {
      collection: 'role',
      via: 'servers'
    },

    component: {
      collection: 'component',
      via: 'server',
      through: 'servercomponent'
    },

    location: {
      model: 'location'
    },
    createdBy: {
      model: 'User'
    },
    updatedBy: {
      model: 'User'
    }
  }
};
module.exports = Server;

models/Component.js

var Component = {
  name: 'Component',
  autoPK: true,
  schema: true,
  autoCreatedBy: true,
  attributes: {
    name: {
      type: 'string',
      required: true,
      unique: true
    },

    // associations
    servers: {
      collection: 'server',
      via: 'component',
      through: 'servercomponent'
    },
    createdBy: {
      model: 'User'
    },
    updatedBy: {
      model: 'User'
    }
  }
};
module.export = Component;