-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
93 lines (80 loc) · 2.82 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
const Sequelize = require('sequelize');
module.exports = function init(target) {
const isModel = target instanceof Sequelize.Model ||
Sequelize.Model.isPrototypeOf(target);
if (!isModel && !target.QueryTypes && !target.Model) {
throw new Error(
'sequelize-pg-bulkupdate(target) : ',
'target must be a sequelize model or the Sequelize object.'
);
} else if (target.Model) {
target = target.Model;
}
attachFunctions(target);
};
function attachFunctions(target) {
target.bulkUpdate = bulkUpdate;
}
/**
* Function attached to the models
*/
function bulkUpdate(values, options = {}) {
if (this.sequelize.options.dialect != 'postgres') {
throw new Error(
'bulkUpdate() only works with postgres dialect.'
);
}
if ( values.length == 0 ) return Promise.resolve([ [], 0 ]);
const tableName = this.getTableName();
const attributes = this.rawAttributes;
const replacements = values.reduce((acc,d) => {
for (const key in d) {
const val = d[key];
acc[key] = acc[key] || [];
acc[key].push(val);
}
return acc;
}, {});
const sql = sqlForBulkUpdate(tableName, values, options, attributes, this);
return this.sequelize.query(sql, {
type: Sequelize.QueryTypes.UPDATE,
replacements
});
}
/**
* Generate the SQL for the bulk update.
*/
function sqlForBulkUpdate(tableName, values, options, attributes, model) {
const primaryKey = options.key || model.primaryKeyAttribute;
const quotedTableName = model.QueryGenerator.quoteTable(tableName);
const fields = Object.keys(attributes).reduce((acc,k) => {
const a = attributes[ k ];
if (a.primaryKey) return acc;
if (!a._modelAttribute) return acc;
if (a.fieldName == primaryKey) return acc;
if (options.fields && !options.fields.includes(a.fieldName))
return acc;
if (!Object.keys(values[0]).includes(a.fieldName)) return acc;
acc.push(a.fieldName);
return acc;
}, [] );
const type = attributes[primaryKey].type.toSql();
let selects = [
`UNNEST(array[:${primaryKey}])::${type} as ${primaryKey}`
];
let updateValues = [];
for (const field of fields) {
const type = attributes[field].type.toSql();
selects.push(`UNNEST(array[:${field}])::${type} as ${field}`);
updateValues.push(`"${field}" = "data_table"."${field}"`);
}
let sql = `UPDATE ${quotedTableName} `;
sql += `SET ${updateValues.join(', ')} FROM `;
sql += `(SELECT ${selects.join(', ')}) as "data_table" `;
let where = `${quotedTableName}."${primaryKey}" = "data_table"."${primaryKey}"`;
sql += `WHERE ${where}`;
if ( options.returning ) {
sql += 'RETURNING *'
}
return sql;
}