From 7e526eb5176261d7220ed2745e646c5b6e1c2686 Mon Sep 17 00:00:00 2001 From: Radu Gruia Date: Mon, 20 Jan 2025 14:14:40 +0000 Subject: [PATCH] test: another integration test --- .../duration/functions/writeAndDuplicate.ts | 14 +++++++++++ integration/testdata/duration/schema.keel | 7 ++++++ integration/testdata/duration/tests.test.ts | 23 ++++++++++++++++++- .../functions-runtime/src/camelCasePlugin.js | 4 +++- packages/functions-runtime/src/database.js | 5 ++-- 5 files changed, 48 insertions(+), 5 deletions(-) create mode 100755 integration/testdata/duration/functions/writeAndDuplicate.ts diff --git a/integration/testdata/duration/functions/writeAndDuplicate.ts b/integration/testdata/duration/functions/writeAndDuplicate.ts new file mode 100755 index 000000000..feee9426a --- /dev/null +++ b/integration/testdata/duration/functions/writeAndDuplicate.ts @@ -0,0 +1,14 @@ +import { WriteAndDuplicate, models, Duration } from "@teamkeel/sdk"; + +// To learn more about what you can do with custom functions, visit https://docs.keel.so/functions +export default WriteAndDuplicate(async (ctx, inputs) => { + const mod = await models.myDuration.create({ dur: inputs.dur }); + const duplicate = await models.myDuration.create({ + dur: Duration.fromISOString("PT1H"), + }); + + return { + model: mod, + duplicate: duplicate, + }; +}); diff --git a/integration/testdata/duration/schema.keel b/integration/testdata/duration/schema.keel index d03667249..46c201594 100644 --- a/integration/testdata/duration/schema.keel +++ b/integration/testdata/duration/schema.keel @@ -13,6 +13,9 @@ model MyDuration { write writeCustomFunction(DurationMessage) returns (ModelMessage) { @permission(expression: true) } + write writeAndDuplicate(DurationMessage) returns (DuplicateModelMessage) { + @permission(expression: true) + } } @permission(expression: true, actions: [get, list, create, update]) @@ -29,3 +32,7 @@ message DurationMessage { message ModelMessage { model MyDuration } +message DuplicateModelMessage { + model MyDuration + duplicate MyDuration +} diff --git a/integration/testdata/duration/tests.test.ts b/integration/testdata/duration/tests.test.ts index f75a99ab4..480bcfffb 100644 --- a/integration/testdata/duration/tests.test.ts +++ b/integration/testdata/duration/tests.test.ts @@ -47,7 +47,7 @@ test("duration - write custom function", async () => { expect(mydurs[0].dur?.toISOString()).toEqual("PT1H2M3S"); }); -test("durs - create and store duration in hook", async () => { +test("duration - create and store duration in hook", async () => { await actions.createDurationInHook({}); const mydurs = await useDatabase() @@ -58,3 +58,24 @@ test("durs - create and store duration in hook", async () => { expect(mydurs.length).toEqual(1); expect(mydurs[0].dur?.toISOString()).toEqual("PT1H"); }); + +test("duration - write two in custom function", async () => { + // write and duplicate will create two models, one with the input and one with PT1H + const result = await actions.writeAndDuplicate({ + dur: Duration.fromISOString("PT1H2M3S"), + }); + + expect(result.model.dur).toEqual("PT1H2M3S"); + expect(result.duplicate.dur).toEqual("PT1H"); + + const mydurs = await useDatabase() + .selectFrom("my_duration") + .selectAll() + .execute(); + + expect(mydurs.length).toEqual(2); + expect(mydurs[0].id).toEqual(result.model.id); + expect(mydurs[0].dur?.toISOString()).toEqual("PT1H2M3S"); + expect(mydurs[1].id).toEqual(result.duplicate.id); + expect(mydurs[1].dur?.toISOString()).toEqual("PT1H"); +}); diff --git a/packages/functions-runtime/src/camelCasePlugin.js b/packages/functions-runtime/src/camelCasePlugin.js index f13e297b4..44ab8652d 100644 --- a/packages/functions-runtime/src/camelCasePlugin.js +++ b/packages/functions-runtime/src/camelCasePlugin.js @@ -1,7 +1,9 @@ const { CamelCasePlugin } = require("kysely"); const { isPlainObject, isRichType } = require("./type-utils"); -// KeelCamelCasePlugin is a wrapper around kysely's camel case plugin. +// KeelCamelCasePlugin is a wrapper around kysely's CamelCasePlugin. The behaviour is the same apart from the fact that +// nested objects that are of a rich keel data type, such as Duration, are skipped so that they continue to be +// implementations of the rich data classes defined by Keel. class KeelCamelCasePlugin { constructor(opt) { this.opt = opt; diff --git a/packages/functions-runtime/src/database.js b/packages/functions-runtime/src/database.js index 85825564f..833649b86 100644 --- a/packages/functions-runtime/src/database.js +++ b/packages/functions-runtime/src/database.js @@ -76,9 +76,8 @@ function createDatabaseClient({ connString } = {}) { new AuditContextPlugin(), // allows users to query using camelCased versions of the database column names, which // should match the names we use in our schema. - // https://kysely-org.github.io/kysely/classes/CamelCasePlugin.html - // If they don't, then we can create a custom implementation of the plugin where we control - // the casing behaviour (see url above for example) + // We're using an extended version of Kysely's CamelCasePlugin which avoids changing keys of objects that represent + // rich data formats, specific to Keel (e.g. Duration) new KeelCamelCasePlugin(), ], log(event) {