From 887362539fbb261e72f6fe09c08b436d734024a6 Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Mon, 15 Apr 2024 11:53:50 +0100 Subject: [PATCH 1/3] Fix promise check for null values --- ndc-lambda-sdk/src/execution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndc-lambda-sdk/src/execution.ts b/ndc-lambda-sdk/src/execution.ts index b0827a1..7ea78b8 100644 --- a/ndc-lambda-sdk/src/execution.ts +++ b/ndc-lambda-sdk/src/execution.ts @@ -172,7 +172,7 @@ async function invokeFunction(func: Function, preparedArgs: unknown[], functionN return await withActiveSpan(tracer, `Function: ${functionName}`, async () => { const result = func.apply(undefined, preparedArgs); // Await the result if it is a promise - if (typeof result === "object" && 'then' in result && typeof result.then === "function") { + if (result && typeof result === "object" && 'then' in result && typeof result.then === "function") { return await result; } return result; From 522a9f53c07666a7cb41f256dbaa652b21a0d0dc Mon Sep 17 00:00:00 2001 From: Daniel Chambers Date: Tue, 16 Apr 2024 12:06:16 +1000 Subject: [PATCH 2/3] Removed any type usage and added tests --- ndc-lambda-sdk/src/execution.ts | 6 +- .../test/execution/execute-query.test.ts | 84 ++++++++++++++++++- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/ndc-lambda-sdk/src/execution.ts b/ndc-lambda-sdk/src/execution.ts index 7ea78b8..c3e2964 100644 --- a/ndc-lambda-sdk/src/execution.ts +++ b/ndc-lambda-sdk/src/execution.ts @@ -170,10 +170,10 @@ function coerceArgumentValue(value: unknown, type: schema.TypeReference, valuePa async function invokeFunction(func: Function, preparedArgs: unknown[], functionName: string): Promise { try { return await withActiveSpan(tracer, `Function: ${functionName}`, async () => { - const result = func.apply(undefined, preparedArgs); + const result: unknown = func.apply(undefined, preparedArgs); // Await the result if it is a promise - if (result && typeof result === "object" && 'then' in result && typeof result.then === "function") { - return await result; + if (result !== null && typeof result === "object" && "then" in result && typeof result.then === "function") { + return await (result as PromiseLike); } return result; }, { [FUNCTION_NAME_SPAN_ATTR_NAME]: functionName }); diff --git a/ndc-lambda-sdk/test/execution/execute-query.test.ts b/ndc-lambda-sdk/test/execution/execute-query.test.ts index 077fb6a..569a2b6 100644 --- a/ndc-lambda-sdk/test/execution/execute-query.test.ts +++ b/ndc-lambda-sdk/test/execution/execute-query.test.ts @@ -2,7 +2,7 @@ import { describe, it } from "mocha"; import { assert, expect } from "chai"; import * as sdk from "@hasura/ndc-sdk-typescript" import { executeQuery } from "../../src/execution"; -import { FunctionNdcKind, FunctionsSchema } from "../../src/schema"; +import { FunctionNdcKind, FunctionsSchema, NullOrUndefinability } from "../../src/schema"; import { sleep } from "../../src/util"; describe("execute query", function() { @@ -389,9 +389,13 @@ describe("execute query", function() { parallelDegree: null, arguments: [], resultType: { - type: "named", - kind: "scalar", - name: "String" + type: "nullable", + nullOrUndefinability: NullOrUndefinability.AcceptsNullOnly, + underlyingType: { + type: "named", + kind: "scalar", + name: "String" + } } } }, @@ -493,5 +497,77 @@ describe("execute query", function() { ]); assert.equal(functionCallCount, 1); }); + + it("function can return null", async function() { + let functionCallCount = 0; + const runtimeFunctions = { + "theFunction": () => { + functionCallCount++; + return null; + } + }; + const queryRequest: sdk.QueryRequest = { + collection: "theFunction", + query: { + fields: { + "__value": { + type: "column", + column: "__value" + } + } + }, + arguments: {}, + collection_relationships: {} + }; + + const result = await executeQuery(queryRequest, functionSchema, runtimeFunctions); + assert.deepStrictEqual(result, [ + { + aggregates: null, + rows: [ + { + "__value": null, + } + ] + } + ]); + assert.equal(functionCallCount, 1); + }); + + it("async function can return null", async function() { + let functionCallCount = 0; + const runtimeFunctions = { + "theFunction": async () => { + functionCallCount++; + return null; + } + }; + const queryRequest: sdk.QueryRequest = { + collection: "theFunction", + query: { + fields: { + "__value": { + type: "column", + column: "__value" + } + } + }, + arguments: {}, + collection_relationships: {} + }; + + const result = await executeQuery(queryRequest, functionSchema, runtimeFunctions); + assert.deepStrictEqual(result, [ + { + aggregates: null, + rows: [ + { + "__value": null, + } + ] + } + ]); + assert.equal(functionCallCount, 1); + }); }); }); From 92a1a1fb092afcc9443d88a543988adeb8fc16c9 Mon Sep 17 00:00:00 2001 From: Daniel Chambers Date: Tue, 16 Apr 2024 12:07:33 +1000 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29d4bc6..ec36db3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Changes to be included in the next upcoming release - Support for NDC Spec v0.1.2 via the NDC TypeScript SDK v4.4.0 ([#29](https://github.com/hasura/ndc-nodejs-lambda/pull/29)). - Built-in scalar types that support equality now define it in the NDC schema. - Built-in scalar types now have an explicit type representation defined in the NDC schema. +- Fixed functions that return null causing crashes ([#31](https://github.com/hasura/ndc-nodejs-lambda/pull/31)) ## [1.2.0] - 2024-03-18 - Improved error messages when unsupported enum types or unions of literal types are found, and allow these types to be used in relaxed types mode ([#17](https://github.com/hasura/ndc-nodejs-lambda/pull/17))