【问题标题】:How can I merge 2 dot notation strings to a GraphQL query string如何将 2 个点表示法字符串合并到 GraphQL 查询字符串
【发布时间】:2018-05-22 03:31:07
【问题描述】:

我正在尝试将 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 出现在结果中。

我尝试创建代表结构的临时对象,但效果不佳。

【问题讨论】:

    标签: javascript graphql graphql-js


    【解决方案1】:

    修改后的答案

    根据您修改后的问题和要求,这里有一个修改后的答案。这将从嵌套的点符号递归构建一个对象,然后利用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 }"
    

    【讨论】:

    • 谢谢,这看起来非常接近我正在寻找的解决方案,但是在更新我的问题之后(我只是这样做了,你可能没有看到它)。如果我使用问题中提供的参数列表运行 buildQuery,答案在常规字符串 lastName { }, billing { address, address } 上有一些额外的花括号,您可以看到 lastName 不应该有 { }
    • 我已经更新了我的答案。可能可以稍微改进一下代码,但它似乎可以工作。
    • 非常感谢,只是一件小事,当我尝试使用 jsbin 时,它会在 args.forEach 上抛出一个错误,在将扩展运算符添加到 args (...args) 后它就消失了。你介意更新你的答案吗?
    • 啊,是的,对不起。当我看到您改为传递参数数组并且没有更新函数调用时,我删除了传播。我看到你的弦实际上有三层深。目前这只适用于两个级别,因此需要递归。
    • 哦,我刚刚看到你关于 2 层深度的评论,让它递归有多难?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2019-07-13
    相关资源
    最近更新 更多