From e2141a35cd7922418c3b14178bb348094800384f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Pallar=C3=A9s?= Date: Tue, 3 Jun 2025 18:05:37 +0200 Subject: [PATCH 1/3] Fix `rds.toJsonObject` method only supporting string values Currently, the `toJsonObject` method from `rds` only supports `{ stringValue: string }`, but other value types can appear in payloads, such as `{ longValue: int }`. This PR changes it so it assumes value types of any kind, as long as the value type is an object with a key and the value we want to map. --- __tests__/resolvers.test.js | 21 +++++++++++++++++++++ rds/index.js | 7 +++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/__tests__/resolvers.test.js b/__tests__/resolvers.test.js index 1eb5ee2..bfe2a2f 100644 --- a/__tests__/resolvers.test.js +++ b/__tests__/resolvers.test.js @@ -242,6 +242,9 @@ describe("rds resolvers", () => { "numberOfRecordsUpdated": 0, "records": [ [ + { + "longValue": 12345 + }, { "stringValue": "Mark Twain" }, @@ -253,6 +256,9 @@ describe("rds resolvers", () => { } ], [ + { + "longValue": 67890 + }, { "stringValue": "Jack London" }, @@ -265,6 +271,21 @@ describe("rds resolvers", () => { ] ], "columnMetadata": [ + { + "type": 4, + "typeName": "serial", + "label": "id", + "schemaName": "", + "tableName": "Books", + "isAutoIncrement": true, + "isSigned": true, + "isCurrency": false, + "isCaseSensitive": false, + "nullable": 0, + "precision": 10, + "scale": 0, + "arrayBaseColumnType": 0 + }, { "isSigned": false, "isCurrency": false, diff --git a/rds/index.js b/rds/index.js index fa91fc3..9ddb850 100644 --- a/rds/index.js +++ b/rds/index.js @@ -20,12 +20,11 @@ export function toJsonObject(inputStr) { } for (const colNo in record) { - - // TODO: what if the column is not a string? - const { stringValue } = record[colNo]; const { label } = columnMetadata[colNo]; - row[label] = stringValue; + // We assume that the record is a simple object with a single key-value pair. + // For example, `{ longValue: 1 }` or `{ stringValue: "Acme Corp" }`. + row[label] = Object.values(record[colNo])[0]; } statement.push(row); From f21dbe493171ad969d657c014a555020ac94cc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Pallar=C3=A9s?= Date: Wed, 4 Jun 2025 10:02:31 +0200 Subject: [PATCH 2/3] update snapshot --- __tests__/__snapshots__/resolvers.test.js.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/__tests__/__snapshots__/resolvers.test.js.snap b/__tests__/__snapshots__/resolvers.test.js.snap index 16b5f4b..86f18c8 100644 --- a/__tests__/__snapshots__/resolvers.test.js.snap +++ b/__tests__/__snapshots__/resolvers.test.js.snap @@ -248,11 +248,13 @@ exports[`rds resolvers toJsonObject 1`] = ` { "ISBN-13": "978-1948132817", "author": "Mark Twain", + "id": 12345, "title": "Adventures of Huckleberry Finn", }, { "ISBN-13": "978-1948132275", "author": "Jack London", + "id": 67890, "title": "The Call of the Wild", }, ], From 8e516082e99dbfaa18bcc3baf0eb838df398a76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Pallar=C3=A9s?= Date: Wed, 4 Jun 2025 11:21:49 +0200 Subject: [PATCH 3/3] support more data types, and handle names and labels --- .../__snapshots__/resolvers.test.js.snap | 26 ++++++++++++ __tests__/resolvers.test.js | 39 +++++++++++++++-- rds/index.js | 42 ++++++++++++++++--- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/__tests__/__snapshots__/resolvers.test.js.snap b/__tests__/__snapshots__/resolvers.test.js.snap index 86f18c8..3163981 100644 --- a/__tests__/__snapshots__/resolvers.test.js.snap +++ b/__tests__/__snapshots__/resolvers.test.js.snap @@ -246,15 +246,41 @@ exports[`rds resolvers toJsonObject 1`] = ` [ [ { + "IS ACTIVE": true, "ISBN-13": "978-1948132817", "author": "Mark Twain", + "blob_value": "aGVsbG8=", "id": 12345, + "tags": [ + "a", + "b", + ], "title": "Adventures of Huckleberry Finn", }, { + "IS ACTIVE": false, "ISBN-13": "978-1948132275", "author": "Jack London", + "blob_value": "d29ybGQ=", "id": 67890, + "optional_double": 12.34, + "tags": [ + [ + true, + false, + ], + [ + 1.234, + ], + [ + 1, + 2, + ], + [ + "a", + "b", + ], + ], "title": "The Call of the Wild", }, ], diff --git a/__tests__/resolvers.test.js b/__tests__/resolvers.test.js index bfe2a2f..907f79f 100644 --- a/__tests__/resolvers.test.js +++ b/__tests__/resolvers.test.js @@ -253,7 +253,13 @@ describe("rds resolvers", () => { }, { "stringValue": "978-1948132817" - } + }, + { + "isNull": true + }, + { "arrayValue": { "stringValues": ["a", "b"] } }, + { "booleanValue": true }, + { "blobValue": Buffer.from("hello").toString("base64") } ], [ { @@ -267,7 +273,21 @@ describe("rds resolvers", () => { }, { "stringValue": "978-1948132275" - } + }, + { + "doubleValue": 12.34, + }, + { "arrayValue": { + "arrayValues": [ + { "booleanValues": [true, false] }, + { "doubleValues": [1.234] }, + { "longValues": [1, 2] }, + { "stringValues": ["a", "b"] }, + ], + }, + }, + { "booleanValue": false }, + { "blobValue": Buffer.from("world").toString("base64") }, ] ], "columnMetadata": [ @@ -333,7 +353,20 @@ describe("rds resolvers", () => { "nullable": 0, "arrayBaseColumnType": 0, "name": "ISBN-13" - } + }, + { + "name": "optional_double", + }, + { + "name": "tags", + }, + { + "name": "is_active", + "label": "IS ACTIVE", + }, + { + "name": "blob_value", + }, ] } ] diff --git a/rds/index.js b/rds/index.js index 9ddb850..e452757 100644 --- a/rds/index.js +++ b/rds/index.js @@ -1,3 +1,31 @@ +/** + * Extract the value from the field given a row from sqlStatementResults. + * + * See https://docs.aws.amazon.com/rdsdataservice/latest/APIReference/API_Field.html. + */ +function extractFieldValue(field) { + // Handle isNull. + if (field.isNull === true) { + return null; + } + + // Handle arrayValue. + if ('arrayValue' in field) { + const { arrayValue } = field; + + // Handle arrayValues. + if (arrayValue.arrayValues) { + return arrayValue.arrayValues.map(field => extractFieldValue(field)); + } + + // Handle stringValues, doubleValues, longValues and booleanValues. + return Object.values(arrayValue)[0] ?? []; + } + + // Handle stringValue, doubleValue, longValue, booleanValue and blobValue. + return Object.values(field)[0]; +} + export function toJsonObject(inputStr) { // on AWS inputStr is always a string, but on LocalStack the input may be an object. let input; @@ -20,11 +48,15 @@ export function toJsonObject(inputStr) { } for (const colNo in record) { - const { label } = columnMetadata[colNo]; - - // We assume that the record is a simple object with a single key-value pair. - // For example, `{ longValue: 1 }` or `{ stringValue: "Acme Corp" }`. - row[label] = Object.values(record[colNo])[0]; + // Use label if available, otherwise use name. + const metadata = columnMetadata[colNo]; + const colName = metadata.label ?? metadata.name; + + // Extract the value from the field. + const value = extractFieldValue(record[colNo]); + if (value !== null) { + row[colName] = value; + } } statement.push(row);