Add support to n:m relations
This commit is contained in:
parent
aa396620fa
commit
7b305b4920
54
lib/sql.js
54
lib/sql.js
|
@ -1073,33 +1073,51 @@ SQLConnector.prototype.buildJoins = function(model, where) {
|
|||
var relations = modelDef.model.relations;
|
||||
var stmt = new ParameterizedSQL('', []);
|
||||
|
||||
var buildOneToMany = function buildOneToMany(modelFrom, keyFrom, modelTo, keyTo, filter) {
|
||||
var modelToEscaped = this.tableEscaped(modelTo);
|
||||
var innerFilter = assign({}, filter);
|
||||
var innerIdField = {};
|
||||
innerIdField[keyTo] = true;
|
||||
innerFilter.fields = assign({}, innerFilter.fields, innerIdField);
|
||||
|
||||
var condition = this.columnEscaped(modelFrom, keyFrom) + '=' +
|
||||
this.columnEscaped(modelTo, keyTo);
|
||||
|
||||
var innerSelect = this.buildSelect(modelTo, innerFilter, {
|
||||
skipParameterize: true
|
||||
});
|
||||
|
||||
return new ParameterizedSQL('INNER JOIN (', [])
|
||||
.merge(innerSelect)
|
||||
.merge(') AS ' + modelToEscaped)
|
||||
.merge('ON ' + condition);
|
||||
}.bind(this);
|
||||
|
||||
for (var key in where) {
|
||||
if (!(key in relations)) continue;
|
||||
|
||||
var rel = relations[key];
|
||||
var keyFrom = rel.keyFrom;
|
||||
var modelTo = rel.modelTo.definition.name;
|
||||
var modelToEscaped = this.tableEscaped(modelTo);
|
||||
var keyTo = rel.keyTo;
|
||||
|
||||
var innerWhere = assign({}, where[key]);
|
||||
var innerIdField = {};
|
||||
innerIdField[keyTo] = true;
|
||||
innerWhere.fields = assign({}, innerWhere.fields, innerIdField);
|
||||
|
||||
var condition = this.columnEscaped(model, keyFrom) + '=' +
|
||||
this.columnEscaped(modelTo, keyTo);
|
||||
|
||||
var innerSelect = this.buildSelect(modelTo, innerWhere, {
|
||||
skipParameterize: true
|
||||
});
|
||||
|
||||
stmt
|
||||
.merge('INNER JOIN (')
|
||||
.merge(innerSelect)
|
||||
.merge(') AS ' + modelToEscaped)
|
||||
.merge('ON ' + condition);
|
||||
var join;
|
||||
if (!rel.modelThrough) {
|
||||
// 1:n relation
|
||||
join = buildOneToMany(model, keyFrom, modelTo, keyTo, where[key]);
|
||||
} else {
|
||||
// n:m relation
|
||||
var modelThrough = rel.modelThrough.definition.name;
|
||||
var keyThrough = rel.keyThrough;
|
||||
var modelToKey = rel.modelTo.definition._ids[0].name;
|
||||
var innerFilter = {fields: {}};
|
||||
innerFilter.fields[keyThrough] = true;
|
||||
|
||||
var joinInner = buildOneToMany(model, keyFrom, modelThrough, keyTo, innerFilter);
|
||||
join = buildOneToMany(modelThrough, keyThrough, modelTo, modelToKey, where[key]);
|
||||
join = joinInner.merge(join);
|
||||
}
|
||||
stmt.merge(join);
|
||||
}
|
||||
|
||||
return stmt;
|
||||
|
|
|
@ -57,6 +57,12 @@ describe('sql connector', function() {
|
|||
Order.belongsTo(Customer, {as: 'customer', foreignKey: 'customer_name'});
|
||||
Order.belongsTo(Store, {as: 'store', foreignKey: 'store_id'});
|
||||
Store.hasMany(Order, {as: 'orders', foreignKey: 'store_id'});
|
||||
Store.hasMany(Customer, {
|
||||
as: 'customers',
|
||||
through: Order,
|
||||
foreignKey: 'store_id',
|
||||
keyThrough: 'customer_name'
|
||||
});
|
||||
Customer.belongsTo(Store, {as: 'favorite_store', foreignKey: 'favorite_store'});
|
||||
Store.hasMany(Customer, {as: 'customers_fav', foreignKey: 'favorite_store'});
|
||||
});
|
||||
|
@ -343,7 +349,7 @@ describe('sql connector', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('builds SELECT with INNER JOIN', function () {
|
||||
it('builds SELECT with INNER JOIN (1:n relation)', function () {
|
||||
var sql = connector.buildSelect('customer', {
|
||||
where: {
|
||||
orders: {
|
||||
|
@ -364,6 +370,28 @@ describe('sql connector', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('builds SELECT with INNER JOIN (n:n relation)', function () {
|
||||
var sql = connector.buildSelect('store', {
|
||||
where: {
|
||||
customers: {
|
||||
where: {
|
||||
vip: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(sql.toJSON()).to.eql({
|
||||
sql: 'SELECT DISTINCT `STORE`.`ID`,`STORE`.`STATE` FROM `STORE` INNER JOIN' +
|
||||
' ( SELECT `ORDER`.`CUSTOMER_NAME`,`ORDER`.`STORE_ID` FROM `ORDER` ' +
|
||||
'ORDER BY `ORDER`.`ID` ) AS `ORDER` ON `STORE`.`ID`=`ORDER`.`STORE_ID` ' +
|
||||
'INNER JOIN ( SELECT `CUSTOMER`.`NAME` FROM `CUSTOMER` WHERE ' +
|
||||
'`CUSTOMER`.`VIP`=$1 ORDER BY `CUSTOMER`.`NAME` ) AS `CUSTOMER` ON ' +
|
||||
'`ORDER`.`CUSTOMER_NAME`=`CUSTOMER`.`NAME` ORDER BY `STORE`.`ID`',
|
||||
params: [true]
|
||||
});
|
||||
});
|
||||
|
||||
it('builds SELECT with INNER JOIN and order by relation columns', function () {
|
||||
var sql = connector.buildSelect('order', {
|
||||
where: {
|
||||
|
|
Loading…
Reference in New Issue