四好公路
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

727 lines
22 KiB

'use strict';
var Promise = require('bluebird'),
request = require('request'),
expect = require('chai').expect,
_ = require('lodash'),
rest = require('../../lib'),
test = require('../support');
describe('Associations(BelongsTo)', function() {
before(function() {
test.models.User = test.db.define('users', {
id: { type: test.Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
username: { type: test.Sequelize.STRING, unique: true },
email: { type: test.Sequelize.STRING, unique: true, validate: { isEmail: true } }
}, {
underscored: true,
timestamps: false
});
test.models.Yuppie = test.db.define('yuppies', {
id: { type: test.Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
username: { type: test.Sequelize.STRING, unique: true },
email: { type: test.Sequelize.STRING, unique: true, validate: { isEmail: true } }
}, {
underscored: true,
timestamps: false
});
test.models.Address = test.db.define('addresses', {
id: { type: test.Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
street: { type: test.Sequelize.STRING },
state_province: { type: test.Sequelize.STRING },
postal_code: { type: test.Sequelize.STRING },
country_code: { type: test.Sequelize.STRING }
}, {
underscored: true,
timestamps: false
});
test.models.Person = test.db.define('person', {
id: { type: test.Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
name: { type: test.Sequelize.STRING, unique: true }
}, {
underscored: true,
timestamps: false
});
test.models.Hobby = test.db.define('hobby', {
id: { type: test.Sequelize.INTEGER, autoIncrement: true, primaryKey: true },
name: { type: test.Sequelize.STRING }
}, {
underscored: true,
timestamps: false
});
// Yuppies have two addresses
test.models.Yuppie.belongsTo(test.models.Address, {
as: 'address2',
foreignKey: 'address2_id'
});
test.models.Yuppie.belongsTo(test.models.Address);
test.models.User.belongsTo(test.models.Address); // user has an address_id
test.models.Person.belongsTo(test.models.Address, {
as: 'addy',
foreignKey: 'addy_id'
});
test.models.Person.belongsToMany(test.models.Hobby, {
as: 'hobbies',
through: 'person_hobbies'
});
test.models.Hobby.belongsToMany(test.models.Person, {
as: 'people',
through: 'person_hobbies'
});
});
beforeEach(function() {
return Promise.all([ test.initializeDatabase(), test.initializeServer() ])
.then(function() {
rest.initialize({
app: test.app,
sequelize: test.Sequelize
});
test.usersResource = rest.resource({
model: test.models.User,
endpoints: ['/users', '/users/:id'],
associations: true
});
rest.resource({
model: test.models.User,
endpoints: ['/usersWithoutFK', '/usersWithoutFK/:id'],
associations: {
removeForeignKeys: true
}
});
rest.resource({
model: test.models.User,
endpoints: ['/usersWithoutInclude', '/usersWithoutInclude/:id']
});
rest.resource({
model: test.models.Person,
endpoints: ['/people', '/people/:id'],
associations: true
});
rest.resource({
model: test.models.Yuppie,
endpoints: ['/yuppies', '/yuppies/:id'],
associations: true
});
rest.resource({
model: test.models.Person,
include: [
{ model: test.models.Address, as: 'addy' },
{ model: test.models.Hobby, as: 'hobbies' }
],
endpoints: ['/personWithTwoIncludes', '/personWithTwoIncludes/:id']
});
rest.resource({
model: test.models.Address,
endpoints: ['/addresses', '/addresses/:id']
});
});
});
afterEach(function() {
return test.clearDatabase()
.then(function() { return test.closeServer(); });
});
// TESTS
describe('read', function() {
beforeEach(function() {
return Promise.all([
test.models.Address.create({
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}),
test.models.Address.create({
street: 'Avenue de l\'Atomium',
state_province: 'Brussels',
postal_code: '1020',
country_code: '32'
}),
test.models.User.create({
username: 'sherlock',
email: 'sherlock@holmes.com'
}),
test.models.User.create({
username: 'MannekenPis',
email: 'manneken.pis@brussels.be'
}),
test.models.Person.create({ name: 'barney' })
]).spread(function(address, address2, user, user2, person) {
return Promise.all([
user.setAddress(address),
person.setAddy(address)
]);
});
});
it('should include prefetched data', function(done) {
request.get({
url: test.baseUrl + '/users/1'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 1,
username: 'sherlock',
email: 'sherlock@holmes.com',
address_id: 1,
address: {
id: 1,
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}
};
expect(result).to.eql(expected);
done();
});
});
it('should include prefetched data without foreign keys', function(done) {
test.usersResource.associationOptions.removeForeignKeys = true;
request.get({
url: test.baseUrl + '/users/1'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 1,
username: 'sherlock',
email: 'sherlock@holmes.com',
address: {
id: 1,
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}
};
expect(result).to.eql(expected);
test.usersResource.associationOptions.removeForeignKeys = false;
done();
});
});
it('should include prefetched data for an aliased relation', function(done) {
request.get({
url: test.baseUrl + '/people/1'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 1,
name: 'barney',
hobbies: [],
addy_id: 1,
addy: {
id: 1,
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}
};
expect(result).to.eql(expected);
done();
});
});
it('should return associated data by url', function(done) {
request.get({
url: test.baseUrl + '/users/1/address'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 1,
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
};
expect(result).to.eql(expected);
done();
});
});
it('should return associated data by url (2)', function(done) {
request.get({
url: test.baseUrl + '/users/2/address'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 2,
street: 'Avenue de l\'Atomium',
state_province: 'Brussels',
postal_code: '1020',
country_code: '32'
};
expect(result).to.eql(expected);
done();
});
});
it('should include prefetched data without foreign key', function(done) {
request.get({
url: test.baseUrl + '/usersWithoutFK/1'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
var expected = {
id: 1,
username: 'sherlock',
email: 'sherlock@holmes.com',
address: {
id: 1,
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}
};
expect(result).to.eql(expected);
done();
});
});
});
describe('list', function() {
beforeEach(function() {
test.expectedResults = [];
var testData = [
{
user: { username: 'sherlock', email: 'sherlock@gmail.com' },
address: { street: '221B Baker Street', state_province: 'London, UK', postal_code: 'NW1', country_code: '44'}
},
{
user: { username: 'barack', email: 'barack@gmail.com' },
address: { street: '1600 Pennsylvania Ave', state_province: 'Washington, DC', postal_code: '20500', country_code: '001'}
},
{
user: { username: 'tony', email: 'tony@gmail.com' },
address: { street: '633 Stag Trail RD', state_province: 'Caldwell, NJ', postal_code: '07006', country_code: '001'}
},
{
user: { username: 'eddie', email: 'eddie@gmail.com' },
address: { street: '1313 Mockingbird Ln', state_province: 'Lincoln, CA', postal_code: '95648', country_code: '001'}
},
{
user: { username: 'lucy', email: 'lucy@gmail.com' },
address: { street: '623 East 68th Street', state_province: 'New York, NY', postal_code: '10065', country_code: '001'}
}
];
return Promise.resolve(testData).each(function(entry) {
return Promise.all([
test.models.User.create(entry.user),
test.models.Address.create(entry.address)
]).spread(function(user, address) {
var expectedResult = entry.user;
expectedResult.id = user.id;
expectedResult.address = address.dataValues;
expectedResult.address_id = address.dataValues.id;
test.expectedResults.push(expectedResult);
return user.setAddress(address);
});
});
});
afterEach(function() {
delete test.expectedResults;
});
it('should include prefetched data', function(done) {
request.get({
url: test.baseUrl + '/users'
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result).to.eql(test.expectedResults);
done();
});
});
it('should pass query parameters to search', function(done) {
request.get({
url: test.baseUrl + '/usersWithoutInclude?address_id=1'
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.length).to.equal(1);
var actual = result[0];
var expected = {
id: 1,
username: 'sherlock',
email: 'sherlock@gmail.com',
address_id: 1
};
expect(actual).to.eql(expected);
done();
});
});
it('should include two associations', function(done) {
var hobbyRecords = [
{ name: 'programming' },
{ name: 'baseball' }
];
var records = [
{
person: { name: 'john' },
address: { street: '100 First Street ' }
},
{
person: { name: 'joe' },
address: { street: '200 Second Street' }
}
];
var expectedPerson;
var expectedId;
Promise.resolve(records).each(function(record) {
return Promise.all([
test.models.Person.create(record.person),
test.models.Address.create(record.address)
]).spread(function(person, address) {
return person.setAddy(address);
});
}).then(function() {
return Promise.all([
test.models.Hobby.create(hobbyRecords[0]),
test.models.Hobby.create(hobbyRecords[1]),
test.models.Person.findAll()
]);
}).spread(function(hobby0, hobby1, people) {
var person = people[0];
expectedId = person.id;
return person.setHobbies([hobby0, hobby1]);
}).then(function(hobbies) {
return test.models.Person.find({
where: { id: expectedId },
include: [
{ model: test.models.Address, as: 'addy' },
{ model: test.models.Hobby, as: 'hobbies' }
]
});
}).then(function(person) {
expectedPerson = JSON.parse(JSON.stringify(person.dataValues));
request.get({
url: test.baseUrl + '/personWithTwoIncludes?q=' + expectedPerson.name
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
body = _.isObject(body) ? body : JSON.parse(body);
expect(body[0]).to.eql(expectedPerson);
done();
});
});
});
it('should include prefetched data without foreign key', function(done) {
request.get({
url: test.baseUrl + '/usersWithoutFK'
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result).to.eql(test.expectedResults.map(function(i) {
delete i.address_id;
return i;
}));
done();
});
});
});
describe('update', function() {
beforeEach(function() {
test.addresses = [
{
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
},
{
street: 'Avenue de l\'Atomium',
state_province: 'Brussels',
postal_code: '1020',
country_code: '32'
}
];
return Promise.all([
test.models.Address.create(test.addresses[0]),
test.models.Address.create(test.addresses[1]),
test.models.User.create({
username: 'sherlock',
email: 'sherlock@holmes.com'
}),
test.models.User.create({
username: 'watson',
email: 'watson@holmes.com'
}),
test.models.Yuppie.create({
username: 'richguy',
email: 'lotsof@money.com'
})
]).spread(function(address, address2, user, user2, yuppie) {
test.addresses[0].id = address.id;
test.addresses[1].id = address2.id;
return Promise.all([
user.setAddress(address),
yuppie.setAddress(address)
]);
});
});
it('should include associated data', function(done) {
request.put({
url: test.baseUrl + '/users/1',
json: {}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(1);
done();
});
});
it('should not include associated data', function(done) {
request.put({
url: test.baseUrl + '/usersWithoutInclude/1',
json: {}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address_id).to.exist;
expect(result.address_id).to.be.eql(1);
done();
});
});
it('should include the new associated data with multiple references to the same model', function(done) {
request.put({
url: test.baseUrl + '/yuppies/1',
json: {
address_id: 2
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address_id).to.be.eql(2);
expect(result.address).to.eql(test.addresses[1]);
done();
});
});
it('should include the new associated data', function(done) {
request.put({
url: test.baseUrl + '/users/1',
json: {
address_id: 2
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
expect(result.address).to.eql(test.addresses[1]);
done();
});
});
it('should include the new associated data by identifier of object nested', function(done) {
request.put({
url: test.baseUrl + '/users/1',
json: {
address: { id: 2 }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
expect(result.address_id).to.be.eql(2);
done();
});
});
it('should include the new associated data without foreign key', function(done) {
request.put({
url: test.baseUrl + '/usersWithoutFK/1',
json: {
address_id: 2
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
expect(result).to.not.contain.key('address_id');
done();
});
});
it('should allow updating an association to null by replacing its primary key', function(done) {
request.put({
url: test.baseUrl + '/users/1',
json: {
address: { id: 2 }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
request.put({
url: test.baseUrl + '/users/1',
json: {
address: { id: null }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.null;
done();
});
});
});
it('should allow updating an association with null', function(done) {
request.put({
url: test.baseUrl + '/users/1',
json: {
address: { id: 2 }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
request.put({
url: test.baseUrl + '/users/1',
json: {
address: null
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.address).to.be.null;
done();
});
});
});
it('should successfully reload an instance with both 1:1 and m:n relation when the 1:1 relation is changed', function(done) {
var personData = { name: 'John Smith' };
Promise.all([
test.models.Person.create(personData),
test.models.Address.create({ street: '123 Main St' })
]).spread(function(person, address) {
personData.addy_id = address.id;
request.put({
url: test.baseUrl + '/personWithTwoIncludes/' + person.id,
json: personData
}, function(error, response, body) {
expect(response.statusCode).to.equal(200);
done();
});
});
});
});
describe('create', function() {
beforeEach(function() {
rest.resource({
model: test.models.User,
include: [test.models.Address],
endpoints: ['/usersNotReloadInstances', '/usersNotReloadInstances/:id'],
reloadInstances: false
});
return Promise.all([
test.models.Address.create({
street: '221B Baker Street',
state_province: 'London',
postal_code: 'NW1',
country_code: '44'
}),
test.models.Address.create({
street: 'Avenue de l\'Atomium',
state_province: 'Brussels',
postal_code: '1020',
country_code: '32'
})
]);
});
it('should include the new associated data by identifier of object nested', function(done) {
request.post({
url: test.baseUrl + '/users',
json: {
username: 'sherlock',
address: { id: 2 }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.username).to.be.eql('sherlock');
expect(result.address_id).to.be.eql(2);
expect(result.address).to.be.an('object');
expect(result.address.id).to.be.eql(2);
done();
});
});
it('should include the new associated data by identifier of object nested without reload', function(done) {
request.post({
url: test.baseUrl + '/usersNotReloadInstances',
json: {
username: 'sherlock',
address: { id: 2 }
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.username).to.be.eql('sherlock');
expect(result).to.not.contain.key('address');
expect(result.address_id).to.be.eql(2);
done();
});
});
it('should not include the associated data by identifier of object nested', function(done) {
request.post({
url: test.baseUrl + '/usersWithoutInclude',
json: {
username: 'sherlock'
}
}, function(error, response, body) {
var result = _.isObject(body) ? body : JSON.parse(body);
expect(result.username).to.be.eql('sherlock');
expect(result).to.not.contain.key('address');
done();
});
});
});
});