使用 pg-promise 跳过更新列
skip update columns with pg-promise
我在使用 Postgres 的 pg-promise 的节点上安装了 API,这很好用,但我正在考虑如何修改 PUT 语句以更好地处理输入中的 NULLS。
PUT语句的代码如下:
//UPDATE a single record
function updateRecord(req, res, next) {
db.none('update generic1 SET string1=,' +
'string2=,' +
'string3=,' +
'string4=,' +
'string5=,' +
'string6=,' +
'integer1=,' +
'integer2=,' +
'integer3=,' +
'date1=,' +
'date2=,' +
'date3=,' +
'currency1=,' +
'currency2=' +
'WHERE id = ',
[req.body.string1,
req.body.string2,
req.body.string3,
req.body.string4,
req.body.string5,
req.body.string6,
parseInt(req.body.integer1),
parseInt(req.body.integer2),
parseInt(req.body.integer3),
req.body.date1,
req.body.date2,
req.body.date3,
parseInt(req.body.currency1),
parseInt(req.body.currency2),
parseInt(req.params.id)])
.then(function(){
res.status(200)
.json({
'status': 'success',
'message': 'updated one record'
});
})
.catch(function(err){
return next(err);
});
}
现在这条语句有效,但如果我将 NULLS 传递给下一次更新,它也会删除现有值。例如,如果我只想更新 string1 和 date2,我必须发送整个 json 对象,否则所有其他值都将设置为 NULL。
有没有更好的方法来处理这个问题?我应该改用 PATCH 动词吗??
我是 pg-promise 的作者 ;)
var pgp = require('pg-promise')({
capSQL: true // capitalize all generated SQL
});
// generic way to skip NULL/undefined values for strings:
function str(col) {
return {
name: col,
skip: function () {
var val = this[col];
return val === null || val === undefined;
}
};
}
// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(col) {
return {
name: col,
skip: function () {
var val = this[col];
return val === null || val === undefined;
},
init: function () {
return parseInt(this[col]);
}
};
}
// Creating a reusable ColumnSet for all updates:
var csGeneric = new pgp.helpers.ColumnSet([
str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
str('string6'), int('integer1'), int('integer2'), int('integer3'),
str('date1'), str('date2'), str('date3')
], {table: 'generic1'});
// Your new request handler:
function updateRecord(req, res, next) {
var update = pgp.helpers.update(req.body, csGeneric) + ' WHERE id = ' +
parseInt(req.params.id);
db.none(update)
.then(function () {
res.status(200)
.json({
'status': 'success',
'message': 'updated one record'
});
})
.catch(function (err) {
return next(err);
});
}
查看 helpers 命名空间 ;)
或者,您可以对每一列进行自己的验证,然后相应地生成一个 UPDATE
查询,尽管它不会那么优雅 ;)
更新
请注意 init
和 skip
的参数化方式在库的 5.4.0 版本中发生了变化,请参阅 the release notes。
从5.4.0版本开始,您可以将代码简化为:
// generic way to skip NULL/undefined values for strings:
function str(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined
};
}
// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined,
init: c => +c.value
};
}
如果你想跳过根本没有传入的属性,因此甚至不存在于对象中,那么代替这个:
skip: c => c.value === null || c.value === undefined
你可以这样做:
skip: c => !c.exists
更新
库的版本 5.6.7 对此进行了进一步改进 - 选项 emptyUpdate
,指定时表示方法返回的值,而不是抛出 Cannot generate an UPDATE without any columns
。有关详细信息,请参阅 helpers.update。
另请参阅:ColumnConfig。
谢谢@vitaly-t!更快更干净,总是好的结果:)
作为参考,我还包含了使用上述帮助器的插入语句。
//firstly create a function that skips the nulls for strings
function str(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined || !c.exists
};
}
//now a function that skips nulls for integers, while parsing type
function int(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined || !c.exists,
init: c => +c.value
};
}
//creating a column set for all updates
var usefulColumSet = new pgp.helpers.ColumnSet([
str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
str('string6'), int('integer1'), int('integer2'), int('integer3'),
str('date1'), str('date2'), str('date3'), int('currency1'), int('currency2')
], {table: 'generic1'});
//*********************CREATE a single record*************************
function createRecord(req, res, next) {
var insert = pgp.helpers.insert(req.body, usefulColumSet);
db.none(insert)
.then(function(){
res.status(200)
.json({
status: 'success',
message: 'Inserted one record successully'
});
})
.catch(function(err){
return next(err);
});
}
//************************UPDATE a single record*************
function updateRecord(req, res, next) {
var update = pgp.helpers.update(req.body, usefulColumSet) + ' WHERE id = ' + parseInt(req.params.id);
db.none(update)
.then(function() {
res.status(200)
.json({
status: 200,
message: 'updated a single record cleanly'
});
})
.catch(function(err) {
return next(err);
});
}
备选方案:
function updateFoo(req, res){
let {name, email, password} = req.body;
// Ex: req.body = { name: 'foo', password: 'bar' }
let data = { name, email, password }; // {name: 'foo', email:undefined, password:'bar}
//Remove ONLY undefined keys from data
Object.keys(data).forEach( key => { if(data[key] === undefined) delete data[key] });
let query = 'UPDATE foo SET';
let i = 1;
Object.keys(data).forEach( key => { query += ` ${key}=$${index},`; i++; })
query = query.slice(0, -1) // Remove exceeding comma
query += ` WHERE id=$${i}`;
let values = Object.values(data); // ['foo', 'bar']
values.push(req.params.id);
// .....
// query = 'UPDATE foo SET name=, password= WHERE id='
// values = ['foo', 'bar', req.params.id]
我在使用 Postgres 的 pg-promise 的节点上安装了 API,这很好用,但我正在考虑如何修改 PUT 语句以更好地处理输入中的 NULLS。
PUT语句的代码如下:
//UPDATE a single record
function updateRecord(req, res, next) {
db.none('update generic1 SET string1=,' +
'string2=,' +
'string3=,' +
'string4=,' +
'string5=,' +
'string6=,' +
'integer1=,' +
'integer2=,' +
'integer3=,' +
'date1=,' +
'date2=,' +
'date3=,' +
'currency1=,' +
'currency2=' +
'WHERE id = ',
[req.body.string1,
req.body.string2,
req.body.string3,
req.body.string4,
req.body.string5,
req.body.string6,
parseInt(req.body.integer1),
parseInt(req.body.integer2),
parseInt(req.body.integer3),
req.body.date1,
req.body.date2,
req.body.date3,
parseInt(req.body.currency1),
parseInt(req.body.currency2),
parseInt(req.params.id)])
.then(function(){
res.status(200)
.json({
'status': 'success',
'message': 'updated one record'
});
})
.catch(function(err){
return next(err);
});
}
现在这条语句有效,但如果我将 NULLS 传递给下一次更新,它也会删除现有值。例如,如果我只想更新 string1 和 date2,我必须发送整个 json 对象,否则所有其他值都将设置为 NULL。
有没有更好的方法来处理这个问题?我应该改用 PATCH 动词吗??
我是 pg-promise 的作者 ;)
var pgp = require('pg-promise')({
capSQL: true // capitalize all generated SQL
});
// generic way to skip NULL/undefined values for strings:
function str(col) {
return {
name: col,
skip: function () {
var val = this[col];
return val === null || val === undefined;
}
};
}
// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(col) {
return {
name: col,
skip: function () {
var val = this[col];
return val === null || val === undefined;
},
init: function () {
return parseInt(this[col]);
}
};
}
// Creating a reusable ColumnSet for all updates:
var csGeneric = new pgp.helpers.ColumnSet([
str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
str('string6'), int('integer1'), int('integer2'), int('integer3'),
str('date1'), str('date2'), str('date3')
], {table: 'generic1'});
// Your new request handler:
function updateRecord(req, res, next) {
var update = pgp.helpers.update(req.body, csGeneric) + ' WHERE id = ' +
parseInt(req.params.id);
db.none(update)
.then(function () {
res.status(200)
.json({
'status': 'success',
'message': 'updated one record'
});
})
.catch(function (err) {
return next(err);
});
}
查看 helpers 命名空间 ;)
或者,您可以对每一列进行自己的验证,然后相应地生成一个 UPDATE
查询,尽管它不会那么优雅 ;)
更新
请注意 init
和 skip
的参数化方式在库的 5.4.0 版本中发生了变化,请参阅 the release notes。
从5.4.0版本开始,您可以将代码简化为:
// generic way to skip NULL/undefined values for strings:
function str(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined
};
}
// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined,
init: c => +c.value
};
}
如果你想跳过根本没有传入的属性,因此甚至不存在于对象中,那么代替这个:
skip: c => c.value === null || c.value === undefined
你可以这样做:
skip: c => !c.exists
更新
库的版本 5.6.7 对此进行了进一步改进 - 选项 emptyUpdate
,指定时表示方法返回的值,而不是抛出 Cannot generate an UPDATE without any columns
。有关详细信息,请参阅 helpers.update。
另请参阅:ColumnConfig。
谢谢@vitaly-t!更快更干净,总是好的结果:)
作为参考,我还包含了使用上述帮助器的插入语句。
//firstly create a function that skips the nulls for strings
function str(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined || !c.exists
};
}
//now a function that skips nulls for integers, while parsing type
function int(column) {
return {
name: column,
skip: c => c.value === null || c.value === undefined || !c.exists,
init: c => +c.value
};
}
//creating a column set for all updates
var usefulColumSet = new pgp.helpers.ColumnSet([
str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
str('string6'), int('integer1'), int('integer2'), int('integer3'),
str('date1'), str('date2'), str('date3'), int('currency1'), int('currency2')
], {table: 'generic1'});
//*********************CREATE a single record*************************
function createRecord(req, res, next) {
var insert = pgp.helpers.insert(req.body, usefulColumSet);
db.none(insert)
.then(function(){
res.status(200)
.json({
status: 'success',
message: 'Inserted one record successully'
});
})
.catch(function(err){
return next(err);
});
}
//************************UPDATE a single record*************
function updateRecord(req, res, next) {
var update = pgp.helpers.update(req.body, usefulColumSet) + ' WHERE id = ' + parseInt(req.params.id);
db.none(update)
.then(function() {
res.status(200)
.json({
status: 200,
message: 'updated a single record cleanly'
});
})
.catch(function(err) {
return next(err);
});
}
备选方案:
function updateFoo(req, res){
let {name, email, password} = req.body;
// Ex: req.body = { name: 'foo', password: 'bar' }
let data = { name, email, password }; // {name: 'foo', email:undefined, password:'bar}
//Remove ONLY undefined keys from data
Object.keys(data).forEach( key => { if(data[key] === undefined) delete data[key] });
let query = 'UPDATE foo SET';
let i = 1;
Object.keys(data).forEach( key => { query += ` ${key}=$${index},`; i++; })
query = query.slice(0, -1) // Remove exceeding comma
query += ` WHERE id=$${i}`;
let values = Object.values(data); // ['foo', 'bar']
values.push(req.params.id);
// .....
// query = 'UPDATE foo SET name=, password= WHERE id='
// values = ['foo', 'bar', req.params.id]