如何将 2 个点符号字符串合并到 GraphQL 查询字符串
How can I merge 2 dot notation strings to a GraphQL query string
我正在尝试将 2 个点符号字符串合并到一个只有 javascript(可以是 ES6/typescript)的 GrahQL 查询中。
例如,假设我有一个字符串数组
[
'firstName',
'lastName',
'billing.address.street',
'billing.address.zip',
'shipping.address.street',
'shipping.address.zip'
]
预期的查询字符串输出为(空格不重要)
firstName, lastName, shipping{address{street, zip}}, billing{address{street, zip }}
我可以将点符号 1 乘 1 转换为查询字符串,但如何将所有这些合并在一起?我得到了一个接受 street.name
并输出 street { name }
的函数。所以这个函数就可以了
convertToString(inputString) {
let result = '';
if (inputString.indexOf('.') === -1) {
result = inputString;
} else {
const inputArray = inputString.split('.');
for (let i = inputArray.length - 1; i >= 0; i--) {
if (i === 0) {
result = inputArray[i] + result;
} else {
result = '{' + inputArray[i] + result + '}';
}
}
}
return result;
}
console.log(convertToString('address.street')); // address { street }
但是我将如何遍历所有字符串并仅获得 1 个将相同属性组合到一个组中的 GraphQL 查询字符串。主要问题是如何在不丢失任何内容且不重复的情况下合并 2 点符号字符串(此时,我可以得到这个 address { name } address { zip }
但是当它在 GraphQL 服务器上运行时,只保留后者,所以只有 zip
出现在结果中。
我尝试创建代表结构的临时对象,但效果并不理想。
修改后的答案
根据您修改后的问题和要求,这里是修改后的答案。这将从嵌套的点符号递归构建一个对象,然后利用 JSON.stringify
构建查询字符串(使用一些字符串操作);
function buildQuery(...args) {
const set = (o = {}, a) => {
const k = a.shift();
o[k] = a.length ? set(o[k], a) : null;
return o;
}
const o = args.reduce((o, a) => set(o, a.split('.')), {});
return JSON.stringify(o)
.replace(/\"|\:|null/g, '')
.replace(/^\{/, '')
.replace(/\}$/, '');
}
const query = buildQuery(
'firstName',
'lastName',
'billing.address.street',
'billing.address.zip',
'shipping.address.street',
'shipping.address.zip'
);
console.log(query);
原答案
我建议先将单个点符号字符串转换为对象,然后再将对象转换为字符串。
function buildQuery(...args) {
let q = {};
args.forEach((arg) => {
const [ o, a ] = arg.split('.');
q[o] = q[o] || [];
if (a) q[o] = q[o].concat(a);
});
return Object.keys(q).map((k) => {
return q[k].length ? `${k} \{ ${q[k].join(', ')} \}` : k;
}).join(', ');
}
const query = buildQuery('person.name', 'person.email', 'street.name', 'street.zip');
console.log(query);
// "person { name, email }, street { name, zip }"
我正在尝试将 2 个点符号字符串合并到一个只有 javascript(可以是 ES6/typescript)的 GrahQL 查询中。
例如,假设我有一个字符串数组
[
'firstName',
'lastName',
'billing.address.street',
'billing.address.zip',
'shipping.address.street',
'shipping.address.zip'
]
预期的查询字符串输出为(空格不重要)
firstName, lastName, shipping{address{street, zip}}, billing{address{street, zip }}
我可以将点符号 1 乘 1 转换为查询字符串,但如何将所有这些合并在一起?我得到了一个接受 street.name
并输出 street { name }
的函数。所以这个函数就可以了
convertToString(inputString) {
let result = '';
if (inputString.indexOf('.') === -1) {
result = inputString;
} else {
const inputArray = inputString.split('.');
for (let i = inputArray.length - 1; i >= 0; i--) {
if (i === 0) {
result = inputArray[i] + result;
} else {
result = '{' + inputArray[i] + result + '}';
}
}
}
return result;
}
console.log(convertToString('address.street')); // address { street }
但是我将如何遍历所有字符串并仅获得 1 个将相同属性组合到一个组中的 GraphQL 查询字符串。主要问题是如何在不丢失任何内容且不重复的情况下合并 2 点符号字符串(此时,我可以得到这个 address { name } address { zip }
但是当它在 GraphQL 服务器上运行时,只保留后者,所以只有 zip
出现在结果中。
我尝试创建代表结构的临时对象,但效果并不理想。
修改后的答案
根据您修改后的问题和要求,这里是修改后的答案。这将从嵌套的点符号递归构建一个对象,然后利用 JSON.stringify
构建查询字符串(使用一些字符串操作);
function buildQuery(...args) {
const set = (o = {}, a) => {
const k = a.shift();
o[k] = a.length ? set(o[k], a) : null;
return o;
}
const o = args.reduce((o, a) => set(o, a.split('.')), {});
return JSON.stringify(o)
.replace(/\"|\:|null/g, '')
.replace(/^\{/, '')
.replace(/\}$/, '');
}
const query = buildQuery(
'firstName',
'lastName',
'billing.address.street',
'billing.address.zip',
'shipping.address.street',
'shipping.address.zip'
);
console.log(query);
原答案
我建议先将单个点符号字符串转换为对象,然后再将对象转换为字符串。
function buildQuery(...args) {
let q = {};
args.forEach((arg) => {
const [ o, a ] = arg.split('.');
q[o] = q[o] || [];
if (a) q[o] = q[o].concat(a);
});
return Object.keys(q).map((k) => {
return q[k].length ? `${k} \{ ${q[k].join(', ')} \}` : k;
}).join(', ');
}
const query = buildQuery('person.name', 'person.email', 'street.name', 'street.zip');
console.log(query);
// "person { name, email }, street { name, zip }"