From fffe530041e06ada2205678076dcfe9f4f2185a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl?= Date: Mon, 26 Feb 2024 23:13:07 +0300 Subject: [PATCH] feat(deno/sdk): native function embedding in typescript (#598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for function or lambda definition typescript sdk for `deno.func` similarly to how `python.from_def` in python sdk works. #### Motivation and context Providing a string is a bit impractical and counter-intuitive espcially when the sdk language matches with runtime's language. #### Migration notes No changes needed. ### Checklist - [x] The change come with new or modified tests - [ ] Hard-to-understand functions have explanatory comments - [ ] End-user documentation is updated to reflect the change --------- Signed-off-by: Michaël --- typegate/tests/runtimes/deno/deno_static.ts | 21 ------------ typegate/tests/runtimes/deno/deno_test.ts | 22 ++++++++++--- .../tests/runtimes/deno/deno_typescript.ts | 31 ++++++++++++++++++ typegraph/node/sdk/src/runtimes/deno.ts | 32 ++++++++++++++++--- website/static/specs/0.0.3.json | 26 +++++++++++++++ 5 files changed, 102 insertions(+), 30 deletions(-) delete mode 100644 typegate/tests/runtimes/deno/deno_static.ts create mode 100644 typegate/tests/runtimes/deno/deno_typescript.ts diff --git a/typegate/tests/runtimes/deno/deno_static.ts b/typegate/tests/runtimes/deno/deno_static.ts deleted file mode 100644 index 22c81a7ee..000000000 --- a/typegate/tests/runtimes/deno/deno_static.ts +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright Metatype OÜ, licensed under the Elastic License 2.0. -// SPDX-License-Identifier: Elastic-2.0 - -import { Policy, t, typegraph } from "@typegraph/sdk/index.js"; -import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js"; - -typegraph("test-deno-static", (g: any) => { - const deno = new DenoRuntime(); - const pub = Policy.public(); - - g.expose({ - simpleStatic: deno.static( - t.either([t.string(), t.integer()]), - "One!", - ).withPolicy(pub), - structStatic: deno.static(t.struct({ "a": t.string() }), { - a: "Hello World", - }) - .withPolicy(pub), - }); -}); diff --git a/typegate/tests/runtimes/deno/deno_test.ts b/typegate/tests/runtimes/deno/deno_test.ts index c27f3b30a..ad365139a 100644 --- a/typegate/tests/runtimes/deno/deno_test.ts +++ b/typegate/tests/runtimes/deno/deno_test.ts @@ -122,22 +122,34 @@ Meta.test("Deno runtime: use local imports", async (t) => { }); Meta.test("Deno runtime with typescript", async (t) => { - const e = await t.engine("runtimes/deno/deno_static.ts"); + const e = await t.engine("runtimes/deno/deno_typescript.ts"); await t.should("work with static values", async () => { await gql` query { - simpleStatic - structStatic { + static { a } } `.expectData({ - simpleStatic: "One!", - structStatic: { + static: { a: "Hello World", }, }).on(e); }); + + await t.should("work with native tyepscript code", async () => { + await gql` + query { + hello(name: "World") + helloFn(name: "wOrLd") + } + ` + .expectData({ + hello: "Hello World", + helloFn: "Hello world", + }) + .on(e); + }); }); Meta.test("Deno runtime: file name reloading", async (t) => { diff --git a/typegate/tests/runtimes/deno/deno_typescript.ts b/typegate/tests/runtimes/deno/deno_typescript.ts new file mode 100644 index 000000000..20815d20f --- /dev/null +++ b/typegate/tests/runtimes/deno/deno_typescript.ts @@ -0,0 +1,31 @@ +// Copyright Metatype OÜ, licensed under the Elastic License 2.0. +// SPDX-License-Identifier: Elastic-2.0 + +import { Policy, t, typegraph } from "@typegraph/sdk/index.js"; +import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js"; + +const hello = ({ name }: any) => `Hello ${name}`; +function helloFn({ name }: any) { + return `Hello ${(name as string).toLowerCase()}`; +} + +typegraph("test-deno-tyepscript", (g: any) => { + const deno = new DenoRuntime(); + const pub = Policy.public(); + + g.expose({ + static: deno.static(t.struct({ a: t.string() }), { + a: "Hello World", + }).withPolicy(pub), + hello: deno.func( + t.struct({ name: t.string() }), + t.string(), + { code: hello }, + ).withPolicy(pub), + helloFn: deno.func( + t.struct({ name: t.string() }), + t.string(), + { code: helloFn }, + ).withPolicy(pub), + }); +}); diff --git a/typegraph/node/sdk/src/runtimes/deno.ts b/typegraph/node/sdk/src/runtimes/deno.ts index 5a784fdc6..c9dafe371 100644 --- a/typegraph/node/sdk/src/runtimes/deno.ts +++ b/typegraph/node/sdk/src/runtimes/deno.ts @@ -26,7 +26,7 @@ interface PredefinedFuncMat extends Materializer { } export interface DenoFunc { - code: string; + code: string | Function; secrets?: Array; effect?: Effect; } @@ -38,6 +38,26 @@ export interface DenoImport { effect?: Effect; } +function stringifyFn(code: string | Function) { + if (typeof code == "function") { + const source = code.toString(); + const namedFnMatch = source.match(/function\s*(\*?\s*[a-zA-Z0-9_]+)/); + if (namedFnMatch) { + const [, name] = namedFnMatch; + if (name.replace(/\s/g, "").startsWith("*")) { + throw new Error(`Generator function "${name}" not supported`); + } + if (/function\s[a-zA-Z0-9_]+\(\) { \[native code\] }/.test(source)) { + throw new Error( + `"${name}" is not supported as it is a native function`, + ); + } + } + return source; + } + return code; +} + export class DenoRuntime extends Runtime { constructor() { super(runtimes.getDenoRuntime()); @@ -51,10 +71,11 @@ export class DenoRuntime extends Runtime { out: O, { code, secrets = [], effect = fx.read() }: DenoFunc, ): t.Func { - const matId = runtimes.registerDenoFunc({ code, secrets }, effect); + const source = stringifyFn(code); + const matId = runtimes.registerDenoFunc({ code: source, secrets }, effect); const mat: FunMat = { _id: matId, - code, + code: source, secrets, effect, }; @@ -123,7 +144,10 @@ export class DenoRuntime extends Runtime { return Policy.create( name, - runtimes.registerDenoFunc(params, fx.read()), + runtimes.registerDenoFunc( + { ...params, code: stringifyFn(params.code) }, + fx.read(), + ), ); } diff --git a/website/static/specs/0.0.3.json b/website/static/specs/0.0.3.json index 845a327ca..26c2c3fb7 100644 --- a/website/static/specs/0.0.3.json +++ b/website/static/specs/0.0.3.json @@ -1241,6 +1241,24 @@ "$ref": "#/definitions/InjectionData_for_String" } } + }, + { + "type": "object", + "required": [ + "data", + "source" + ], + "properties": { + "source": { + "type": "string", + "enum": [ + "random" + ] + }, + "data": { + "$ref": "#/definitions/InjectionData_for_String" + } + } } ] }, @@ -2363,6 +2381,14 @@ }, "version": { "type": "string" + }, + "random_seed": { + "type": [ + "integer", + "null" + ], + "format": "uint32", + "minimum": 0.0 } } },