用于AWS AppSync中SQL查询的Stringify JSON对象

时间:2020-06-22 15:50:52

标签: graphql velocity aws-appsync

问题:如何在Appsync速度模板中为SQL语句字符串化JSON对象?

说明:我有一个Aurora RDS表,该表的列的数据类型为JSON。 AppSync API已连接到RDS。 我的GraphQL模式看起来像

input CreateServiceCatalogItemInput {
    serviceName: String!
    serviceConfig: ServiceConfigInput!
}

type Mutation {
    createServiceCatalogItem(input: CreateServiceCatalogItemInput!): ServiceCatalogItem
}

type Query {
    getAllServiceCatalogItem: [ServiceCatalogItem]
}

type ServiceCatalogItem {
    serviceId: ID!
    serviceName: String!
    serviceConfig: ServiceConfig!
}

type ServiceConfig {
    connectionType: String
    capacity: Int
}

input ServiceConfigInput {
    connectionType: String
    capacity: Int
}

schema {
    query: Query
    mutation: Mutation
}

我的createServiceCatalogItem突变解析器看起来像

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toString($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

这引发了我错误:

对com.amazonaws.deepdish.transform.util.TransformUtils类中的方法'toString'的调用引发了异常java.lang.IllegalArgumentException:...处的参数数量错误

如果我这样做:

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.toJson($ctx.args.input.serviceConfig)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

这引发了我错误:

无法解析JSON文档:'意外字符('c'(代码99)):期望逗号分隔... \

如果我这样做:

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$ctx.args.input.serviceConfig') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

然后我得到了有意义的错误:

RDSHttp:{“ message”:“错误:类型json的输入语法无效\ n详细信息:令牌\” connectionType \“无效。\ n位置:222 \ n其中:JSON数据,第1行: {connectionType ...“}

但是,当我在解析器中对JSON进行硬编码时,它会起作用:

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"ftth\",\"capacity\":1}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

那么如何将{connectionType = ftth,容量= 1}转换为{“ connectionType”:“ ftth”,“ capacity”:1}?我在做错什么还是我错过了什么?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

您可以像这样构建一个JSON变量:

#set($json = $util.toJson({
  "connectionType": "$ctx.args.input.serviceConfig.connectionType",
  "capacity": $ctx.args.input.serviceConfig.capacity
  }))

并在查询中插入

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($json)' RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

由于所有引号和转义符,上述内容颇具挑战性,但我认为使用escapeJavaScript可以解决问题。

或直接:

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '{\"connectionType\":\"$ctx.args.input.serviceConfig.connectionType\",\"capacity\": $ctx.args.input.serviceConfig.capacity}') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

答案 1 :(得分:0)

解决方案1 ​​

感谢@cyberwombat,我得以解决此问题。如果有人需要,我会将其发布为参考。

我的serviceConfig对象不是固定的,并且可能会随着时间而变化,因此我修改了解析器以使其更通用,看起来像这样:

#set($serviceConfigMap = {})

#foreach($key in $ctx.args.input.serviceConfig.keySet())
    $util.qr($serviceConfigMap.put("$key", $ctx.args.input.serviceConfig.get($key)))
#end

#set($serviceConfigMap = $util.toJson($serviceConfigMap))

{
    "version": "2018-05-29",
    "statements": [
        "INSERT INTO b2b_service_catalog(service_name, service_config) VALUES ('$ctx.args.input.serviceName', '$util.escapeJavaScript($serviceConfigMap)') RETURNING service_id AS \"serviceId\", service_name AS \"serviceName\", service_config AS \"serviceConfig\"",
    ]
}

旧解决方案

这是我以前解决此问题的方式。

我将解析器转换为Pipeline,并在NodeJS中创建了一个简单的Lambda函数以对JSON对象进行字符串化。这就是我的lambda函数的样子:

exports.handler = (event, context, callback) => {

    const response = {
        statusCode: 200,
        body: JSON.stringify(event.input.serviceConfig).replace(/\"/g, '\\\"'),
    };
    callback(null, response)
};

这是serviceConfig现在的样子以及我想要的样子:

{\"connectionType\":\"ftth\",\"maxUploadCapacity\":1}"

我现在可以在解析器中的SQL语句中轻松使用它。