gpt4 book ai didi

node.js - JSON stringify 和 PostgreSQL bigint 合规性

转载 作者:行者123 更新时间:2023-11-29 13:39:00 24 4
gpt4 key购买 nike

I am trying to add BigInt support within my library ,并遇到了 JSON.stringify 的问题。

库的性质允许不必担心类型歧义和反序列化,因为序列化的所有内容都会进入服务器,并且永远不需要任何反序列化。

我最初想出了以下简化方法,只是为了抵消 Node.js 向我抛出 TypeError: Do not know how to serialize a BigInt:

// Does JSON.stringify, with support for BigInt:
function toJson(data) {
return JSON.stringify(data, (_, v) => typeof v === 'bigint' ? v.toString() : v);
}

但由于它将每个 BigInt 转换为字符串,因此每个值最终都用双引号引起来。

是否有任何解决方法,也许是 Node.js 格式化实用程序中的一些技巧,以从 JSON.stringify 生成结果,其中每个 BigInt 将被格式化为开放值(value)?这是 PostgreSQL 理解和支持的内容,因此我正在寻找一种方法来使用符合 PostgreSQL 的 BigInt 生成 JSON。

示例

const obj = {
value: 123n
};

console.log(toJson(obj));

// This is what I'm getting: {"value":"123"}
// This is what I want: {"value":123}

显然,我不能只将 BigInt 转换为 number,因为那样我会丢失信息。为此重写整个 JSON.stringify 可能太复杂了。

更新

此时我已经回顾并使用了几个 polyfill,比如这些:

但它们似乎都是一个笨拙的解决方案,引入这么多代码,然后修改以支持 BigInt。我希望找到更优雅的东西。

最佳答案

我最终得到的解决方案...

注入(inject)完整的 123n 数字,然后在 RegEx 的帮助下取消引号:

function toJson(data) {
return JSON.stringify(data, (_, v) => typeof v === 'bigint' ? `${v}n` : v)
.replace(/"(-?\d+)n"/g, (_, a) => a);
}

它完全可以满足需要,而且速度很快。唯一的缺点是,如果您在 data 中将一个值设置为类似 123n 的字符串,它将变成一个开放数字,但您可以在上面轻松混淆它,变成类似 ${^123^}123-bigint 的东西,算法很容易实现。

根据问题,该操作并不意味着是可逆的,因此如果您对结果使用 JSON.parse,这些将是 number-s,丢失正如预期的那样,2^532^64 - 1 之间的任何值。

谁说这是不可能的 - 是吧? :)

UPDATE-1

为了与 JSON.stringify 兼容,undefined 必须导致 undefined。而在实际pg-promise内实现 我现在使用 "123#bigint" 模式,以降低意外匹配的可能性。

所以这是最终的代码:

 function toJson(data) {
if (data !== undefined) {
return JSON.stringify(data, (_, v) => typeof v === 'bigint' ? `${v}#bigint` : v)
.replace(/"(-?\d+)#bigint"/g, (_, a) => a);
}
}

UPDATE-2

通过下面的评论,您可以通过计算与 BigInt 注入(inject)匹配的替换次数来确保安全,并在不匹配时抛出错误:

function toJson(data) {
if (data !== undefined) {
let intCount = 0, repCount = 0;
const json = JSON.stringify(data, (_, v) => {
if (typeof v === 'bigint') {
intCount++;
return `${v}#bigint`;
}
return v;
});
const res = json.replace(/"(-?\d+)#bigint"/g, (_, a) => {
repCount++;
return a;
});
if (repCount > intCount) {
// You have a string somewhere that looks like "123#bigint";
throw new Error(`BigInt serialization conflict with a string value.`);
}
return res;
}
}

虽然我个人认为这是一种矫枉过正,UPDATE-1 中的方法已经足够好了。

关于node.js - JSON stringify 和 PostgreSQL bigint 合规性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58249954/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com