From 817792cbadc1bdc84fd7a5d5069244a8f0cf1715 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 13:19:56 -0400 Subject: [PATCH 01/20] Add Node types for `assert` --- packages/generate/package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/generate/package.json b/packages/generate/package.json index bc6f5e1fc..63501a8e2 100644 --- a/packages/generate/package.json +++ b/packages/generate/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@types/jest": "^29.5.1", + "@types/node": "^20.1.7", "conditional-type-checks": "^1.0.5", "edgedb": "^1.1.0", "esbuild": "^0.15.7", diff --git a/yarn.lock b/yarn.lock index 10ad6f402..dd00d48c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -878,6 +878,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.0.tgz#4668bc392bb6938637b47e98b1f2ed5426f33316" integrity sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ== +"@types/node@^20.1.7": + version "20.1.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.7.tgz#ce10c802f7731909d0a44ac9888e8b3a9125eb62" + integrity sha512-WCuw/o4GSwDGMoonES8rcvwsig77dGCMbZDrZr2x4ZZiNW4P/gcoZXe/0twgtobcTkmg9TuKflxYL/DuwDyJzg== + "@types/prettier@^2.1.5": version "2.7.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" From 88b93b511dbad31146a51d75150216edb5730c34 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 13:20:10 -0400 Subject: [PATCH 02/20] Perform codemod --- packages/generate/test/casts.test.ts | 15 +- packages/generate/test/cli.test.ts | 3 +- packages/generate/test/collections.test.ts | 243 ++++++++++----------- packages/generate/test/delete.test.ts | 7 +- packages/generate/test/detached.test.ts | 3 +- packages/generate/test/for.test.ts | 17 +- packages/generate/test/functions.test.ts | 46 ++-- packages/generate/test/globals.test.ts | 74 +++---- packages/generate/test/group.test.ts | 81 ++++--- packages/generate/test/insert.test.ts | 31 +-- packages/generate/test/json.test.ts | 10 +- packages/generate/test/literals.test.ts | 93 ++++---- packages/generate/test/objectTypes.test.ts | 122 +++++------ packages/generate/test/operators.test.ts | 28 +-- packages/generate/test/params.test.ts | 19 +- packages/generate/test/paths.test.ts | 67 +++--- packages/generate/test/primitives.test.ts | 55 ++--- packages/generate/test/queries.test.ts | 3 +- packages/generate/test/select.test.ts | 241 ++++++++++---------- packages/generate/test/sets.test.ts | 114 +++++----- packages/generate/test/update.test.ts | 27 ++- packages/generate/test/with.test.ts | 198 ++++++++--------- 22 files changed, 711 insertions(+), 786 deletions(-) diff --git a/packages/generate/test/casts.test.ts b/packages/generate/test/casts.test.ts index 1c0dd269a..5fbb51439 100644 --- a/packages/generate/test/casts.test.ts +++ b/packages/generate/test/casts.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import e from "../dbschema/edgeql-js"; import type { $Movie } from "../dbschema/edgeql-js/modules/default"; @@ -20,27 +21,23 @@ test("casting", () => { tc.assert< tc.IsExact<(typeof primitiveCast)["__element__"], (typeof e)["float64"]> >(true); - expect(primitiveCast.toEdgeQL()).toEqual( - `(3.14)` - ); + assert.equal(primitiveCast.toEdgeQL(), `(3.14)`); }); test("enums", async () => { - expect(e.cast(e.Genre, e.str("Horror")).toEdgeQL()).toEqual( - `("Horror")` - ); + assert.equal(e.cast(e.Genre, e.str("Horror")).toEdgeQL(), `("Horror")`); const result = await e.cast(e.Genre, e.str("Horror")).run(client); - expect(result).toEqual("Horror"); + assert.equal(result, "Horror"); }); test("scalar literals", () => { - expect(e.cast(e.json, "hello").toEdgeQL()).toEqual(`("hello")`); + assert.equal(e.cast(e.json, "hello").toEdgeQL(), `("hello")`); }); test("object type empty set", () => { const expr = e.cast(e.Movie, e.set()); - expect(expr.toEdgeQL()).toEqual(`{}`); + assert.equal(expr.toEdgeQL(), `{}`); tc.assert>(true); }); diff --git a/packages/generate/test/cli.test.ts b/packages/generate/test/cli.test.ts index 606d37c3c..06baf80f5 100644 --- a/packages/generate/test/cli.test.ts +++ b/packages/generate/test/cli.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import path from "path"; import { adapter } from "edgedb"; import { execSync } from "child_process"; @@ -9,5 +10,5 @@ test("basic generate", async () => { stdio: "inherit", }); const qbIndex = path.resolve(QBDIR, "dbschema", "edgeql-js", "index.ts"); - expect(await adapter.exists(qbIndex)).toEqual(true); + assert.equal(await adapter.exists(qbIndex), true); }, 60000); diff --git a/packages/generate/test/collections.test.ts b/packages/generate/test/collections.test.ts index bb8814e8c..a218b4ed4 100644 --- a/packages/generate/test/collections.test.ts +++ b/packages/generate/test/collections.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type { Client } from "edgedb"; import * as $ from "../src/syntax/reflection"; import e, { $infer, objectTypeToTupleType } from "../dbschema/edgeql-js"; @@ -22,51 +23,49 @@ afterAll(async () => { test("array literal", async () => { const strArrayType = e.array(e.str); - expect(strArrayType.__kind__).toEqual($.TypeKind.array); - expect(strArrayType.__element__.__kind__).toEqual($.TypeKind.scalar); - expect(strArrayType.__element__.__name__).toEqual("std::str"); + assert.deepEqual(strArrayType.__kind__, $.TypeKind.array); + assert.deepEqual(strArrayType.__element__.__kind__, $.TypeKind.scalar); + assert.equal(strArrayType.__element__.__name__, "std::str"); const arg = e.array(["asdf", e.str("qwer")]); type arg = $.setToTsType; tc.assert>(true); - expect(arg.__kind__).toEqual($.ExpressionKind.Array); - expect(arg.__element__.__kind__).toEqual($.TypeKind.array); - expect(arg.__cardinality__).toEqual($.Cardinality.One); - expect(arg.__element__.__element__.__kind__).toEqual($.TypeKind.scalar); - expect(arg.__element__.__element__.__name__).toEqual("std::str"); + assert.deepEqual(arg.__kind__, $.ExpressionKind.Array); + assert.deepEqual(arg.__element__.__kind__, $.TypeKind.array); + assert.deepEqual(arg.__cardinality__, $.Cardinality.One); + assert.deepEqual(arg.__element__.__element__.__kind__, $.TypeKind.scalar); + assert.equal(arg.__element__.__element__.__name__, "std::str"); const result = await client.querySingle(e.select(arg).toEdgeQL()); - expect(result).toEqual(["asdf", "qwer"]); + assert.deepEqual(result, ["asdf", "qwer"]); const arg1 = arg[1]; tc.assert>( true ); - expect(arg1.__kind__).toEqual($.ExpressionKind.Operator); + assert.deepEqual(arg1.__kind__, $.ExpressionKind.Operator); tc.assert>( true ); - expect(arg1.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(arg1.__cardinality__, $.Cardinality.One); tc.assert>( true ); - expect(arg1.__element__.__name__).toEqual("std::str"); - expect(await e.select(arg1).run(client)).toEqual("qwer"); + assert.equal(arg1.__element__.__name__, "std::str"); + assert.equal(await e.select(arg1).run(client), "qwer"); const multiArray = e.array(["asdf", e.set(e.str("qwer"), e.str("erty"))]); type multiArray = $.setToTsType; tc.assert>(true); - expect(multiArray.__kind__).toEqual($.ExpressionKind.Array); - expect(multiArray.__element__.__kind__).toEqual($.TypeKind.array); + assert.deepEqual(multiArray.__kind__, $.ExpressionKind.Array); + assert.deepEqual(multiArray.__element__.__kind__, $.TypeKind.array); - expect(multiArray.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(multiArray.__element__.__element__.__kind__).toEqual( - $.TypeKind.scalar - ); - expect(multiArray.__element__.__element__.__name__).toEqual("std::str"); + assert.deepEqual(multiArray.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(multiArray.__element__.__element__.__kind__, $.TypeKind.scalar); + assert.equal(multiArray.__element__.__element__.__name__, "std::str"); const multiArrayResult = await client.query(e.select(multiArray).toEdgeQL()); - expect(multiArrayResult).toEqual([ + assert.deepEqual(multiArrayResult, [ ["asdf", "qwer"], ["asdf", "erty"], ]); @@ -75,8 +74,8 @@ test("array literal", async () => { tc.assert< tc.IsExact<(typeof multi0)["__cardinality__"], $.Cardinality.AtLeastOne> >(true); - expect(multi0.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(await e.select(multi0).run(client)).toEqual(["asdf", "asdf"]); + assert.deepEqual(multi0.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await e.select(multi0).run(client), ["asdf", "asdf"]); // array slicing const arr = e.str_split(e.str("zxcvbnm"), e.str("")); @@ -105,17 +104,15 @@ test("array literal", async () => { } > >(true); - expect(JSON.stringify(sliceResult)).toEqual( - JSON.stringify({ - reverseIndex: "n", - slice24: ["c", "v"], - slice2: ["c", "v", "b", "n", "m"], - slice4: ["z", "x", "c", "v"], - reverseSlice2: ["n", "m"], - reverseSlice4: ["z", "x", "c"], - reverseSlice24: ["v", "b"], - }) - ); + assert.deepEqual(JSON.stringify(sliceResult), JSON.stringify({ + reverseIndex: "n", + slice24: ["c", "v"], + slice2: ["c", "v", "b", "n", "m"], + slice4: ["z", "x", "c", "v"], + reverseSlice2: ["n", "m"], + reverseSlice4: ["z", "x", "c"], + reverseSlice24: ["v", "b"], + })); // @ts-expect-error arr["str"]; @@ -125,28 +122,28 @@ test("array literal", async () => { test("tuple literal", async () => { const tupleType = e.tuple([e.str, e.int64]); - expect(tupleType.__kind__).toEqual($.TypeKind.tuple); - expect(tupleType.__items__[0].__kind__).toEqual($.TypeKind.scalar); - expect(tupleType.__items__[0].__name__).toEqual("std::str"); - expect(tupleType.__items__[1].__kind__).toEqual($.TypeKind.scalar); - expect(tupleType.__items__[1].__name__).toEqual("std::int64"); + assert.deepEqual(tupleType.__kind__, $.TypeKind.tuple); + assert.deepEqual(tupleType.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__items__[0].__name__, "std::str"); + assert.deepEqual(tupleType.__items__[1].__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__items__[1].__name__, "std::int64"); const myTuple = e.tuple(["asdf", 45]); type myTuple = $.setToTsType; tc.assert>(true); - expect(myTuple.__element__.__kind__).toEqual($.TypeKind.tuple); - expect(myTuple.__element__.__items__[0].__kind__).toEqual($.TypeKind.scalar); - expect(myTuple.__element__.__items__[0].__name__).toEqual("std::str"); - expect(myTuple.__element__.__items__[1].__kind__).toEqual($.TypeKind.scalar); - expect(myTuple.__element__.__items__[1].__name__).toEqual("std::number"); + assert.deepEqual(myTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual(myTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(myTuple.__element__.__items__[0].__name__, "std::str"); + assert.deepEqual(myTuple.__element__.__items__[1].__kind__, $.TypeKind.scalar); + assert.equal(myTuple.__element__.__items__[1].__name__, "std::number"); const myTupleResult = await client.querySingle(e.select(myTuple).toEdgeQL()); - expect(myTupleResult).toEqual(["asdf", 45]); + assert.deepEqual(myTupleResult, ["asdf", 45]); const myTuplePath0 = myTuple[0]; const myTuplePath1 = myTuple[1]; tc.assert, string>>(true); tc.assert, number>>(true); - expect(await e.select(myTuplePath0).run(client)).toEqual("asdf"); - expect(await e.select(myTuplePath1).run(client)).toEqual(45); + assert.equal(await e.select(myTuplePath0).run(client), "asdf"); + assert.equal(await e.select(myTuplePath1).run(client), 45); const multiTuple = e.tuple(["asdf", e.set(e.str("qwer"), e.str("erty"))]); tc.assert< @@ -155,16 +152,14 @@ test("tuple literal", async () => { [[string, string], ...[string, string][]] > >(true); - expect(multiTuple.__kind__).toEqual($.ExpressionKind.Tuple); - expect(multiTuple.__element__.__kind__).toEqual($.TypeKind.tuple); - expect(multiTuple.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(multiTuple.__element__.__items__[0].__kind__).toEqual( - $.TypeKind.scalar - ); - expect(multiTuple.__element__.__items__[0].__name__).toEqual("std::str"); - expect(multiTuple.__element__.__items__[1].__name__).toEqual("std::str"); + assert.deepEqual(multiTuple.__kind__, $.ExpressionKind.Tuple); + assert.deepEqual(multiTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual(multiTuple.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(multiTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(multiTuple.__element__.__items__[0].__name__, "std::str"); + assert.equal(multiTuple.__element__.__items__[1].__name__, "std::str"); const multiTupleResult = await client.query(e.select(multiTuple).toEdgeQL()); - expect(multiTupleResult).toEqual([ + assert.deepEqual(multiTupleResult, [ ["asdf", "qwer"], ["asdf", "erty"], ]); @@ -178,21 +173,19 @@ test("tuple literal", async () => { $.Cardinality.AtLeastOne > >(true); - expect(multiTuplePath.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(await e.select(multiTuplePath).run(client)).toEqual(["asdf", "asdf"]); + assert.deepEqual(multiTuplePath.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await e.select(multiTuplePath).run(client), ["asdf", "asdf"]); const singleTuple = e.tuple([e.str("asdf")]); type singleTuple = $infer; tc.assert>(true); - expect(singleTuple.__element__.__kind__).toEqual($.TypeKind.tuple); - expect(singleTuple.__element__.__items__[0].__kind__).toEqual( - $.TypeKind.scalar - ); - expect(singleTuple.__element__.__items__[0].__name__).toEqual("std::str"); + assert.deepEqual(singleTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual(singleTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(singleTuple.__element__.__items__[0].__name__, "std::str"); const singleTupleResult = await client.querySingle( e.select(singleTuple).toEdgeQL() ); - expect(singleTupleResult).toEqual(["asdf"]); + assert.deepEqual(singleTupleResult, ["asdf"]); const nestedTuple = e.tuple([ "a", @@ -206,7 +199,7 @@ test("tuple literal", async () => { > >(true); const nestedTupleResult = await e.select(nestedTuple).run(client); - expect(nestedTupleResult).toEqual([ + assert.deepEqual(nestedTupleResult, [ ["a", ["b", "c"]], ["a", ["b", "d"]], ]); @@ -229,7 +222,7 @@ test("tuple literal", async () => { } > >(true); - expect(JSON.parse(JSON.stringify(nestedTuplePathResult))).toEqual({ + assert.deepEqual(JSON.parse(JSON.stringify(nestedTuplePathResult)), { tup0: ["a", "a"], tup1: [ ["b", "c"], @@ -242,13 +235,12 @@ test("tuple literal", async () => { const heroNamesTuple = e.tuple([e.Hero.name]); type heroNamesTuple = $infer; tc.assert>(true); - expect(heroNamesTuple.__element__.__kind__).toEqual($.TypeKind.tuple); - expect(heroNamesTuple.__element__.__items__[0].__kind__).toEqual( - $.TypeKind.scalar - ); - expect(heroNamesTuple.__element__.__items__[0].__name__).toEqual("std::str"); + assert.deepEqual(heroNamesTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual(heroNamesTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(heroNamesTuple.__element__.__items__[0].__name__, "std::str"); const heroNamesTupleResult = await e.select(heroNamesTuple).run(client); - expect(heroNamesTupleResult.sort((a, b) => a[0].localeCompare(b[0]))).toEqual( + assert.deepEqual( + heroNamesTupleResult.sort((a, b) => a[0].localeCompare(b[0])), [[data.cap.name], [data.iron_man.name], [data.spidey.name]].sort((a, b) => a[0].localeCompare(b[0]) ) @@ -260,11 +252,11 @@ test("namedTuple literal", async () => { string: e.str, number: e.int64, }); - expect(tupleType.__kind__).toEqual($.TypeKind.namedtuple); - expect(tupleType.__shape__.string.__kind__).toEqual($.TypeKind.scalar); - expect(tupleType.__shape__.string.__name__).toEqual("std::str"); - expect(tupleType.__shape__.number.__kind__).toEqual($.TypeKind.scalar); - expect(tupleType.__shape__.number.__name__).toEqual("std::int64"); + assert.deepEqual(tupleType.__kind__, $.TypeKind.namedtuple); + assert.deepEqual(tupleType.__shape__.string.__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__shape__.string.__name__, "std::str"); + assert.deepEqual(tupleType.__shape__.number.__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__shape__.number.__name__, "std::int64"); const named = e.tuple({ string: "asdf", @@ -273,31 +265,28 @@ test("namedTuple literal", async () => { type named = $.setToTsType; tc.assert>(true); - expect(named.__kind__).toEqual($.ExpressionKind.NamedTuple); - expect(named.__element__.__kind__).toEqual($.TypeKind.namedtuple); - expect(named.__cardinality__).toEqual($.Cardinality.One); - expect(named.__shape__.string.__kind__).toEqual($.ExpressionKind.Literal); - expect(named.__shape__.string.__value__).toEqual("asdf"); - expect(named.__shape__.number.__kind__).toEqual($.ExpressionKind.Literal); - expect(named.__shape__.number.__value__).toEqual(1234); - expect(named.__element__.__shape__.string.__kind__).toEqual( - $.TypeKind.scalar - ); - expect(named.__element__.__shape__.string.__name__).toEqual("std::str"); - expect(named.__element__.__shape__.number.__kind__).toEqual( - $.TypeKind.scalar - ); - expect(named.__element__.__shape__.number.__name__).toEqual("std::number"); + assert.deepEqual(named.__kind__, $.ExpressionKind.NamedTuple); + assert.deepEqual(named.__element__.__kind__, $.TypeKind.namedtuple); + assert.deepEqual(named.__cardinality__, $.Cardinality.One); + assert.deepEqual(named.__shape__.string.__kind__, $.ExpressionKind.Literal); + assert.equal(named.__shape__.string.__value__, "asdf"); + assert.deepEqual(named.__shape__.number.__kind__, $.ExpressionKind.Literal); + assert.equal(named.__shape__.number.__value__, 1234); + assert.deepEqual(named.__element__.__shape__.string.__kind__, $.TypeKind.scalar); + assert.equal(named.__element__.__shape__.string.__name__, "std::str"); + assert.deepEqual(named.__element__.__shape__.number.__kind__, $.TypeKind.scalar); + assert.equal(named.__element__.__shape__.number.__name__, "std::number"); const namedResult = await client.querySingle(e.select(named).toEdgeQL()); - expect(JSON.stringify(namedResult)).toEqual( + assert.deepEqual( + JSON.stringify(namedResult), JSON.stringify({ string: "asdf", number: 1234 }) ); const namedStr = named.string; const namedNum = named.number; tc.assert, string>>(true); tc.assert, number>>(true); - expect(await e.select(namedStr).run(client)).toEqual("asdf"); - expect(await e.select(namedNum).run(client)).toEqual(1234); + assert.equal(await e.select(namedStr).run(client), "asdf"); + assert.equal(await e.select(namedNum).run(client), 1234); const nested = e.tuple({ a: "asdf", @@ -327,27 +316,25 @@ test("namedTuple literal", async () => { } > >(true); - expect(JSON.stringify(nestedResult)).toEqual( - JSON.stringify({ - nested: [ - { a: "asdf", named: { b: 123 }, tuple: [true, "x"] }, - { a: "asdf", named: { b: 123 }, tuple: [true, "y"] }, - ], - nestedA: ["asdf", "asdf"], - nestedNamed: [{ b: 123 }, { b: 123 }], - nestedTuple: [ - [true, "x"], - [true, "y"], - ], - nestedTuple0: [true, true], - nestedTuple1: ["x", "y"], - }) - ); + assert.deepEqual(JSON.stringify(nestedResult), JSON.stringify({ + nested: [ + { a: "asdf", named: { b: 123 }, tuple: [true, "x"] }, + { a: "asdf", named: { b: 123 }, tuple: [true, "y"] }, + ], + nestedA: ["asdf", "asdf"], + nestedNamed: [{ b: 123 }, { b: 123 }], + nestedTuple: [ + [true, "x"], + [true, "y"], + ], + nestedTuple0: [true, true], + nestedTuple1: ["x", "y"], + })); const emptyNamedTuple = e.tuple({ string: e.cast(e.str, e.set()) }); type emptyNamedTuple = $.setToTsType; tc.assert>(true); - expect(emptyNamedTuple.__cardinality__).toEqual($.Cardinality.Empty); + assert.deepEqual(emptyNamedTuple.__cardinality__, $.Cardinality.Empty); const multiNamedTuple = e.tuple({ hero: e.Hero, @@ -363,17 +350,17 @@ test("namedTuple literal", async () => { }[] > >(true); - expect(multiNamedTuple.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(multiNamedTuple.__cardinality__, $.Cardinality.Many); }); test("non literal tuples", async () => { const ver = e.sys.get_version(); - expect(ver.major.__element__.__name__).toEqual("std::int64"); - expect(ver.major.__cardinality__).toEqual($.Cardinality.One); - expect(ver.stage.__element__.__name__).toEqual("sys::VersionStage"); - expect(ver.stage.__cardinality__).toEqual($.Cardinality.One); - expect(ver.local.__element__.__name__).toEqual("array"); - expect(ver.local.__cardinality__).toEqual($.Cardinality.One); + assert.equal(ver.major.__element__.__name__, "std::int64"); + assert.deepEqual(ver.major.__cardinality__, $.Cardinality.One); + assert.equal(ver.stage.__element__.__name__, "sys::VersionStage"); + assert.deepEqual(ver.stage.__cardinality__, $.Cardinality.One); + assert.equal(ver.local.__element__.__name__, "array"); + assert.deepEqual(ver.local.__cardinality__, $.Cardinality.One); const result = await e .select({ @@ -404,12 +391,12 @@ test("non literal tuples", async () => { > >(true); - expect({ + assert.deepEqual({ major: result.verMajor, stage: result.verStage, local: result.verLocal, local0: result.verLocal0, - }).toEqual({ + }, { major: result.ver.major, stage: result.ver.stage, local: result.ver.local, @@ -420,9 +407,9 @@ test("non literal tuples", async () => { test("objectTypeToTupleType helper", () => { const movieTuple = objectTypeToTupleType(e.Movie); - expect(movieTuple["__kind__"]).toBe("namedtuple"); - expect(movieTuple["__name__"].slice(0, 6)).toBe("tuple<"); - expect(movieTuple["__name__"].slice(6, -1).split(", ").sort()).toEqual([ + assert.equal(movieTuple["__kind__"], "namedtuple"); + assert.equal(movieTuple["__name__"].slice(0, 6), "tuple<"); + assert.deepEqual(movieTuple["__name__"].slice(6, -1).split(", ").sort(), [ "genre: default::Genre", "rating: std::float64", "release_year: default::year", @@ -442,11 +429,9 @@ test("objectTypeToTupleType helper", () => { "release_year", ]); - expect(movieTupleWithFields["__kind__"]).toBe("namedtuple"); - expect(movieTupleWithFields["__name__"].slice(0, 6)).toBe("tuple<"); - expect( - movieTupleWithFields["__name__"].slice(6, -1).split(", ").sort() - ).toEqual([ + assert.equal(movieTupleWithFields["__kind__"], "namedtuple"); + assert.equal(movieTupleWithFields["__name__"].slice(0, 6), "tuple<"); + assert.deepEqual(movieTupleWithFields["__name__"].slice(6, -1).split(", ").sort(), [ "id: std::uuid", "release_year: default::year", "title: std::str", diff --git a/packages/generate/test/delete.test.ts b/packages/generate/test/delete.test.ts index 5953530fd..fcf2e7e90 100644 --- a/packages/generate/test/delete.test.ts +++ b/packages/generate/test/delete.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; @@ -28,8 +29,8 @@ test("basic delete", async () => { })); const deletedResult = await deleteBlackWidow.run(client); - expect(deletedResult).not.toEqual(null); - expect(deletedResult!.id).toEqual(insertedResult.id); + assert.notDeepEqual(deletedResult, null); + assert.deepEqual(deletedResult!.id, insertedResult.id); const deleteWrappingSelect = e.delete( e.select(e.Hero, (hero) => ({ @@ -42,7 +43,7 @@ test("basic delete", async () => { tc.assert>( true ); - expect(wrappingDeleteResult).toEqual(null); + assert.equal(wrappingDeleteResult, null); const deleteAll = e.delete(e.Hero); tc.assert< diff --git a/packages/generate/test/detached.test.ts b/packages/generate/test/detached.test.ts index c045eda64..2a6a9b631 100644 --- a/packages/generate/test/detached.test.ts +++ b/packages/generate/test/detached.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; import { setupTests, tc, teardownTests, TestData } from "./setupTeardown"; @@ -40,5 +41,5 @@ test("detached", async () => { id: data.iron_man.id, name: data.iron_man.name, }); - expect(result?.friends).toEqual(heroes); + assert.deepEqual(result?.friends, heroes); }); diff --git a/packages/generate/test/for.test.ts b/packages/generate/test/for.test.ts index 8c6e20ac7..2c828c5df 100644 --- a/packages/generate/test/for.test.ts +++ b/packages/generate/test/for.test.ts @@ -1,11 +1,14 @@ +import assert from "node:assert/strict"; import e from "../dbschema/edgeql-js"; test("simple for loop", () => { - expect(e.for(e.set(1, 2, 3), (x) => e.op(e.op(x, "*", 2), "+", x)).toEdgeQL()) - .toEqual(`FOR __forVar__0 IN {{ 1, 2, 3 }} -UNION ( - ((__forVar__0 * 2) + __forVar__0) -)`); + assert.equal( + e.for(e.set(1, 2, 3), (x) => e.op(e.op(x, "*", 2), "+", x)).toEdgeQL(), + `FOR __forVar__0 IN {{ 1, 2, 3 }} + UNION ( + ((__forVar__0 * 2) + __forVar__0) + )` + ); }); test("with vars in for loop", () => { @@ -17,7 +20,7 @@ test("with vars in for loop", () => { }); }); - expect(q1.toEdgeQL()).toEqual(`FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal(q1.toEdgeQL(), `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_0 := std::to_str(__forVar__0) @@ -49,7 +52,7 @@ UNION ( })); }); - expect(q2.toEdgeQL()).toEqual(`FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal(q2.toEdgeQL(), `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_1 := std::to_str(__forVar__0) diff --git a/packages/generate/test/functions.test.ts b/packages/generate/test/functions.test.ts index 23f29cf56..92de23fbb 100644 --- a/packages/generate/test/functions.test.ts +++ b/packages/generate/test/functions.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import superjson from "superjson"; import * as $ from "../src/syntax/reflection"; import e from "../dbschema/edgeql-js"; @@ -13,15 +14,14 @@ function checkFunctionExpr( returnType: T["__element__"], cardinality: T["__cardinality__"] ) { - expect(expr.__name__).toEqual(name); - expect(superjson.stringify(expr.__args__)).toEqual( + assert.deepEqual(expr.__name__, name); + assert.deepEqual( + superjson.stringify(expr.__args__), superjson.stringify(args.filter((arg) => arg !== undefined)) ); - expect(superjson.stringify(expr.__namedargs__)).toEqual( - superjson.stringify(namedargs) - ); - expect(expr.__element__.__name__).toEqual(returnType.__name__); - expect(expr.__cardinality__).toEqual(cardinality); + assert.deepEqual(superjson.stringify(expr.__namedargs__), superjson.stringify(namedargs)); + assert.deepEqual(expr.__element__.__name__, returnType.__name__); + assert.deepEqual(expr.__cardinality__, cardinality); } test("no args", () => { @@ -565,11 +565,11 @@ test("assert_*", () => { __cardinality__: $.Cardinality.Many, } as unknown as $.TypeSet; - expect(emptySet.__cardinality__).toEqual($.Cardinality.Empty); - expect(oneSet.__cardinality__).toEqual($.Cardinality.One); - expect(atLeastOneSet.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(atMostOneSet.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(manySet.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(emptySet.__cardinality__, $.Cardinality.Empty); + assert.deepEqual(oneSet.__cardinality__, $.Cardinality.One); + assert.deepEqual(atLeastOneSet.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(atMostOneSet.__cardinality__, $.Cardinality.AtMostOne); + assert.deepEqual(manySet.__cardinality__, $.Cardinality.Many); tc.assert< tc.IsExact<(typeof emptySet)["__cardinality__"], $.Cardinality.Empty> >(true); @@ -594,22 +594,22 @@ test("assert_*", () => { // assert_single const emptySingle = e.assert_single(emptySet); - expect(emptySingle.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(emptySingle.__cardinality__, $.Cardinality.AtMostOne); tc.assert< tc.IsExact<(typeof emptySingle)["__cardinality__"], $.Cardinality.AtMostOne> >(true); const oneSingle = e.assert_single(oneSet); - expect(oneSingle.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(oneSingle.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact<(typeof oneSingle)["__cardinality__"], $.Cardinality.One> >(true); const atLeastOneSingle = e.assert_single(atLeastOneSet); - expect(atLeastOneSingle.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(atLeastOneSingle.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact<(typeof atLeastOneSingle)["__cardinality__"], $.Cardinality.One> >(true); const atMostOneSingle = e.assert_single(atMostOneSet); - expect(atMostOneSingle.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(atMostOneSingle.__cardinality__, $.Cardinality.AtMostOne); tc.assert< tc.IsExact< (typeof atMostOneSingle)["__cardinality__"], @@ -617,24 +617,24 @@ test("assert_*", () => { > >(true); const manySingle = e.assert_single(manySet); - expect(manySingle.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(manySingle.__cardinality__, $.Cardinality.AtMostOne); tc.assert< tc.IsExact<(typeof manySingle)["__cardinality__"], $.Cardinality.AtMostOne> >(true); // assert_exists const emptyExists = e.assert_exists(emptySet); - expect(emptyExists.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(emptyExists.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact<(typeof emptyExists)["__cardinality__"], $.Cardinality.One> >(true); const oneExists = e.assert_exists(oneSet); - expect(oneExists.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(oneExists.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact<(typeof oneExists)["__cardinality__"], $.Cardinality.One> >(true); const atLeastOneExists = e.assert_exists(atLeastOneSet); - expect(atLeastOneExists.__cardinality__).toEqual($.Cardinality.AtLeastOne); + assert.deepEqual(atLeastOneExists.__cardinality__, $.Cardinality.AtLeastOne); tc.assert< tc.IsExact< (typeof atLeastOneExists)["__cardinality__"], @@ -642,12 +642,12 @@ test("assert_*", () => { > >(true); const atMostOneExists = e.assert_exists(atMostOneSet); - expect(atMostOneExists.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(atMostOneExists.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact<(typeof atMostOneExists)["__cardinality__"], $.Cardinality.One> >(true); const manyExists = e.assert_exists(manySet); - expect(manyExists.__cardinality__).toEqual($.Cardinality.AtLeastOne); + assert.deepEqual(manyExists.__cardinality__, $.Cardinality.AtLeastOne); tc.assert< tc.IsExact<(typeof manyExists)["__cardinality__"], $.Cardinality.AtLeastOne> >(true); @@ -655,7 +655,7 @@ test("assert_*", () => { test("persist Cardinality.One", async () => { const query = e.str_trim(e.str("test string")); - expect(query.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(query.__cardinality__, $.Cardinality.One); tc.assert>( true ); diff --git a/packages/generate/test/globals.test.ts b/packages/generate/test/globals.test.ts index 7f95650f3..2844ba849 100644 --- a/packages/generate/test/globals.test.ts +++ b/packages/generate/test/globals.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import { $ } from "edgedb"; import * as tc from "conditional-type-checks"; @@ -24,60 +25,47 @@ afterAll(async () => { }); testIfVersionGTE(2)("globals", async () => { - expect(e.select(e.global.uuid_global).toEdgeQL()).toEqual( + assert.equal( + e.select(e.global.uuid_global).toEdgeQL(), `SELECT (GLOBAL default::uuid_global)` ); // TODO: add additional tests using .withGlobals once it lands const str_required = await e.select(e.global.str_required).run(client); - expect(str_required).toEqual(`hi mom`); + assert.equal(str_required, `hi mom`); const str_required_multi = await e .select(e.global.str_required_multi) .run(client); - expect(str_required_multi).toEqual(["hi", "mom"]); + assert.deepEqual(str_required_multi, ["hi", "mom"]); - expect(e.global.arr_global.__element__.__name__).toEqual(`array`); - expect(e.global.arr_global.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(e.global.named_tuple_global.__element__.__name__).toEqual( + assert.equal(e.global.arr_global.__element__.__name__, `array`); + assert.deepEqual(e.global.arr_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal( + e.global.named_tuple_global.__element__.__name__, `tuple` ); - expect(e.global.named_tuple_global.__cardinality__).toEqual( - $.Cardinality.AtMostOne - ); - expect(e.global.num_global.__element__.__name__).toEqual(`std::int64`); - expect(e.global.num_global.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(e.global.seq_global.__element__.__name__).toEqual( - `default::global_seq` - ); - expect(e.global.seq_global.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(e.global.str_global.__element__.__name__).toEqual(`std::str`); - expect(e.global.str_global.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(e.global.str_global_with_default.__element__.__name__).toEqual( - `std::str` - ); - expect(e.global.str_global_with_default.__cardinality__).toEqual( - $.Cardinality.One - ); - expect(e.global.str_multi.__element__.__name__).toEqual(`default::str_multi`); - expect(e.global.str_multi.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(e.global.str_required.__element__.__name__).toEqual(`std::str`); - expect(e.global.str_required.__cardinality__).toEqual($.Cardinality.One); - expect(e.global.str_required_multi.__element__.__name__).toEqual( + assert.deepEqual(e.global.named_tuple_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.num_global.__element__.__name__, `std::int64`); + assert.deepEqual(e.global.num_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.seq_global.__element__.__name__, `default::global_seq`); + assert.deepEqual(e.global.seq_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.str_global.__element__.__name__, `std::str`); + assert.deepEqual(e.global.str_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.str_global_with_default.__element__.__name__, `std::str`); + assert.deepEqual(e.global.str_global_with_default.__cardinality__, $.Cardinality.One); + assert.equal(e.global.str_multi.__element__.__name__, `default::str_multi`); + assert.deepEqual(e.global.str_multi.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(e.global.str_required.__element__.__name__, `std::str`); + assert.deepEqual(e.global.str_required.__cardinality__, $.Cardinality.One); + assert.equal( + e.global.str_required_multi.__element__.__name__, `default::str_required_multi` ); - expect(e.global.str_required_multi.__cardinality__).toEqual( - $.Cardinality.AtLeastOne - ); - expect(e.global.tuple_global.__element__.__name__).toEqual( - `tuple` - ); - expect(e.global.tuple_global.__cardinality__).toEqual( - $.Cardinality.AtMostOne - ); - expect(e.global.uuid_global.__element__.__name__).toEqual(`std::uuid`); - expect(e.global.uuid_global.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(e.extra.global.user_id.__element__.__name__).toEqual(`std::uuid`); - expect(e.extra.global.user_id.__cardinality__).toEqual( - $.Cardinality.AtMostOne - ); + assert.deepEqual(e.global.str_required_multi.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(e.global.tuple_global.__element__.__name__, `tuple`); + assert.deepEqual(e.global.tuple_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.uuid_global.__element__.__name__, `std::uuid`); + assert.deepEqual(e.global.uuid_global.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.extra.global.user_id.__element__.__name__, `std::uuid`); + assert.deepEqual(e.extra.global.user_id.__cardinality__, $.Cardinality.AtMostOne); }); diff --git a/packages/generate/test/group.test.ts b/packages/generate/test/group.test.ts index edecc2835..6ad8fb22d 100644 --- a/packages/generate/test/group.test.ts +++ b/packages/generate/test/group.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; @@ -66,11 +67,11 @@ if (versionGTE(2)) { grouping: ["release_year"], }, ]); - expect(result.length).toEqual(2); - expect(result[0].elements.length).toEqual(1); - expect(result[0].elements[0].title).toBeDefined(); - expect(result[1].elements[0].release_year).toBeDefined(); - expect(result[1].elements[0].characters[0].name).toBeDefined(); + assert.equal(result.length, 2); + assert.equal(result[0].elements.length, 1); + assert.ok(result[0].elements[0].title); + assert.ok(result[1].elements[0].release_year); + assert.ok(result[1].elements[0].characters[0].name); }); test("group nested select", async () => { @@ -117,11 +118,11 @@ if (versionGTE(2)) { grouping: ["release_year"], }, ]); - expect(result.length).toEqual(1); - expect(result[0].elements.length).toEqual(1); - expect(result[0].elements[0].title).toBeDefined(); - expect(result[0].elements[0].release_year).toBeDefined(); - expect(result[0].elements[0].characters[0].name).toBeDefined(); + assert.equal(result.length, 1); + assert.equal(result[0].elements.length, 1); + assert.ok(result[0].elements[0].title); + assert.ok(result[0].elements[0].release_year); + assert.ok(result[0].elements[0].characters[0].name); }); test("multiple keys", async () => { @@ -154,8 +155,8 @@ if (versionGTE(2)) { > >(true); - expect(result.length).toEqual(2); - expect(result[0].elements.length).toEqual(1); + assert.equal(result.length, 2); + assert.equal(result[0].elements.length, 1); expect( result.filter((val) => val.key.title === data.civil_war.title)[0] ).toMatchObject({ @@ -200,7 +201,7 @@ if (versionGTE(2)) { // title2 := __withVar_1, // title3 := __withVar_1 // BY title1, title2, title3`); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __scope_0_defaultMovie_expr := DETACHED default::Movie, __scope_0_defaultMovie := (FOR __scope_0_defaultMovie_inner IN {__scope_0_defaultMovie_expr} UNION ( WITH @@ -247,11 +248,11 @@ SELECT __scope_0_defaultMovie_groups { }[] > >(true); - expect(result.length).toEqual(2); - expect(result[0].elements[0].title).toBeDefined(); - expect(result[1].elements[0].release_year).toBeDefined(); - expect(result[1].elements[0].len).toBeDefined(); - expect(result[0].grouping).toEqual(["title1", "title2", "title3"]); + assert.equal(result.length, 2); + assert.ok(result[0].elements[0].title); + assert.ok(result[1].elements[0].release_year); + assert.ok(result[1].elements[0].len); + assert.deepEqual(result[0].grouping, ["title1", "title2", "title3"]); }); test("grouping set", async () => { @@ -270,14 +271,14 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - expect(result.length).toEqual(4); + assert.equal(result.length, 4); expect(result).toMatchObject([ { grouping: ["title", "year"] }, { grouping: ["title", "year"] }, { grouping: ["title", "rating"] }, { grouping: ["title", "rating"] }, ]); - expect(result[0].elements.length).toEqual(1); + assert.equal(result[0].elements.length, 1); }); test("grouping tuples", async () => { @@ -297,16 +298,14 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - expect( - query.toEdgeQL().includes(`BY (title, len), (year, rating)`) - ).toEqual(true); + assert.equal(query.toEdgeQL().includes(`BY (title, len), (year, rating)`), true); expect(result[0].grouping).toMatchObject([ "title", "len", "year", "rating", ]); - expect(result.length).toEqual(2); + assert.equal(result.length, 2); }); test("cube", async () => { @@ -323,10 +322,8 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - expect(query.toEdgeQL().includes(`BY cube(title, len, year)`)).toEqual( - true - ); - expect(result.length).toEqual(15); + assert.equal(query.toEdgeQL().includes(`BY cube(title, len, year)`), true); + assert.equal(result.length, 15); }); test("rollup", async () => { @@ -343,21 +340,17 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - expect(query.toEdgeQL().includes(`BY rollup(title, len, year)`)).toEqual( - true - ); - expect( - result - .map((r) => r.grouping) - .every((g) => { - return ( - (!g[0] || g[0] === "title") && - (!g[1] || g[1] === "len") && - (!g[2] || g[2] === "year") - ); - }) - ).toEqual(true); - expect(result.length).toEqual(7); + assert.equal(query.toEdgeQL().includes(`BY rollup(title, len, year)`), true); + assert.equal(result + .map((r) => r.grouping) + .every((g) => { + return ( + (!g[0] || g[0] === "title") && + (!g[1] || g[1] === "len") && + (!g[2] || g[2] === "year") + ); + }), true); + assert.equal(result.length, 7); }); test("key override error", async () => { @@ -395,7 +388,7 @@ SELECT __scope_0_defaultMovie_groups { }; }); const result = await query.run(client); - expect(result[0].grouping).toEqual(["ccc", "ccc2", "len", "len2"]); + assert.deepEqual(result[0].grouping, ["ccc", "ccc2", "len", "len2"]); }); // depends on https://github.com/edgedb/edgedb/issues/3951 diff --git a/packages/generate/test/insert.test.ts b/packages/generate/test/insert.test.ts index 45b90f92c..f7bff9b6a 100644 --- a/packages/generate/test/insert.test.ts +++ b/packages/generate/test/insert.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type { Client } from "edgedb"; import type { Villain } from "../dbschema/edgeql-js/modules/default"; import type { InsertShape } from "../dbschema/edgeql-js/insert"; @@ -36,7 +37,7 @@ test("basic insert", async () => { rating: 5, }); - expect(q1.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(q1.__cardinality__, $.Cardinality.One); tc.assert>( true ); @@ -69,7 +70,7 @@ test("unless conflict", async () => { }) .unlessConflict(); - expect(q0.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q0.__cardinality__, $.Cardinality.AtMostOne); tc.assert< tc.IsExact<(typeof q0)["__cardinality__"], $.Cardinality.AtMostOne> >(true); @@ -83,14 +84,14 @@ test("unless conflict", async () => { on: movie.title, })); - expect(q1.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q1.__cardinality__, $.Cardinality.AtMostOne); tc.assert< tc.IsExact<(typeof q1)["__cardinality__"], $.Cardinality.AtMostOne> >(true); const r1 = await q1.run(client); - expect(r1).toEqual(null); + assert.equal(r1, null); tc.assert>(true); const q2 = e @@ -115,10 +116,10 @@ test("unless conflict", async () => { for (const movie of allMovies) { if (movie.title === "The Avengers") { - expect(movie.rating).toEqual(11); - expect(r2.id).toEqual(movie.id); + assert.equal(movie.rating, 11); + assert.deepEqual(r2.id, movie.id); } else { - expect(movie.rating).not.toEqual(11); + assert.notDeepEqual(movie.rating, 11); } } @@ -132,11 +133,11 @@ test("unless conflict", async () => { else: e.select(e.Hero, () => ({ name: true })), })); - expect(q3.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(q3.__cardinality__, $.Cardinality.Many); tc.assert>( true ); - expect(q3.__element__.__name__).toEqual("std::Object"); + assert.equal(q3.__element__.__name__, "std::Object"); tc.assert>( true ); @@ -295,8 +296,8 @@ test("insert link prop in nested select", async () => { })); const result = await selected.run(client); - expect(result.characters[0]["@character_name"]).toEqual("Tony Stark"); - expect(result.characters[0].name).toEqual("Iron Man"); + assert.equal(result.characters[0]["@character_name"], "Tony Stark"); + assert.equal(result.characters[0].name, "Iron Man"); }); test("insert link prop in nested insert", async () => { @@ -317,8 +318,8 @@ test("insert link prop in nested insert", async () => { })); const result = await selected.run(client); - expect(result.characters[0]["@character_name"]).toEqual("Ivan Vanko"); - expect(result.characters[0].name).toEqual("Whiplash"); + assert.equal(result.characters[0]["@character_name"], "Ivan Vanko"); + assert.equal(result.characters[0].name, "Whiplash"); }); test("no plain data as link prop", async () => { @@ -341,7 +342,7 @@ test("undefined in insert", async () => { release_year: undefined, }) .run(client); - expect(result.id).toBeDefined(); + assert.ok(result.id); }); test("invalid insert", async () => { @@ -358,7 +359,7 @@ test("invalid insert", async () => { test("empty shape insert", async () => { const res = await e.insert(e.Profile, {}).run(client); - expect(Object.keys(res)).toEqual(["id"]); + assert.deepEqual(Object.keys(res), ["id"]); }); testIfVersionGTE(2)("insert custom ID", async () => { diff --git a/packages/generate/test/json.test.ts b/packages/generate/test/json.test.ts index ec5e0fa5b..fee8e8407 100644 --- a/packages/generate/test/json.test.ts +++ b/packages/generate/test/json.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; @@ -24,7 +25,8 @@ test("basic select", async () => { const result = await query.runJSON(client); tc.assert>(true); - expect(result).toEqual( + assert.equal( + result, '[{"title" : "Captain America: Civil War"}, {"title" : "The Avengers"}]' ); }); @@ -37,7 +39,7 @@ test("select one", async () => { const result = await query.runJSON(client); tc.assert>(true); - expect(result).toEqual('[{"title" : "The Avengers"}]'); + assert.equal(result, '[{"title" : "The Avengers"}]'); }); test("json properties", async () => { @@ -77,7 +79,7 @@ test("json param", async () => { test("json read/write equivalents", async () => { const data = [5, "asdf", { sup: [3] }, ["asdf", 1234, false, null]]; for (const datum of data) { - expect(await e.json(datum).run(client)).toEqual(datum); + assert.deepEqual(await e.json(datum).run(client), datum); } }); @@ -91,7 +93,7 @@ test("serialize data classes", async () => { new edgedb.RelativeDuration(3), new edgedb.DateDuration(1), ]; - expect(await e.json(datum).run(client)).toEqual([ + assert.deepEqual(await e.json(datum).run(client), [ "2022-07-18T21:42:46.569Z", "2020-01-01", "2020-01-01T00:00:00", diff --git a/packages/generate/test/literals.test.ts b/packages/generate/test/literals.test.ts index ad4774803..fbda98adc 100644 --- a/packages/generate/test/literals.test.ts +++ b/packages/generate/test/literals.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as edgedb from "edgedb"; import { TypeKind } from "edgedb/dist/reflection"; import e from "../dbschema/edgeql-js"; @@ -12,85 +13,81 @@ test("literals", () => { const dateduration = new edgedb.DateDuration(1, 2, 3, 4); const uuid = "317fee4c-0da5-45aa-9980-fedac211bfb6"; - expect(e.std.bigint(BigInt("9007199254740991")).toEdgeQL()).toEqual( + assert.equal( + e.std.bigint(BigInt("9007199254740991")).toEdgeQL(), `9007199254740991n` ); - expect(e.std.bool(true).toEdgeQL()).toEqual(`true`); - expect( - e.std.bytes(Buffer.from(`whatever\nðñòóôõö÷øùúûüýþÿ`)).toEdgeQL() - ).toEqual( + assert.equal(e.std.bool(true).toEdgeQL(), `true`); + assert.deepEqual( + e.std.bytes(Buffer.from(`whatever\nðñòóôõö÷øùúûüýþÿ`)).toEdgeQL(), `b'whatever\\n\\xc3\\xb0\\xc3\\xb1\\xc3\\xb2\\xc3\\xb3\\xc3\\xb4\\xc3` + `\\xb5\\xc3\\xb6\\xc3\\xb7\\xc3\\xb8\\xc3\\xb9\\xc3\\xba\\xc3\\xbb` + `\\xc3\\xbc\\xc3\\xbd\\xc3\\xbe\\xc3\\xbf'` ); - expect( - e.std.datetime(new Date("2021-06-25T02:01:13.681Z")).toEdgeQL() - ).toEqual(`'2021-06-25T02:01:13.681Z'`); - expect(e.std.decimal("1234.1234n").toEdgeQL()).toEqual( - `"1234.1234n"` + assert.equal( + e.std.datetime(new Date("2021-06-25T02:01:13.681Z")).toEdgeQL(), + `'2021-06-25T02:01:13.681Z'` ); - expect(e.std.duration(duration).toEdgeQL()).toEqual( - `'PT5H6M7.00800901S'` - ); - expect(e.std.int16(144.1235).toEdgeQL()).toEqual(`144.1235`); - expect(e.std.int64(1234.15).toEdgeQL()).toEqual(`1234.15`); - expect(e.std.float64(1234.1234).toEdgeQL()).toEqual( - `1234.1234` - ); - expect(e.std.float64(124).toEdgeQL()).toEqual(`124`); - expect(e.std.int16("9223372036854775807").toEdgeQL()).toEqual( + assert.equal(e.std.decimal("1234.1234n").toEdgeQL(), `"1234.1234n"`); + assert.equal(e.std.duration(duration).toEdgeQL(), `'PT5H6M7.00800901S'`); + assert.equal(e.std.int16(144.1235).toEdgeQL(), `144.1235`); + assert.equal(e.std.int64(1234.15).toEdgeQL(), `1234.15`); + assert.equal(e.std.float64(1234.1234).toEdgeQL(), `1234.1234`); + assert.equal(e.std.float64(124).toEdgeQL(), `124`); + assert.equal( + e.std.int16("9223372036854775807").toEdgeQL(), `9223372036854775807` ); - expect(e.year("1234").toEdgeQL()).toEqual(`1234`); + assert.equal(e.year("1234").toEdgeQL(), `1234`); - expect(e.std.json("asdf").toEdgeQL()).toEqual(`to_json($$"asdf"$$)`); - expect( - e.std.json({ a: 123, b: "some string", c: [true, false] }).toEdgeQL() - ).toEqual('to_json($${"a":123,"b":"some string","c":[true,false]}$$)'); + assert.equal(e.std.json("asdf").toEdgeQL(), `to_json($$"asdf"$$)`); + assert.equal( + e.std.json({ a: 123, b: "some string", c: [true, false] }).toEdgeQL(), + 'to_json($${"a":123,"b":"some string","c":[true,false]}$$)' + ); - expect(e.std.str(`asdfaf`).toEdgeQL()).toEqual(`"asdfaf"`); - expect(e.std.str(`string " with ' all \` quotes`).toEdgeQL()).toEqual( + assert.equal(e.std.str(`asdfaf`).toEdgeQL(), `"asdfaf"`); + assert.equal( + e.std.str(`string " with ' all \` quotes`).toEdgeQL(), `"string \\" with ' all \` quotes"` ); - expect(e.std.uuid(uuid).toEdgeQL()).toEqual( + assert.equal( + e.std.uuid(uuid).toEdgeQL(), `"317fee4c-0da5-45aa-9980-fedac211bfb6"` ); - expect(e.cal.local_date(localdate).toEdgeQL()).toEqual( - `'2021-10-31'` - ); - expect(e.cal.local_datetime(localdatetime).toEdgeQL()).toEqual( + assert.equal(e.cal.local_date(localdate).toEdgeQL(), `'2021-10-31'`); + assert.equal( + e.cal.local_datetime(localdatetime).toEdgeQL(), `'2021-10-31T21:45:30'` ); - expect(e.cal.local_time(localtime).toEdgeQL()).toEqual( - `'15:15:00'` - ); - expect(e.cal.relative_duration(relduration).toEdgeQL()).toEqual( + assert.equal(e.cal.local_time(localtime).toEdgeQL(), `'15:15:00'`); + assert.equal( + e.cal.relative_duration(relduration).toEdgeQL(), `'P1Y2M21D'` ); - expect(e.cal.date_duration(dateduration).toEdgeQL()).toEqual( + assert.equal( + e.cal.date_duration(dateduration).toEdgeQL(), `'P1Y2M25D'` ); }); test("collection type literals", () => { const literalArray = e.literal(e.array(e.str), ["adsf"]); - expect(literalArray.toEdgeQL()).toEqual(`["adsf"]`); + assert.equal(literalArray.toEdgeQL(), `["adsf"]`); const literalNamedTuple = e.literal(e.tuple({ str: e.str }), { str: "asdf", }); - expect(literalNamedTuple.toEdgeQL()).toEqual(`( str := "asdf" )`); + assert.equal(literalNamedTuple.toEdgeQL(), `( str := "asdf" )`); const literalTuple = e.literal(e.tuple([e.str, e.int64]), ["asdf", 1234]); - expect(literalTuple.toEdgeQL()).toEqual(`( "asdf", 1234 )`); + assert.equal(literalTuple.toEdgeQL(), `( "asdf", 1234 )`); }); test("enum literals", () => { const horror = e.Genre.Horror; - expect(e.Genre.Horror.__element__.__kind__).toEqual(TypeKind.enum); - expect(horror.__element__).toEqual(e.Genre); - expect(horror.__cardinality__).toEqual(edgedb.$.Cardinality.One); - expect(e.literal(e.Genre, "Horror").toEdgeQL()).toEqual( - `default::Genre.Horror` - ); + assert.deepEqual(e.Genre.Horror.__element__.__kind__, TypeKind.enum); + assert.deepEqual(horror.__element__, e.Genre); + assert.deepEqual(horror.__cardinality__, edgedb.$.Cardinality.One); + assert.equal(e.literal(e.Genre, "Horror").toEdgeQL(), `default::Genre.Horror`); expect(e.Genre.__values__).toContain("Horror"); @@ -104,9 +101,7 @@ testIfVersionGTE(2)("constructing with strings", async () => { const { client } = await setupTests(); const dateString = new Date().toISOString(); - expect( - await (await e.datetime(dateString).run(client)).toISOString() - ).toEqual(dateString); + assert.deepEqual(await (await e.datetime(dateString).run(client)).toISOString(), dateString); await e.int64("12341234").run(client); await e.cal.local_datetime("1999-03-31T15:17:00").run(client); diff --git a/packages/generate/test/objectTypes.test.ts b/packages/generate/test/objectTypes.test.ts index b684fccb3..7256bed43 100644 --- a/packages/generate/test/objectTypes.test.ts +++ b/packages/generate/test/objectTypes.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as $ from "../src/syntax/reflection"; import type { PropertyDesc } from "../src/syntax/typesystem"; import e from "../dbschema/edgeql-js"; @@ -11,54 +12,44 @@ const $Simple = e.default.Simple.__element__; const $Z = e.default.Z.__element__; test("property hydration", () => { - expect(typeof $Hero).toBe("object"); - expect($Hero.__name__).toBe("default::Hero"); - expect($Hero.__pointers__.name.__kind__).toBe("property"); - expect($Hero.__pointers__.name.cardinality).toBe($.Cardinality.One); - expect($Hero.__pointers__.name.target).toEqual(e.std.str); - expect($Hero.__pointers__.name.target.__kind__).toEqual($.TypeKind.scalar); - expect($Hero.__pointers__.name.exclusive).toEqual(true); - expect($Hero.__pointers__.secret_identity.exclusive).toEqual(false); - - expect(e.default.Movie.__element__.__pointers__.profile.exclusive).toEqual( - true - ); + assert.equal(typeof $Hero, "object"); + assert.equal($Hero.__name__, "default::Hero"); + assert.equal($Hero.__pointers__.name.__kind__, "property"); + assert.equal($Hero.__pointers__.name.cardinality, $.Cardinality.One); + assert.deepEqual($Hero.__pointers__.name.target, e.std.str); + assert.deepEqual($Hero.__pointers__.name.target.__kind__, $.TypeKind.scalar); + assert.equal($Hero.__pointers__.name.exclusive, true); + assert.equal($Hero.__pointers__.secret_identity.exclusive, false); + + assert.equal(e.default.Movie.__element__.__pointers__.profile.exclusive, true); // expect(e.default.Movie.profile.__exclusive__).toEqual(true); - expect(e.default.Movie.__element__.__pointers__.characters.exclusive).toEqual( - false - ); + assert.equal(e.default.Movie.__element__.__pointers__.characters.exclusive, false); // expect(e.default.Movie.characters.__exclusive__).toEqual(false); }); test("link hydration", () => { - expect($Hero.__pointers__.villains.__kind__).toBe("link"); - expect($Hero.__pointers__.villains.target.__kind__).toBe($.TypeKind.object); - expect($Hero.__pointers__.villains.cardinality).toBe($.Cardinality.Many); - expect($Hero.__pointers__.villains.target.__name__).toEqual( - "default::Villain" - ); - expect($Hero.__pointers__.villains.properties).toEqual({}); + assert.equal($Hero.__pointers__.villains.__kind__, "link"); + assert.equal($Hero.__pointers__.villains.target.__kind__, $.TypeKind.object); + assert.equal($Hero.__pointers__.villains.cardinality, $.Cardinality.Many); + assert.equal($Hero.__pointers__.villains.target.__name__, "default::Villain"); + assert.deepEqual($Hero.__pointers__.villains.properties, {}); // type union link - expect($Z.__pointers__.xy.__kind__).toEqual("link"); - expect($Z.__pointers__.xy.target.__name__).toEqual("default::X | default::Y"); - expect(Object.keys($Z.__pointers__.xy.target.__pointers__).sort()).toEqual([ + assert.equal($Z.__pointers__.xy.__kind__, "link"); + assert.equal($Z.__pointers__.xy.target.__name__, "default::X | default::Y"); + assert.deepEqual(Object.keys($Z.__pointers__.xy.target.__pointers__).sort(), [ "__type__", "a", "id", ]); - expect($Z.__pointers__.xy.target.__pointers__.a.target.__name__).toEqual( - "std::str" - ); + assert.equal($Z.__pointers__.xy.target.__pointers__.a.target.__name__, "std::str"); }); const link = $AnnotationSubject.__pointers__.annotations; test("link properties", () => { - expect(link.properties["@value"].target.__name__).toEqual("std::str"); - expect(link.properties["@value"].cardinality).toEqual( - $.Cardinality.AtMostOne - ); - expect(link.properties["@value"].__kind__).toEqual("property"); + assert.equal(link.properties["@value"].target.__name__, "std::str"); + assert.deepEqual(link.properties["@value"].cardinality, $.Cardinality.AtMostOne); + assert.equal(link.properties["@value"].__kind__, "property"); }); test("overloaded properties", () => { @@ -73,39 +64,39 @@ test("overloaded properties", () => { test("named tuple tests", () => { // named tuple tests const BagShape = $Bag.__pointers__; - expect(BagShape.namedTuple.cardinality).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(BagShape.namedTuple.cardinality, $.Cardinality.AtMostOne); const namedTuple = BagShape.namedTuple.target; - expect(namedTuple.__kind__).toEqual($.TypeKind.namedtuple); - expect(namedTuple.__shape__.x.__name__).toEqual("std::str"); - expect(namedTuple.__shape__.x.__kind__).toEqual($.TypeKind.scalar); - expect(namedTuple.__shape__.y.__name__).toEqual("std::int64"); + assert.deepEqual(namedTuple.__kind__, $.TypeKind.namedtuple); + assert.equal(namedTuple.__shape__.x.__name__, "std::str"); + assert.deepEqual(namedTuple.__shape__.x.__kind__, $.TypeKind.scalar); + assert.equal(namedTuple.__shape__.y.__name__, "std::int64"); }); test("unnamed tuple tests", () => { // named tuple tests const BagShape = $Bag.__pointers__; const unnamedTuple = BagShape.unnamedTuple.target; - expect(unnamedTuple.__kind__).toEqual($.TypeKind.tuple); - expect(unnamedTuple.__items__[0].__name__).toEqual("std::str"); - expect(unnamedTuple.__items__[1].__name__).toEqual("std::int64"); + assert.deepEqual(unnamedTuple.__kind__, $.TypeKind.tuple); + assert.equal(unnamedTuple.__items__[0].__name__, "std::str"); + assert.equal(unnamedTuple.__items__[1].__name__, "std::int64"); }); test("array tests", () => { // named tuple tests const BagShape = $Bag.__pointers__; const arrayProp = BagShape.stringsArr.target; - expect(arrayProp.__kind__).toEqual($.TypeKind.array); - expect(arrayProp.__element__.__name__).toEqual("std::str"); + assert.deepEqual(arrayProp.__kind__, $.TypeKind.array); + assert.equal(arrayProp.__element__.__name__, "std::str"); }); test("merging tests", () => { const merged = $.$mergeObjectTypes($Bag, $Simple); - expect(Object.keys(merged.__pointers__).length).toEqual(4); - expect(Object.keys(merged.__pointers__).includes("id")).toEqual(true); - expect(Object.keys(merged.__pointers__).includes("__type__")).toEqual(true); - expect(Object.keys(merged.__pointers__).includes("name")).toEqual(true); - expect(Object.keys(merged.__pointers__).includes("age")).toEqual(true); + assert.equal(Object.keys(merged.__pointers__).length, 4); + assert.equal(Object.keys(merged.__pointers__).includes("id"), true); + assert.equal(Object.keys(merged.__pointers__).includes("__type__"), true); + assert.equal(Object.keys(merged.__pointers__).includes("name"), true); + assert.equal(Object.keys(merged.__pointers__).includes("age"), true); type merged = keyof (typeof merged)["__pointers__"]; // shared keys tc.assert>(true); @@ -115,24 +106,19 @@ test("backlinks", () => { const heroMovie = e.Hero[" ({ limit: 1 })).assert_single().nemesis - .__cardinality__ - ).toEqual($.Cardinality.AtMostOne); + assert.equal(heroMovie.toEdgeQL(), `DETACHED default::Hero. ({ limit: 1 })).assert_single().nemesis + .__cardinality__, $.Cardinality.AtMostOne); - expect(e.Profile[" { // on root object const movieStar = e.Movie["*"]; - expect(movieStar).toEqual(movieStarShape); + assert.deepEqual(movieStar, movieStarShape); tc.assert< tc.IsExact< typeof movieStar, @@ -165,7 +151,7 @@ test("select *", () => { // on select scope e.select(e.Movie, (movie) => { - expect(movie["*"]).toEqual(movieStarShape); + assert.deepEqual(movie["*"], movieStarShape); return {}; }); @@ -174,7 +160,7 @@ test("select *", () => { e.select( e.select(e.Movie, () => ({})), (movie) => { - expect(movie["*"]).toEqual(movieStarShape); + assert.deepEqual(movie["*"], movieStarShape); return {}; } @@ -182,7 +168,7 @@ test("select *", () => { // on polymorphic select scope e.select(e.Person.is(e.Hero), (hero) => { - expect(hero["*"]).toEqual({ + assert.deepEqual(hero["*"], { id: true, name: true, height: true, @@ -195,7 +181,7 @@ test("select *", () => { // on insert select e.select(e.insert(e.Movie, { title: "test" }), (movie) => { - expect(movie["*"]).toEqual(movieStarShape); + assert.deepEqual(movie["*"], movieStarShape); return movie["*"]; }).toEdgeQL(); diff --git a/packages/generate/test/operators.test.ts b/packages/generate/test/operators.test.ts index be86f2a6a..ba708d368 100644 --- a/packages/generate/test/operators.test.ts +++ b/packages/generate/test/operators.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import superjson from "superjson"; import type { Client } from "edgedb"; import e from "../dbschema/edgeql-js"; @@ -25,15 +26,16 @@ function checkOperatorExpr( cardinality: T["__cardinality__"], edgeql?: string ) { - expect(expr.__name__).toEqual(name); - expect(superjson.stringify(expr.__args__)).toEqual( + assert.deepEqual(expr.__name__, name); + assert.deepEqual( + superjson.stringify(expr.__args__), superjson.stringify(args.filter((arg) => arg !== undefined)) ); - expect(expr.__element__).toEqual(returnType); - expect(expr.__cardinality__).toEqual(cardinality); + assert.deepEqual(expr.__element__, returnType); + assert.deepEqual(expr.__cardinality__, cardinality); if (edgeql) { - expect(expr.toEdgeQL()).toEqual(edgeql); + assert.deepEqual(expr.toEdgeQL(), edgeql); } } @@ -218,18 +220,18 @@ test("non-literal args", async () => { test("cardinalities for set of operators", async () => { const t1 = e.op(e.cast(e.str, e.set()), "??", "default"); - expect(t1.__cardinality__).toEqual($.Cardinality.AtMostOne); - expect(await t1.run(client)).toEqual("default"); + assert.deepEqual(t1.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(await t1.run(client), "default"); const t2 = e.op(e.cast(e.str, e.set()), "union", "default"); - expect(t2.__cardinality__).toEqual($.Cardinality.One); - expect(await t1.run(client)).toEqual("default"); + assert.deepEqual(t2.__cardinality__, $.Cardinality.One); + assert.equal(await t1.run(client), "default"); const t3 = e.op("one", "union", "two"); - expect(t3.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(await t3.run(client)).toEqual(["one", "two"]); + assert.deepEqual(t3.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await t3.run(client), ["one", "two"]); const t4 = e.op("distinct", "default"); - expect(t4.__cardinality__).toEqual($.Cardinality.One); - expect(await t4.run(client)).toEqual("default"); + assert.deepEqual(t4.__cardinality__, $.Cardinality.One); + assert.equal(await t4.run(client), "default"); }); diff --git a/packages/generate/test/params.test.ts b/packages/generate/test/params.test.ts index b25102cf6..afa78ca5e 100644 --- a/packages/generate/test/params.test.ts +++ b/packages/generate/test/params.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; import { @@ -34,7 +35,7 @@ test("simple params", () => { }) ); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __param__str := $str, __param__numArr := >$numArr, __param__optBool := $optBool @@ -120,7 +121,7 @@ test("complex params", async () => { ], }); - expect({ + assert.deepEqual({ ...result, nums: [...result.nums], tuple: [...result.tuple], @@ -135,7 +136,7 @@ test("complex params", async () => { age: p.age, tags: [...p.tags], })), - }).toEqual({ + }, { id: (result as any).id, str: "test string", nums: [1, 2, 3], @@ -158,11 +159,11 @@ test("native tuple type params", async () => { ); if (versionGTE(3)) { - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __param__test := >$test SELECT (SELECT __param__test)`); } else { - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __param__test := >to_json($test) SELECT (SELECT __param__test)`); } @@ -224,7 +225,7 @@ test("all param types", async () => { const result = await query.run(client, args); - expect(result).toEqual({ + assert.deepEqual(result, { // @ts-ignore id: result.id, ...args, @@ -270,9 +271,7 @@ test("all param types", async () => { tuple: args, }); - expect(Object.values(complexResult.tuple as any)).toEqual( - Object.values(args) - ); + assert.deepEqual(Object.values(complexResult.tuple as any), Object.values(args)); }); testIfVersionGTE(2)("v2 param types", async () => { @@ -288,7 +287,7 @@ testIfVersionGTE(2)("v2 param types", async () => { const result = await query.run(client, args); - expect(result).toEqual({ + assert.deepEqual(result, { // @ts-ignore id: result.id, ...args, diff --git a/packages/generate/test/paths.test.ts b/packages/generate/test/paths.test.ts index 34ce55ae6..b72e6eb74 100644 --- a/packages/generate/test/paths.test.ts +++ b/packages/generate/test/paths.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as $ from "../src/syntax/reflection"; import e from "../dbschema/edgeql-js/index"; import { $PathNode } from "../dbschema/edgeql-js/syntax"; @@ -14,14 +15,12 @@ test("path structure", () => { const VillainRoot = $.$toSet($Villain, $.Cardinality.One); const Villain = $PathNode(VillainRoot, null); - expect(Hero.name.__element__.__kind__).toEqual($.TypeKind.scalar); - expect(Hero.name.__element__.__name__).toEqual("std::str"); - expect(Hero.name.__cardinality__).toEqual($.Cardinality.Many); - expect(HeroSingleton.name.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(Hero.name.__element__.__kind__, $.TypeKind.scalar); + assert.equal(Hero.name.__element__.__name__, "std::str"); + assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); + assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); - expect(Villain[">(true); @@ -30,14 +29,14 @@ test("path structure", () => { ); // Hero.name - expect(Hero.name.__element__.__name__).toEqual("std::str"); - expect(Hero.name.__cardinality__).toEqual($.Cardinality.Many); + assert.equal(Hero.name.__element__.__name__, "std::str"); + assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); tc.assert>( true ); // HeroSingleton.name - expect(HeroSingleton.name.__cardinality__).toEqual($.Cardinality.One); + assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); tc.assert< tc.IsExact >(true); @@ -47,10 +46,8 @@ test("path structure", () => { const HeroSetAtLeastOne = $.$toSet($Hero, $.Cardinality.AtLeastOne); const AtLeastOneHero = $PathNode(HeroSetAtLeastOne, null); type AtLeastOneHero = typeof AtLeastOneHero; - expect(AtLeastOneHero.id.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(AtLeastOneHero.number_of_movies.__cardinality__).toEqual( - $.Cardinality.Many - ); + assert.deepEqual(AtLeastOneHero.id.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(AtLeastOneHero.number_of_movies.__cardinality__, $.Cardinality.Many); tc.assert< tc.IsExact< AtLeastOneHero["number_of_movies"]["__cardinality__"], @@ -59,7 +56,7 @@ test("path structure", () => { >(true); // Hero.villains.id - expect(Hero.villains.id.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(Hero.villains.id.__cardinality__, $.Cardinality.Many); tc.assert< tc.IsExact< HeroSingleton["villains"]["id"]["__cardinality__"], @@ -67,18 +64,18 @@ test("path structure", () => { > >(true); - expect(Hero.villains.nemesis.villains.name.toEdgeQL()).toEqual( + assert.equal( + Hero.villains.nemesis.villains.name.toEdgeQL(), "DETACHED default::Hero.villains.nemesis.villains.name" ); const Herotype = Hero.__type__.__type__.__type__; - expect(Herotype.annotations.__type__.computed_fields.toEdgeQL()).toEqual( + assert.equal( + Herotype.annotations.__type__.computed_fields.toEdgeQL(), "DETACHED default::Hero.__type__.__type__.__type__.annotations.__type__.computed_fields" ); - expect(Hero.villains.__parent__).not.toBeNull(); - expect(Hero.villains.__parent__?.linkName).toEqual("villains"); - expect(Hero.villains.__parent__?.type.__element__.__name__).toEqual( - "default::Hero" - ); + assert.ok(Hero.villains.__parent__); + assert.equal(Hero.villains.__parent__?.linkName, "villains"); + assert.equal(Hero.villains.__parent__?.type.__element__.__name__, "default::Hero"); }); test("type intersection on path node", () => { @@ -100,27 +97,27 @@ test("type intersection on path node", () => { tc.assert< tc.IsExact<(typeof hero)["__element__"]["__shape__"], { id: true }> >(true); - expect(hero.__element__.__shape__).toEqual({ id: true }); - expect(hero.__element__.__name__).toEqual("default::Hero"); - expect(hero.__element__.__kind__).toEqual($.TypeKind.object); - expect(hero.__kind__).toEqual($.ExpressionKind.TypeIntersection); + assert.deepEqual(hero.__element__.__shape__, { id: true }); + assert.equal(hero.__element__.__name__, "default::Hero"); + assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); + assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); // referential equality - expect(hero.__expr__).toBe(person); + assert.equal(hero.__expr__, person); // check that pathify works - expect(hero.number_of_movies.__element__.__name__).toEqual("std::int64"); - expect(hero.toEdgeQL()).toEqual(`DETACHED default::Person[IS default::Hero]`); + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); + assert.equal(hero.toEdgeQL(), `DETACHED default::Person[IS default::Hero]`); }); test("type intersection on select", () => { const q2 = e.select(e.Person, () => ({ id: true, name: true, limit: 5 })); const hero = q2.is(e.Hero); - expect(hero.__element__.__name__).toEqual("default::Hero"); - expect(hero.__element__.__kind__).toEqual($.TypeKind.object); - expect(hero.__kind__).toEqual($.ExpressionKind.TypeIntersection); + assert.equal(hero.__element__.__name__, "default::Hero"); + assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); + assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); // referential equality - expect(hero.__expr__).toBe(q2); + assert.equal(hero.__expr__, q2); // check that pathify works - expect(hero.number_of_movies.__element__.__name__).toEqual("std::int64"); + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); }); test("assert_single", () => { @@ -128,5 +125,5 @@ test("assert_single", () => { tc.assert< tc.IsExact<(typeof singleHero)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(singleHero.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(singleHero.__cardinality__, $.Cardinality.AtMostOne); }); diff --git a/packages/generate/test/primitives.test.ts b/packages/generate/test/primitives.test.ts index a98efa59c..ac2cb5cff 100644 --- a/packages/generate/test/primitives.test.ts +++ b/packages/generate/test/primitives.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; import type { getSharedParentPrimitiveVariadic } from "../dbschema/edgeql-js/syntax"; @@ -15,24 +16,24 @@ afterAll(async () => { }); test("primitive types", () => { - expect(e.int16.__name__).toEqual("std::int16"); - expect(e.int32.__name__).toEqual("std::int32"); - expect(e.int64.__name__).toEqual("std::int64"); - expect(e.float32.__name__).toEqual("std::float32"); - expect(e.float64.__name__).toEqual("std::float64"); - expect(e.str.__name__).toEqual("std::str"); + assert.equal(e.int16.__name__, "std::int16"); + assert.equal(e.int32.__name__, "std::int32"); + assert.equal(e.int64.__name__, "std::int64"); + assert.equal(e.float32.__name__, "std::float32"); + assert.equal(e.float64.__name__, "std::float64"); + assert.equal(e.str.__name__, "std::str"); }); test("collection types", () => { const arrayType = e.array(e.str); - expect(arrayType.__name__).toEqual("array"); + assert.equal(arrayType.__name__, "array"); const named = e.tuple({ str: e.str }); - expect(named.__name__).toEqual("tuple"); - expect(named.__shape__.str.__name__).toEqual("std::str"); + assert.equal(named.__name__, "tuple"); + assert.equal(named.__shape__.str.__name__, "std::str"); const unnamed = e.tuple([e.str, e.int64]); - expect(unnamed.__name__).toEqual("tuple"); - expect(unnamed.__items__[0].__name__).toEqual("std::str"); - expect(unnamed.__items__[1].__name__).toEqual("std::int64"); + assert.equal(unnamed.__name__, "tuple"); + assert.equal(unnamed.__items__[0].__name__, "std::str"); + assert.equal(unnamed.__items__[1].__name__, "std::int64"); }); test("scalar type merging", () => { @@ -55,24 +56,26 @@ test("range primitives", async () => { new Date("2022-07-05T16:00:00Z") ); - expect(e.std.range(range).toEdgeQL()).toEqual( + assert.equal( + e.std.range(range).toEdgeQL(), `std::range(3, 8, inc_lower := true, inc_upper := false)` ); - expect(e.std.range(lowerRange).toEdgeQL()).toEqual( + assert.equal( + e.std.range(lowerRange).toEdgeQL(), `std::range(3, {}, inc_lower := true, inc_upper := false)` ); - expect(e.std.range(upperRange).toEdgeQL()).toEqual( + assert.equal( + e.std.range(upperRange).toEdgeQL(), `std::range({}, 8, inc_lower := true, inc_upper := false)` ); - expect(e.std.range(dateRange).toEdgeQL()).toEqual( + assert.equal( + e.std.range(dateRange).toEdgeQL(), `std::range('2022-07-05T14:00:00.000Z', '2022-07-05T16:00:00.000Z', inc_lower := true, inc_upper := false)` ); - expect(e.range(3, 8).toEdgeQL()).toEqual(`std::range(3, 8)`); - expect(e.range(3).toEdgeQL()).toEqual(`std::range(3)`); - expect(e.range(undefined, 8).toEdgeQL()).toEqual( - `std::range({}, 8)` - ); + assert.equal(e.range(3, 8).toEdgeQL(), `std::range(3, 8)`); + assert.equal(e.range(3).toEdgeQL(), `std::range(3)`); + assert.equal(e.range(undefined, 8).toEdgeQL(), `std::range({}, 8)`); expect(() => e.range(new edgedb.Range(null, null))).toThrow(); expect(() => e.range(edgedb.Range.empty())).toThrow(); @@ -98,7 +101,7 @@ test("range primitives", async () => { > >(true); - expect(res).toEqual({ + assert.deepEqual(res, { range: range, lowerRange: lowerRange, upperRange: new edgedb.Range(null, 8, false), @@ -110,7 +113,7 @@ test("range primitives", async () => { tc.assert< tc.IsExact<(typeof getLower)["__element__"]["__name__"], "std::number"> >(true); - expect(getLower.__element__.__name__).toEqual("std::number"); + assert.equal(getLower.__element__.__name__, "std::number"); const q2 = e.params( { @@ -133,7 +136,7 @@ test("range primitives", async () => { > >(true); - expect(res2).toEqual({ range: range, rangeArray: [dateRange] }); + assert.deepEqual(res2, { range: range, rangeArray: [dateRange] }); await e .insert(e.Bag, { @@ -154,12 +157,12 @@ test("range primitives", async () => { tc.assert[]>>(true); - expect(res3).toEqual([lowerRange]); + assert.deepEqual(res3, [lowerRange]); await e.delete(e.Bag).run(client); }); test("enum value with space", async () => { const result = await e.Genre["Science Fiction"].run(client); - expect(result).toEqual("Science Fiction"); + assert.equal(result, "Science Fiction"); }); diff --git a/packages/generate/test/queries.test.ts b/packages/generate/test/queries.test.ts index f9533a397..b23259736 100644 --- a/packages/generate/test/queries.test.ts +++ b/packages/generate/test/queries.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; @@ -44,5 +45,5 @@ test("basic select", async () => { > >(true); - expect(result.length).toEqual(2); + assert.equal(result.length, 2); }); diff --git a/packages/generate/test/select.test.ts b/packages/generate/test/select.test.ts index dfb8978e7..4adbf80c7 100644 --- a/packages/generate/test/select.test.ts +++ b/packages/generate/test/select.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import * as edgedb from "edgedb"; import * as $ from "../src/syntax/reflection"; import * as tc from "conditional-type-checks"; @@ -25,74 +26,72 @@ test("basic select", () => { test("selecting JS data", () => { const strSelect = e.select("test"); - expect(strSelect.__kind__).toBe($.ExpressionKind.Select); - expect(strSelect.__element__).toBe(e.str); - expect(strSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(strSelect.__kind__, $.ExpressionKind.Select); + assert.equal(strSelect.__element__, e.str); + assert.equal(strSelect.__cardinality__, $.Cardinality.One); const numberSelect = e.select(1234); - expect(numberSelect.__kind__).toBe($.ExpressionKind.Select); - expect(numberSelect.__element__.__name__).toBe(`std::number`); - expect(numberSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(numberSelect.__kind__, $.ExpressionKind.Select); + assert.equal(numberSelect.__element__.__name__, `std::number`); + assert.equal(numberSelect.__cardinality__, $.Cardinality.One); const boolSelect = e.select(false); - expect(boolSelect.__kind__).toBe($.ExpressionKind.Select); - expect(boolSelect.__element__).toBe(e.bool); - expect(boolSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(boolSelect.__kind__, $.ExpressionKind.Select); + assert.equal(boolSelect.__element__, e.bool); + assert.equal(boolSelect.__cardinality__, $.Cardinality.One); const bigintSelect = e.select(BigInt(1234)); - expect(bigintSelect.__kind__).toBe($.ExpressionKind.Select); - expect(bigintSelect.__element__).toBe(e.bigint); - expect(bigintSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(bigintSelect.__kind__, $.ExpressionKind.Select); + assert.equal(bigintSelect.__element__, e.bigint); + assert.equal(bigintSelect.__cardinality__, $.Cardinality.One); const bufferSelect = e.select(Buffer.from([])); - expect(bufferSelect.__kind__).toBe($.ExpressionKind.Select); - expect(bufferSelect.__element__).toBe(e.bytes); - expect(bufferSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(bufferSelect.__kind__, $.ExpressionKind.Select); + assert.equal(bufferSelect.__element__, e.bytes); + assert.equal(bufferSelect.__cardinality__, $.Cardinality.One); const dateSelect = e.select(new Date()); - expect(dateSelect.__kind__).toBe($.ExpressionKind.Select); - expect(dateSelect.__element__).toBe(e.datetime); - expect(dateSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(dateSelect.__kind__, $.ExpressionKind.Select); + assert.equal(dateSelect.__element__, e.datetime); + assert.equal(dateSelect.__cardinality__, $.Cardinality.One); const durationSelect = e.select(new edgedb.Duration()); - expect(durationSelect.__kind__).toBe($.ExpressionKind.Select); - expect(durationSelect.__element__).toBe(e.duration); - expect(durationSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(durationSelect.__kind__, $.ExpressionKind.Select); + assert.equal(durationSelect.__element__, e.duration); + assert.equal(durationSelect.__cardinality__, $.Cardinality.One); const ldrSelect = e.select(new edgedb.LocalDateTime(1, 2, 3)); - expect(ldrSelect.__kind__).toBe($.ExpressionKind.Select); - expect(ldrSelect.__element__).toBe(e.cal.local_datetime); - expect(ldrSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(ldrSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ldrSelect.__element__, e.cal.local_datetime); + assert.equal(ldrSelect.__cardinality__, $.Cardinality.One); const ldSelect = e.select(new edgedb.LocalDate(1, 2, 3)); - expect(ldSelect.__kind__).toBe($.ExpressionKind.Select); - expect(ldSelect.__element__).toBe(e.cal.local_date); - expect(ldSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(ldSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ldSelect.__element__, e.cal.local_date); + assert.equal(ldSelect.__cardinality__, $.Cardinality.One); const ltSelect = e.select(new edgedb.LocalTime(1, 2, 3)); - expect(ltSelect.__kind__).toBe($.ExpressionKind.Select); - expect(ltSelect.__element__).toBe(e.cal.local_time); - expect(ltSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(ltSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ltSelect.__element__, e.cal.local_time); + assert.equal(ltSelect.__cardinality__, $.Cardinality.One); const rdSelect = e.select(new edgedb.RelativeDuration(1, 2, 3)); - expect(rdSelect.__kind__).toBe($.ExpressionKind.Select); - expect(rdSelect.__element__).toBe(e.cal.relative_duration); - expect(rdSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(rdSelect.__kind__, $.ExpressionKind.Select); + assert.equal(rdSelect.__element__, e.cal.relative_duration); + assert.equal(rdSelect.__cardinality__, $.Cardinality.One); const memSelect = e.select(new edgedb.ConfigMemory(BigInt(1234))); - expect(memSelect.__kind__).toBe($.ExpressionKind.Select); - expect(memSelect.__element__).toBe(e.cfg.memory); - expect(memSelect.__cardinality__).toBe($.Cardinality.One); + assert.equal(memSelect.__kind__, $.ExpressionKind.Select); + assert.equal(memSelect.__element__, e.cfg.memory); + assert.equal(memSelect.__cardinality__, $.Cardinality.One); }); test("no shape", async () => { const query = e.select(e.default.Hero); const result = await query.run(client); tc.assert>(true); - expect(query.__element__.__shape__).toEqual( - e.default.Hero.__element__.__shape__ - ); - expect(result.every((val) => !!val.id)).toEqual(true); + assert.deepEqual(query.__element__.__shape__, e.default.Hero.__element__.__shape__); + assert.equal(result.every((val) => !!val.id), true); }); test("computed only shape", () => { @@ -118,7 +117,7 @@ type q1 = $.setToTsType; test("path construction", () => { const result = e.select(e.default.Hero); - expect(result.villains.nemesis.name.__element__.__name__).toEqual("std::str"); + assert.equal(result.villains.nemesis.name.__element__.__name__, "std::str"); }); test("complex shape", () => { @@ -183,7 +182,7 @@ test("compositionality", () => { type no_shape = $.BaseTypeToTsType<(typeof no_shape)["__element__"]>; type q1 = $.BaseTypeToTsType<(typeof q1)["__element__"]>; tc.assert>(true); - expect(no_shape.__element__.__shape__).toEqual(q1.__element__.__shape__); + assert.deepEqual(no_shape.__element__.__shape__, q1.__element__.__shape__); // expect(no_shape.__element__.__shape__).toEqual({id: true}); // allow override shape @@ -216,9 +215,9 @@ test("polymorphism", () => { })); // query.__element__. - expect(query.__kind__).toEqual($.ExpressionKind.Select); - expect(query.__element__.__kind__).toEqual($.TypeKind.object); - expect(query.__element__.__name__).toEqual("default::Person"); + assert.deepEqual(query.__kind__, $.ExpressionKind.Select); + assert.deepEqual(query.__element__.__kind__, $.TypeKind.object); + assert.equal(query.__element__.__name__, "default::Person"); type result = $.BaseTypeToTsType<(typeof query)["__element__"]>; tc.assert< @@ -338,31 +337,31 @@ test("limit/offset inference", () => { tc.assert< tc.IsExact<(typeof testSet)["__cardinality__"], $.Cardinality.AtLeastOne> >(true); - expect(testSet.__cardinality__).toEqual($.Cardinality.AtLeastOne); + assert.deepEqual(testSet.__cardinality__, $.Cardinality.AtLeastOne); const r0 = e.select(testSet, () => ({})); tc.assert< tc.IsExact<(typeof r0)["__cardinality__"], $.Cardinality.AtLeastOne> >(true); - expect(r0.__cardinality__).toEqual($.Cardinality.AtLeastOne); + assert.deepEqual(r0.__cardinality__, $.Cardinality.AtLeastOne); const r1 = e.select(testSet, () => ({ limit: 1 })); tc.assert>( true ); - expect(r1.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(r1.__cardinality__, $.Cardinality.Many); const r2 = e.select(testSet, () => ({ offset: 1 })); tc.assert>( true ); - expect(r2.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(r2.__cardinality__, $.Cardinality.Many); }); test("offset", () => { const q = e.select(e.Hero, () => ({ name: true })); const r1 = e.select(q, () => ({ offset: 5 })); - expect(r1.__modifiers__.offset?.__element__.__name__).toEqual("std::number"); + assert.equal(r1.__modifiers__.offset?.__element__.__name__, "std::number"); }); test("infer cardinality - scalar filters", () => { @@ -373,7 +372,7 @@ test("infer cardinality - scalar filters", () => { tc.assert< tc.IsExact<(typeof q2)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q2.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q2.__cardinality__, $.Cardinality.AtMostOne); const u3 = e.uuid("asdf"); const q3 = e.select(q, (hero) => { @@ -382,13 +381,13 @@ test("infer cardinality - scalar filters", () => { tc.assert< tc.IsExact<(typeof q3)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q3.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q3.__cardinality__, $.Cardinality.AtMostOne); const q4 = q2.secret_identity; tc.assert< tc.IsExact<(typeof q4)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q4.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q4.__cardinality__, $.Cardinality.AtMostOne); const q5 = e.select(q, (hero) => ({ filter: e.op(hero.secret_identity, "=", "asdf"), @@ -396,7 +395,7 @@ test("infer cardinality - scalar filters", () => { tc.assert>( true ); - expect(q5.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(q5.__cardinality__, $.Cardinality.Many); const q6 = e.select(e.Villain.nemesis, (nemesis) => ({ filter_single: e.op(nemesis.name, "=", "asdf"), @@ -404,7 +403,7 @@ test("infer cardinality - scalar filters", () => { tc.assert< tc.IsExact<(typeof q6)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q6.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q6.__cardinality__, $.Cardinality.AtMostOne); const strs = e.set(e.str("asdf"), e.str("qwer")); const q7 = e.select(e.Villain, (villain) => ({ @@ -413,7 +412,7 @@ test("infer cardinality - scalar filters", () => { tc.assert>( true ); - expect(q7.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(q7.__cardinality__, $.Cardinality.Many); const expr8 = e.select(e.Villain, () => ({ id: true, name: true })); const q8 = e.select(expr8, (villain) => ({ @@ -422,7 +421,7 @@ test("infer cardinality - scalar filters", () => { tc.assert< tc.IsExact<(typeof q8)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q8.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q8.__cardinality__, $.Cardinality.AtMostOne); const expr9 = e.select(e.Villain, () => ({ id: true, name: true })); const q9 = e.select(expr9, (villain) => ({ @@ -431,7 +430,7 @@ test("infer cardinality - scalar filters", () => { tc.assert< tc.IsExact<(typeof q9)["__cardinality__"], $.Cardinality.AtMostOne> >(true); - expect(q9.__cardinality__).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(q9.__cardinality__, $.Cardinality.AtMostOne); // const q10 = e.select(e.Villain, villain => ({ // filter_single: e.op(villain.name, "=", e.cast(e.str, e.set())) @@ -451,7 +450,7 @@ test("infer cardinality - object type filters", () => { const c1 = singleHero.__cardinality__; tc.assert>(true); - expect(c1).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(c1, $.Cardinality.AtMostOne); const oneProfile = e.select(e.Hero, () => ({ limit: 1 })).assert_single(); const singleMovie = e.select(e.Movie, (movie) => ({ @@ -460,7 +459,7 @@ test("infer cardinality - object type filters", () => { const c2 = singleMovie.__cardinality__; tc.assert>(true); - expect(c2).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(c2, $.Cardinality.AtMostOne); // not a singleton @@ -468,7 +467,7 @@ test("infer cardinality - object type filters", () => { filter: e.op(villain.nemesis, "=", oneHero), })).__cardinality__; tc.assert>(true); - expect(c3).toEqual($.Cardinality.Many); + assert.deepEqual(c3, $.Cardinality.Many); // not a singleton // technically a bug, but for now this behavior is expected @@ -476,7 +475,7 @@ test("infer cardinality - object type filters", () => { filter_single: e.op(villain, "=", villain), })).__cardinality__; tc.assert>(true); - expect(c4).toEqual($.Cardinality.AtMostOne); + assert.deepEqual(c4, $.Cardinality.AtMostOne); }); test("non 'e.eq' filters", () => { @@ -486,7 +485,7 @@ test("non 'e.eq' filters", () => { tc.assert>( true ); - expect(q1.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(q1.__cardinality__, $.Cardinality.Many); const q2 = e.select(e.Hero, (hero) => ({ filter: e.op(true, "if", e.op(hero.name, "=", "Thanos"), "else", false), @@ -494,13 +493,13 @@ test("non 'e.eq' filters", () => { tc.assert>( true ); - expect(q2.__cardinality__).toEqual($.Cardinality.Many); + assert.deepEqual(q2.__cardinality__, $.Cardinality.Many); }); test("fetch heroes", async () => { const result = await e.select(e.Hero).run(client); - expect(result.length).toEqual(3); - expect(result.every((h) => typeof h.id === "string")).toEqual(true); + assert.equal(result.length, 3); + assert.equal(result.every((h) => typeof h.id === "string"), true); }); test("filter by id", async () => { @@ -510,7 +509,7 @@ test("filter by id", async () => { })) .run(client); - expect(result?.id).toEqual(data.spidey.id); + assert.deepEqual(result?.id, data.spidey.id); }); test("filter by id expr", async () => { @@ -520,7 +519,7 @@ test("filter by id expr", async () => { })) .run(client); - expect(result?.id).toEqual(data.spidey.id); + assert.deepEqual(result?.id, data.spidey.id); }); test("limit 1", async () => { @@ -532,7 +531,7 @@ test("limit 1", async () => { })) .assert_single(); const result = await e.select(query).run(client); - expect(result?.id).toEqual(data.iron_man.id); + assert.deepEqual(result?.id, data.iron_man.id); }); test("limit 2", async () => { @@ -543,8 +542,8 @@ test("limit 2", async () => { })); const results = await query.run(client); - expect(results.length).toEqual(2); - expect(results).toEqual([{ id: data.iron_man.id }, { id: data.spidey.id }]); + assert.equal(results.length, 2); + assert.deepEqual(results, [{ id: data.iron_man.id }, { id: data.spidey.id }]); }); test("order by self", async () => { @@ -552,11 +551,9 @@ test("order by self", async () => { order_by: hero, })); const result = await query.run(client); - expect(result).toEqual( - [data.cap, data.spidey, data.iron_man] - .map((h) => ({ id: h.id })) - .sort((a, b) => a.id.localeCompare(b.id)) - ); + assert.deepEqual(result, [data.cap, data.spidey, data.iron_man] + .map((h) => ({ id: h.id })) + .sort((a, b) => a.id.localeCompare(b.id))); }); test("shapes", async () => { @@ -574,7 +571,7 @@ test("shapes", async () => { const result = await query.run(client); expect(result).toMatchObject(data.iron_man); - expect(result?.villains).toEqual([{ id: data.thanos.id }]); + assert.deepEqual(result?.villains, [{ id: data.thanos.id }]); }); test("computables", async () => { @@ -612,8 +609,8 @@ test("computables", async () => { >(true); const results = await query.run(client); - expect(results?.id).toEqual(data.cap.id); - expect(results?.computable).toEqual(35); + assert.deepEqual(results?.id, data.cap.id); + assert.equal(results?.computable, 35); // expect( // results?.all_heroes.every(hero => hero.__type__.name === "default::Hero") // ).toEqual(true); @@ -625,9 +622,7 @@ test("type intersections", async () => { // __type__: {name: true}, })); const results = await query.run(client); - expect(results.every((person) => typeof person.id === "string")).toEqual( - true - ); + assert.equal(results.every((person) => typeof person.id === "string"), true); // expect( // results.every(person => person.__type__.name === "default::Hero") // ).toEqual(true); @@ -656,11 +651,12 @@ test("backlinks", async () => { const result2 = await q2.run(client); - expect(result1).toEqual(result2); - expect(Array.isArray(result1)).toEqual(true); - expect( - [data.the_avengers.title, data.civil_war.title].includes(result1[0].title) - ).toEqual(true); + assert.deepEqual(result1, result2); + assert.equal(Array.isArray(result1), true); + assert.equal( + [data.the_avengers.title, data.civil_war.title].includes(result1[0].title), + true + ); const q3 = e.select(e.Hero, (hero) => ({ " { >(true); for (const hero of res3) { - expect(hero[" { const res1 = await q1.run(client); - expect(res1).not.toBeNull(); - expect(res1!.villains.length).toBe(1); + assert.ok(res1); + assert.equal(res1!.villains.length, 1); const q2 = e.select(e.Hero, (hero) => ({ name: true, @@ -823,8 +819,8 @@ test("filters in subqueries", async () => { const res2 = await q2.run(client); - expect(res2).not.toBeNull(); - expect(res2!.villains.length).toBe(0); + assert.ok(res2); + assert.equal(res2!.villains.length, 0); tc.assert< tc.IsExact< @@ -866,11 +862,11 @@ test("filters in subqueries", async () => { // q3.__modifiers__. const res3 = await q3.run(client); - expect(Array.isArray(res3)).toBe(true); + assert.equal(Array.isArray(res3), true); const ironMan = res3.find((r) => r.name === "Iron Man"); - expect(ironMan).not.toBeUndefined(); - expect(Array.isArray(ironMan!.villains)).toBe(true); - expect(Array.isArray(ironMan!.thanos)).toBe(false); + assert.ok(ironMan); + assert.equal(Array.isArray(ironMan!.villains), true); + assert.equal(Array.isArray(ironMan!.thanos), false); tc.assert< tc.IsExact< @@ -916,7 +912,7 @@ test("repeated computed", async () => { }, })); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __scope_0_defaultVillain := DETACHED default::Villain SELECT __scope_0_defaultVillain { id, @@ -979,7 +975,7 @@ test("polymorphic subqueries", async () => { }), })); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __scope_0_defaultPerson := DETACHED default::Movie.characters SELECT __scope_0_defaultPerson { id, @@ -1052,7 +1048,7 @@ test("polymorphic field in nested shape", async () => { })); const result = await query.run(client); - expect(JSON.parse(JSON.stringify(result))).toEqual({ + assert.deepEqual(JSON.parse(JSON.stringify(result)), { title: data.the_avengers.title, characters: [ { @@ -1089,15 +1085,14 @@ test("correlated path select", async () => { const heros = [data.cap, data.iron_man, data.spidey]; - expect((await query.run(client)).sort()).toEqual( - $.util - .flatMap(heros, (h1) => - heros.map((h2) => `${h1.name} is ${h2.secret_identity}`) - ) - .sort() - ); + assert.deepEqual((await query.run(client)).sort(), $.util + .flatMap(heros, (h1) => + heros.map((h2) => `${h1.name} is ${h2.secret_identity}`) + ) + .sort()); - expect((await correlatedQuery.run(client)).sort()).toEqual( + assert.deepEqual( + (await correlatedQuery.run(client)).sort(), heros.map((h) => `${h.name} is ${h.secret_identity}`).sort() ); }); @@ -1109,7 +1104,7 @@ test("modifiers on scalar selects", async () => { })); const res1 = await q1.run(client); tc.assert>(true); - expect(res1.sort()).toEqual([data.iron_man.name, data.spidey.name].sort()); + assert.deepEqual(res1.sort(), [data.iron_man.name, data.spidey.name].sort()); // order const unorderedSet = e.set( @@ -1125,14 +1120,14 @@ test("modifiers on scalar selects", async () => { })); const res2 = await q2.run(client); tc.assert>(true); - expect(res2).toEqual([1, 2, 3, 4, 5]); + assert.deepEqual(res2, [1, 2, 3, 4, 5]); const q3 = e.select(unorderedSet, (el) => ({ order_by: { expression: el, direction: e.DESC }, })); const res3 = await q3.run(client); tc.assert>(true); - expect(res3).toEqual([5, 4, 3, 2, 1]); + assert.deepEqual(res3, [5, 4, 3, 2, 1]); // offset and limit const q4 = e @@ -1143,7 +1138,7 @@ test("modifiers on scalar selects", async () => { .assert_single(); const res4 = await e.select(q4).run(client); tc.assert>(true); - expect(res4).toEqual(1); + assert.equal(res4, 1); }); test("nested matching scopes", async () => { @@ -1169,13 +1164,13 @@ test("nested matching scopes", async () => { })), })); - expect(JSON.stringify(result)).toEqual(JSON.stringify(expectedResult)); + assert.deepEqual(JSON.stringify(result), JSON.stringify(expectedResult)); }); test("runnable expressions", async () => { const expr = e.op("Hello ", "++", "World"); - expect(await expr.run(client)).toEqual(`Hello World`); + assert.equal(await expr.run(client), `Hello World`); }); test("computed property path", async () => { @@ -1185,7 +1180,7 @@ test("computed property path", async () => { }); const query = e.select(expr.numbers); - expect(await query.run(client)).toEqual([1, 2, 3]); + assert.deepEqual(await query.run(client), [1, 2, 3]); }); test("select with enums", async () => { @@ -1195,7 +1190,7 @@ test("select with enums", async () => { filter: e.op(movie.genre, "=", e.Genre.Action), })); const result = await query.run(client); - expect(result.length).toEqual(2); + assert.equal(result.length, 2); }); test("filter by sequence", async () => { @@ -1215,7 +1210,7 @@ test("select *", async () => { })) .run(client); - expect(allFields).toEqual([ + assert.deepEqual(allFields, [ { ...data.the_avengers, characters: undefined, @@ -1256,9 +1251,7 @@ test("filter on link prop in nested path", async () => { test("cardinality of linkprop in scopified object", async () => { const query = e.select(e.Movie.characters, (c) => { - expect(c["@character_name"].__cardinality__).toEqual( - $.Cardinality.AtMostOne - ); + assert.deepEqual(c["@character_name"].__cardinality__, $.Cardinality.AtMostOne); return { name: true, // doesn't work yet @@ -1281,8 +1274,8 @@ test("portable shape", async () => { }); const result = await query.run(client); - expect(result?.rating).toBeDefined(); - expect(result?.characters).toBeDefined(); + assert.ok(result?.rating); + assert.ok(result?.characters); }); test("filter_single id", async () => { @@ -1291,7 +1284,7 @@ test("filter_single id", async () => { filter_single: { title: "The Avengers" }, })); const result = await query.run(client); - expect(result?.title).toEqual("The Avengers"); + assert.equal(result?.title, "The Avengers"); }); test("filter_single exclusive prop", async () => { @@ -1300,7 +1293,7 @@ test("filter_single exclusive prop", async () => { filter_single: { title: "The Avengers" }, })); const result = await query.run(client); - expect(result?.title).toEqual("The Avengers"); + assert.equal(result?.title, "The Avengers"); }); test("filter_single composite", async () => { @@ -1309,7 +1302,7 @@ test("filter_single composite", async () => { filter_single: { title: "The Avengers", release_year: 2012 }, })); const result = await query.run(client); - expect(result?.title).toEqual("The Avengers"); + assert.equal(result?.title, "The Avengers"); }); test("filter_single composite truple", async () => { diff --git a/packages/generate/test/sets.test.ts b/packages/generate/test/sets.test.ts index 92533638d..f1b493981 100644 --- a/packages/generate/test/sets.test.ts +++ b/packages/generate/test/sets.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import { $, Client } from "edgedb"; import { tc } from "./setupTeardown"; import e, { $infer } from "../dbschema/edgeql-js"; @@ -17,108 +18,104 @@ afterAll(async () => { }); test("empty sets", async () => { - expect(e.set()).toEqual(null); + assert.equal(e.set(), null); const stringSet = e.cast(e.str, e.set()); - expect(stringSet.toEdgeQL()).toEqual(`{}`); + assert.equal(stringSet.toEdgeQL(), `{}`); tc.assert, null>>(true); const $Hero = e.Hero.__element__; const heroSet = e.cast($Hero, e.set()); - expect(heroSet.toEdgeQL()).toEqual(`{}`); + assert.equal(heroSet.toEdgeQL(), `{}`); tc.assert, null>>(true); const int32Set = e.cast(e.int32, e.set()); - expect(int32Set.toEdgeQL()).toEqual(`{}`); + assert.equal(int32Set.toEdgeQL(), `{}`); tc.assert, null>>(true); tc.assert< tc.IsExact<(typeof int32Set)["__element__"]["__name__"], "std::number"> >(true); - expect(await e.cast(e.int64, e.set()).run(client)).toEqual(null); + assert.equal(await e.cast(e.int64, e.set()).run(client), null); }); test("object set contructor", async () => { const hero = e.set(e.default.Hero); - expect(hero.id.__element__.__name__).toEqual("std::uuid"); - expect(hero.name.__element__.__name__).toEqual("std::str"); - expect(hero.number_of_movies.__element__.__name__).toEqual("std::int64"); + assert.equal(hero.id.__element__.__name__, "std::uuid"); + assert.equal(hero.name.__element__.__name__, "std::str"); + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); const person = e.set(e.default.Hero, e.default.Villain); - expect(person.id.__element__.__name__).toEqual("std::uuid"); - expect(person.name.__element__.__name__).toEqual("std::str"); - expect((person as any).number_of_movies).toEqual(undefined); - expect(person.__element__.__name__).toEqual( - "default::Hero UNION default::Villain" - ); + assert.equal(person.id.__element__.__name__, "std::uuid"); + assert.equal(person.name.__element__.__name__, "std::str"); + assert.deepEqual((person as any).number_of_movies, undefined); + assert.equal(person.__element__.__name__, "default::Hero UNION default::Villain"); const merged = e.set(e.default.Hero, e.default.Villain, e.default.Person); - expect(merged.__element__.__name__).toEqual( + assert.equal( + merged.__element__.__name__, "default::Hero UNION default::Villain UNION default::Person" ); - expect(e.set(e.select(e.Hero), e.select(e.Villain)).toEdgeQL()).toEqual( + assert.equal( + e.set(e.select(e.Hero), e.select(e.Villain)).toEdgeQL(), `{ (SELECT DETACHED default::Hero), (SELECT DETACHED default::Villain) }` ); - expect( - await e - .select(e.set(e.select(e.Hero), e.select(e.Villain)), (obj) => ({ - name: true, - filter: e.op(obj.name, "=", "Thanos"), - })) - .assert_single() - .run(client) - ).toEqual({ name: "Thanos" }); - - expect( - await e - .select(e.set(e.Hero, e.Villain), (obj) => ({ - name: true, - filter: e.op(obj.name, "=", "Thanos"), - })) - .assert_single() - .run(client) - ).toEqual({ name: "Thanos" }); + assert.deepEqual(await e + .select(e.set(e.select(e.Hero), e.select(e.Villain)), (obj) => ({ + name: true, + filter: e.op(obj.name, "=", "Thanos"), + })) + .assert_single() + .run(client), { name: "Thanos" }); + + assert.deepEqual(await e + .select(e.set(e.Hero, e.Villain), (obj) => ({ + name: true, + filter: e.op(obj.name, "=", "Thanos"), + })) + .assert_single() + .run(client), { name: "Thanos" }); }); test("scalar set contructor", () => { // single elements const _f1 = e.set("asdf"); - expect(_f1.__element__.__name__).toEqual("std::str"); - expect(_f1.__cardinality__).toEqual($.Cardinality.One); - expect(_f1.__element__.__kind__).toEqual($.TypeKind.scalar); - expect(_f1.toEdgeQL()).toEqual(`{ "asdf" }`); + assert.equal(_f1.__element__.__name__, "std::str"); + assert.deepEqual(_f1.__cardinality__, $.Cardinality.One); + assert.deepEqual(_f1.__element__.__kind__, $.TypeKind.scalar); + assert.equal(_f1.toEdgeQL(), `{ "asdf" }`); type _f1 = $infer; tc.assert>(true); const _f4 = e.set(e.int32(42)); - expect(_f4.__element__.__name__).toEqual("std::int32"); - expect(_f4.__cardinality__).toEqual($.Cardinality.One); - expect(_f4.__element__.__kind__).toEqual($.TypeKind.scalar); - expect(_f4.toEdgeQL()).toEqual(`{ 42 }`); + assert.equal(_f4.__element__.__name__, "std::int32"); + assert.deepEqual(_f4.__cardinality__, $.Cardinality.One); + assert.deepEqual(_f4.__element__.__kind__, $.TypeKind.scalar); + assert.equal(_f4.toEdgeQL(), `{ 42 }`); type _f4 = $infer; tc.assert>(true); // multiple elements const _f2 = e.set("asdf", "qwer", e.str("poiu")); - expect(_f2.__element__.__name__).toEqual("std::str"); - expect(_f2.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(_f2.toEdgeQL()).toEqual(`{ "asdf", "qwer", "poiu" }`); + assert.equal(_f2.__element__.__name__, "std::str"); + assert.deepEqual(_f2.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(_f2.toEdgeQL(), `{ "asdf", "qwer", "poiu" }`); type _f2 = $infer; tc.assert>(true); const _f3 = e.set(1, 2, 3); - expect(_f3.__element__.__name__).toEqual("std::number"); - expect(_f3.__cardinality__).toEqual($.Cardinality.AtLeastOne); - expect(_f3.toEdgeQL()).toEqual(`{ 1, 2, 3 }`); + assert.equal(_f3.__element__.__name__, "std::number"); + assert.deepEqual(_f3.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(_f3.toEdgeQL(), `{ 1, 2, 3 }`); type _f3 = $infer; tc.assert>(true); // implicit casting const _f5 = e.set(5, e.literal(e.float32, 1234.5)); - expect(_f5.__element__.__name__).toEqual("std::number"); - expect(_f5.toEdgeQL()).toEqual(`{ 5, 1234.5 }`); + assert.equal(_f5.__element__.__name__, "std::number"); + assert.equal(_f5.toEdgeQL(), `{ 5, 1234.5 }`); type _f5 = $infer; tc.assert>(true); }); @@ -145,7 +142,8 @@ test("invalid sets", () => { test("enums", () => { const query = e.set(e.Genre.Action, e.Genre.Horror, e.Genre.Select); - expect(query.toEdgeQL()).toEqual( + assert.equal( + query.toEdgeQL(), "{ default::Genre.Action, default::Genre.Horror, default::Genre.`Select` }" ); @@ -157,9 +155,9 @@ test("tuples", async () => { e.tuple([1, "asdf", e.int16(214)]), e.tuple([3, "asdf", e.int64(5)]) ); - expect(q1.__element__.__kind__).toEqual(TypeKind.tuple); - expect(q1.__element__.__items__[0].__name__).toEqual("std::number"); - expect(q1.__element__.__items__[1].__name__).toEqual("std::str"); + assert.deepEqual(q1.__element__.__kind__, TypeKind.tuple); + assert.equal(q1.__element__.__items__[0].__name__, "std::number"); + assert.equal(q1.__element__.__items__[1].__name__, "std::str"); expect(await q1.run(client)).toMatchObject([ [1, "asdf", 214], [3, "asdf", 5], @@ -174,7 +172,7 @@ test("named tuples", async () => { e.tuple({ a: 1, b: "asdf", c: e.int16(214) }), e.tuple({ a: 3, b: "asdf", c: e.int64(5) }) ); - expect(q1.__element__.__kind__).toEqual(TypeKind.namedtuple); + assert.deepEqual(q1.__element__.__kind__, TypeKind.namedtuple); expect(await q1.run(client)).toMatchObject([ { a: 1, b: "asdf", c: 214 }, { a: 3, b: "asdf", c: 5 }, @@ -190,9 +188,9 @@ test("named tuples", async () => { test("array", async () => { const q1 = e.set(e.array([e.int16(5), e.int64(67)]), e.array([6])); - expect(q1.__element__.__kind__).toEqual(TypeKind.array); + assert.deepEqual(q1.__element__.__kind__, TypeKind.array); - expect(await q1.run(client)).toEqual([[5, 67], [6]]); + assert.deepEqual(await q1.run(client), [[5, 67], [6]]); expect(() => e.set(e.array([e.int16(5)]), e.array(["asdf"]) as any) diff --git a/packages/generate/test/update.test.ts b/packages/generate/test/update.test.ts index 6e11635fb..2769d18ef 100644 --- a/packages/generate/test/update.test.ts +++ b/packages/generate/test/update.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; @@ -92,16 +93,14 @@ test("scoped update", async () => { const result = await query.run(client); tc.assert>(true); - expect(result).toEqual({ id: data.spidey.id }); + assert.deepEqual(result, { id: data.spidey.id }); - expect( - await e - .select(e.Hero, (hero) => ({ - name: true, - filter_single: e.op(hero.id, "=", e.uuid(result!.id)), - })) - .run(client) - ).toEqual({ name: `The Amazing ${data.spidey.name}` }); + assert.deepEqual(await e + .select(e.Hero, (hero) => ({ + name: true, + filter_single: e.op(hero.id, "=", e.uuid(result!.id)), + })) + .run(client), { name: `The Amazing ${data.spidey.name}` }); }); test("update link property", async () => { @@ -116,7 +115,7 @@ test("update link property", async () => { .select(theAvengers, () => ({ id: true, characters: true })) .run(client); - expect(qq1?.characters.length).toEqual(2); + assert.equal(qq1?.characters.length, 2); const q2 = e.update(theAvengers, () => ({ set: { @@ -132,7 +131,7 @@ test("update link property", async () => { const t2 = await e .select(theAvengers, () => ({ id: true, characters: true })) .run(client); - expect(t2?.characters.length).toEqual(3); + assert.equal(t2?.characters.length, 3); await e .update(theAvengers, () => ({ @@ -149,7 +148,7 @@ test("update link property", async () => { const t3 = await e .select(theAvengers, () => ({ id: true, characters: true })) .run(client); - expect(t3?.characters.length).toEqual(2); + assert.equal(t3?.characters.length, 2); await e .update(theAvengers, () => ({ @@ -162,7 +161,7 @@ test("update link property", async () => { const t4 = await e .select(theAvengers, () => ({ id: true, characters: true })) .run(client); - expect(t4?.characters.length).toEqual(0); + assert.equal(t4?.characters.length, 0); await e .update(theAvengers, () => ({ @@ -181,7 +180,7 @@ test("update link property", async () => { const t5 = await e .select(theAvengers, () => ({ id: true, characters: true })) .run(client); - expect(t5?.characters.length).toEqual(2); + assert.equal(t5?.characters.length, 2); }); test("optional prop update", async () => { diff --git a/packages/generate/test/with.test.ts b/packages/generate/test/with.test.ts index 05f4c902a..5270f93ed 100644 --- a/packages/generate/test/with.test.ts +++ b/packages/generate/test/with.test.ts @@ -1,3 +1,4 @@ +import assert from "node:assert/strict"; import type * as $ from "../src/syntax/reflection"; import e from "../dbschema/edgeql-js"; import { tc } from "./setupTeardown"; @@ -5,7 +6,7 @@ import { tc } from "./setupTeardown"; test("simple repeated expression", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect(e.select(e.op(numbers, "+", numbers)).toEdgeQL()).toEqual(`WITH + assert.equal(e.select(e.op(numbers, "+", numbers)).toEdgeQL(), `WITH __withVar_0 := { 1, 2, 3 } SELECT (__withVar_0 + __withVar_0)`); }); @@ -13,8 +14,7 @@ SELECT (__withVar_0 + __withVar_0)`); test("simple expression with alias", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect(e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL()) - .toEqual(`WITH + assert.equal(e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL(), `WITH __withVar_0 := { 1, 2, 3 }, __withVar_1 := __withVar_0 SELECT (__withVar_0 + __withVar_1)`); @@ -38,7 +38,7 @@ test("implicit WITH vars referencing each other", () => { hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), }); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __withVar_4 := 10, __withVar_3 := ( WITH @@ -89,7 +89,7 @@ test("simple repeated expression not in select expr", () => { test("explicit WITH block", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect(e.with([numbers], e.select(numbers)).toEdgeQL()).toEqual(`WITH + assert.equal(e.with([numbers], e.select(numbers)).toEdgeQL(), `WITH __withVar_0 := { 1, 2, 3 } SELECT __withVar_0`); }); @@ -97,13 +97,11 @@ SELECT __withVar_0`); test("explicit WITH block in nested query", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect( - e - .select({ - nested: e.with([numbers], e.select(numbers)), - }) - .toEdgeQL() - ).toEqual(`SELECT { + assert.equal(e + .select({ + nested: e.with([numbers], e.select(numbers)), + }) + .toEdgeQL(), `SELECT { multi nested := assert_exists(( WITH __withVar_0 := { 1, 2, 3 } @@ -130,14 +128,12 @@ test("explicit WITH block nested in implicit WITH block", () => { const explicitWith = e.with([numbers], e.select(numbers)); - expect( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -154,16 +150,14 @@ test("explicit WITH block nested in explicit WITH block", () => { const explicitWith = e.with([numbers], e.select(numbers)); - expect( - e - .with( - [explicitWith], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .with( + [explicitWith], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -180,16 +174,14 @@ test("explicit WITH block nested in explicit WITH block, sub expr explicitly ext const explicitWith = e.with([numbers], e.select(numbers)); - expect( - e - .with( - [explicitWith, number], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .with( + [explicitWith, number], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -225,17 +217,15 @@ test("explicit WITH block nested in explicit WITH block, sub expr implicitly ext const explicitWith = e.with([numbers], e.select(numbers)); - expect( - e - .with( - [explicitWith], - e.select({ - number, - numbers: explicitWith, - }) - ) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .with( + [explicitWith], + e.select({ + number, + numbers: explicitWith, + }) + ) + .toEdgeQL(), `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -268,7 +258,7 @@ test("implicit WITH and explicit WITH in sub expr", () => { hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), }); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __withVar_5 := 10, __withVar_4 := ( WITH @@ -306,14 +296,12 @@ test("explicit WITH nested in implicit WITH + alias implicit", () => { const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - expect( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -339,14 +327,12 @@ test("explicit WITH nested in implicit WITH + alias explicit", () => { e.select({ numbers, numbersAlias }) ); - expect( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -395,16 +381,14 @@ test( e.select(e.op(numbers, "+", numbersAlias)) ); - expect( - e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), `WITH __withVar_1 := { 1, 2, 3 }, __withVar_0 := ( WITH @@ -432,16 +416,14 @@ test( e.select(e.op(numbers, "+", numbersAlias2)) ); - expect( - e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL() - ).toEqual(`WITH + assert.equal(e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), `WITH __withVar_1 := { 1, 2, 3 }, __withVar_2 := __withVar_1, __withVar_0 := ( @@ -464,29 +446,27 @@ test("query with no WITH block", () => { limit: 1, })); - expect(query.toEdgeQL()).toEqual( - `WITH - __scope_0_defaultHero := DETACHED default::Person[IS default::Hero] + assert.equal(query.toEdgeQL(), `WITH +__scope_0_defaultHero := DETACHED default::Person[IS default::Hero] SELECT __scope_0_defaultHero { - id, - single computable := 35, - multi all_heroes := ( - WITH - __scope_1_defaultHero := DETACHED default::Hero - SELECT __scope_1_defaultHero { - __type__ := ( - WITH - __scope_2_schemaObjectType := __scope_1_defaultHero.__type__ - SELECT __scope_2_schemaObjectType { - name - } - ) - } - ) +id, +single computable := 35, +multi all_heroes := ( + WITH + __scope_1_defaultHero := DETACHED default::Hero + SELECT __scope_1_defaultHero { + __type__ := ( + WITH + __scope_2_schemaObjectType := __scope_1_defaultHero.__type__ + SELECT __scope_2_schemaObjectType { + name + } + ) + } +) } ORDER BY __scope_0_defaultHero.name -LIMIT 1` - ); +LIMIT 1`); }); test("repeated expression referencing scoped select object", () => { @@ -503,7 +483,7 @@ test("repeated expression referencing scoped select object", () => { }; }); - expect(query.toEdgeQL()).toEqual(`WITH + assert.equal(query.toEdgeQL(), `WITH __scope_0_defaultHero_expr := DETACHED default::Hero, __scope_0_defaultHero := (FOR __scope_0_defaultHero_inner IN {__scope_0_defaultHero_expr} UNION ( WITH From f15797f803f4377f901bf1301216c34fc63e8410 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 15:00:16 -0400 Subject: [PATCH 03/20] Fix select tests --- packages/generate/test/select.test.ts | 2363 ++++++++++++------------- 1 file changed, 1157 insertions(+), 1206 deletions(-) diff --git a/packages/generate/test/select.test.ts b/packages/generate/test/select.test.ts index 4adbf80c7..a2b028a49 100644 --- a/packages/generate/test/select.test.ts +++ b/packages/generate/test/select.test.ts @@ -3,755 +3,743 @@ import * as edgedb from "edgedb"; import * as $ from "../src/syntax/reflection"; import * as tc from "conditional-type-checks"; -import e, { $infer } from "../dbschema/edgeql-js"; -import { setupTests, teardownTests, TestData } from "./setupTeardown"; +import e, { type $infer } from "../dbschema/edgeql-js"; +import { setupTests, teardownTests, type TestData } from "./setupTeardown"; import { CardinalityViolationError } from "edgedb"; let client: edgedb.Client; let data: TestData; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); +describe("select", () => { + beforeAll(async () => { + const setup = await setupTests(); + ({ client, data } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("basic select", () => { - const result = e.select(e.std.str("asdf")); - type result = $infer; - tc.assert>(true); -}); + test("basic select", () => { + const result = e.select(e.std.str("asdf")); + type result = $infer; + tc.assert>(true); + }); -test("selecting JS data", () => { - const strSelect = e.select("test"); - assert.equal(strSelect.__kind__, $.ExpressionKind.Select); - assert.equal(strSelect.__element__, e.str); - assert.equal(strSelect.__cardinality__, $.Cardinality.One); - - const numberSelect = e.select(1234); - assert.equal(numberSelect.__kind__, $.ExpressionKind.Select); - assert.equal(numberSelect.__element__.__name__, `std::number`); - assert.equal(numberSelect.__cardinality__, $.Cardinality.One); - - const boolSelect = e.select(false); - assert.equal(boolSelect.__kind__, $.ExpressionKind.Select); - assert.equal(boolSelect.__element__, e.bool); - assert.equal(boolSelect.__cardinality__, $.Cardinality.One); - - const bigintSelect = e.select(BigInt(1234)); - assert.equal(bigintSelect.__kind__, $.ExpressionKind.Select); - assert.equal(bigintSelect.__element__, e.bigint); - assert.equal(bigintSelect.__cardinality__, $.Cardinality.One); - - const bufferSelect = e.select(Buffer.from([])); - assert.equal(bufferSelect.__kind__, $.ExpressionKind.Select); - assert.equal(bufferSelect.__element__, e.bytes); - assert.equal(bufferSelect.__cardinality__, $.Cardinality.One); - - const dateSelect = e.select(new Date()); - assert.equal(dateSelect.__kind__, $.ExpressionKind.Select); - assert.equal(dateSelect.__element__, e.datetime); - assert.equal(dateSelect.__cardinality__, $.Cardinality.One); - - const durationSelect = e.select(new edgedb.Duration()); - assert.equal(durationSelect.__kind__, $.ExpressionKind.Select); - assert.equal(durationSelect.__element__, e.duration); - assert.equal(durationSelect.__cardinality__, $.Cardinality.One); - - const ldrSelect = e.select(new edgedb.LocalDateTime(1, 2, 3)); - assert.equal(ldrSelect.__kind__, $.ExpressionKind.Select); - assert.equal(ldrSelect.__element__, e.cal.local_datetime); - assert.equal(ldrSelect.__cardinality__, $.Cardinality.One); - - const ldSelect = e.select(new edgedb.LocalDate(1, 2, 3)); - assert.equal(ldSelect.__kind__, $.ExpressionKind.Select); - assert.equal(ldSelect.__element__, e.cal.local_date); - assert.equal(ldSelect.__cardinality__, $.Cardinality.One); - - const ltSelect = e.select(new edgedb.LocalTime(1, 2, 3)); - assert.equal(ltSelect.__kind__, $.ExpressionKind.Select); - assert.equal(ltSelect.__element__, e.cal.local_time); - assert.equal(ltSelect.__cardinality__, $.Cardinality.One); - - const rdSelect = e.select(new edgedb.RelativeDuration(1, 2, 3)); - assert.equal(rdSelect.__kind__, $.ExpressionKind.Select); - assert.equal(rdSelect.__element__, e.cal.relative_duration); - assert.equal(rdSelect.__cardinality__, $.Cardinality.One); - - const memSelect = e.select(new edgedb.ConfigMemory(BigInt(1234))); - assert.equal(memSelect.__kind__, $.ExpressionKind.Select); - assert.equal(memSelect.__element__, e.cfg.memory); - assert.equal(memSelect.__cardinality__, $.Cardinality.One); -}); + test("selecting JS data", () => { + const strSelect = e.select("test"); + assert.equal(strSelect.__kind__, $.ExpressionKind.Select); + assert.equal(strSelect.__element__, e.str); + assert.equal(strSelect.__cardinality__, $.Cardinality.One); + + const numberSelect = e.select(1234); + assert.equal(numberSelect.__kind__, $.ExpressionKind.Select); + assert.equal(numberSelect.__element__.__name__, `std::number`); + assert.equal(numberSelect.__cardinality__, $.Cardinality.One); + + const boolSelect = e.select(false); + assert.equal(boolSelect.__kind__, $.ExpressionKind.Select); + assert.equal(boolSelect.__element__, e.bool); + assert.equal(boolSelect.__cardinality__, $.Cardinality.One); + + const bigintSelect = e.select(BigInt(1234)); + assert.equal(bigintSelect.__kind__, $.ExpressionKind.Select); + assert.equal(bigintSelect.__element__, e.bigint); + assert.equal(bigintSelect.__cardinality__, $.Cardinality.One); + + const bufferSelect = e.select(Buffer.from([])); + assert.equal(bufferSelect.__kind__, $.ExpressionKind.Select); + assert.equal(bufferSelect.__element__, e.bytes); + assert.equal(bufferSelect.__cardinality__, $.Cardinality.One); + + const dateSelect = e.select(new Date()); + assert.equal(dateSelect.__kind__, $.ExpressionKind.Select); + assert.equal(dateSelect.__element__, e.datetime); + assert.equal(dateSelect.__cardinality__, $.Cardinality.One); + + const durationSelect = e.select(new edgedb.Duration()); + assert.equal(durationSelect.__kind__, $.ExpressionKind.Select); + assert.equal(durationSelect.__element__, e.duration); + assert.equal(durationSelect.__cardinality__, $.Cardinality.One); + + const ldrSelect = e.select(new edgedb.LocalDateTime(1, 2, 3)); + assert.equal(ldrSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ldrSelect.__element__, e.cal.local_datetime); + assert.equal(ldrSelect.__cardinality__, $.Cardinality.One); + + const ldSelect = e.select(new edgedb.LocalDate(1, 2, 3)); + assert.equal(ldSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ldSelect.__element__, e.cal.local_date); + assert.equal(ldSelect.__cardinality__, $.Cardinality.One); + + const ltSelect = e.select(new edgedb.LocalTime(1, 2, 3)); + assert.equal(ltSelect.__kind__, $.ExpressionKind.Select); + assert.equal(ltSelect.__element__, e.cal.local_time); + assert.equal(ltSelect.__cardinality__, $.Cardinality.One); + + const rdSelect = e.select(new edgedb.RelativeDuration(1, 2, 3)); + assert.equal(rdSelect.__kind__, $.ExpressionKind.Select); + assert.equal(rdSelect.__element__, e.cal.relative_duration); + assert.equal(rdSelect.__cardinality__, $.Cardinality.One); + + const memSelect = e.select(new edgedb.ConfigMemory(BigInt(1234))); + assert.equal(memSelect.__kind__, $.ExpressionKind.Select); + assert.equal(memSelect.__element__, e.cfg.memory); + assert.equal(memSelect.__cardinality__, $.Cardinality.One); + }); -test("no shape", async () => { - const query = e.select(e.default.Hero); - const result = await query.run(client); - tc.assert>(true); - assert.deepEqual(query.__element__.__shape__, e.default.Hero.__element__.__shape__); - assert.equal(result.every((val) => !!val.id), true); -}); + test("no shape", async () => { + const query = e.select(e.default.Hero); + const result = await query.run(client); + tc.assert>(true); + assert.deepEqual( + query.__element__.__shape__, + e.default.Hero.__element__.__shape__ + ); + assert.equal( + result.every((val) => !!val.id), + true + ); + }); -test("computed only shape", () => { - const query = e.select(e.Hero, (hero) => ({ - upper_name: e.str_upper(hero.name), - })); + test("computed only shape", () => { + const query = e.select(e.Hero, (hero) => ({ + upper_name: e.str_upper(hero.name), + })); - tc.assert, { upper_name: string }[]>>(true); -}); + tc.assert, { upper_name: string }[]>>(true); + }); -const q1 = e.select(e.Hero, () => ({ - id: true, - secret_identity: true, - name: 1 > 0, - villains: { + const q1 = e.select(e.Hero, () => ({ id: true, + secret_identity: true, + name: 1 > 0, + villains: { + id: true, + computed: e.str("test"), + }, computed: e.str("test"), - }, - computed: e.str("test"), -})); + })); -type q1 = $.setToTsType; + type q1 = $.setToTsType; -test("path construction", () => { - const result = e.select(e.default.Hero); - assert.equal(result.villains.nemesis.name.__element__.__name__, "std::str"); -}); + test("path construction", () => { + const result = e.select(e.default.Hero); + assert.equal(result.villains.nemesis.name.__element__.__name__, "std::str"); + }); -test("complex shape", () => { - type q1type = $.BaseTypeToTsType<(typeof q1)["__element__"]>; - tc.assert< - tc.IsExact< - q1type, - { - id: string; - name: string | undefined; - secret_identity: string | null; - villains: { + test("complex shape", () => { + type q1type = $.BaseTypeToTsType<(typeof q1)["__element__"]>; + tc.assert< + tc.IsExact< + q1type, + { id: string; + name: string | undefined; + secret_identity: string | null; + villains: { + id: string; + computed: "test"; + }[]; computed: "test"; - }[]; - computed: "test"; - } - > - >(true); -}); + } + > + >(true); + }); -test("deep shape", () => { - const deep = e.select(e.Hero, (_hero) => ({ - id: true, - __type__: { - name: true, + test("deep shape", () => { + const deep = e.select(e.Hero, () => ({ + id: true, __type__: { - id: true, + name: true, __type__: { id: true, - name: true, + __type__: { + id: true, + name: true, + }, }, }, - }, - })); - type deep = $.setToTsType; - tc.assert< - tc.IsExact< - deep, - { - id: string; - __type__: { - name: string; + })); + type deep = $.setToTsType; + tc.assert< + tc.IsExact< + deep, + { + id: string; __type__: { - id: string; + name: string; __type__: { id: string; - name: string; + __type__: { + id: string; + name: string; + }; }; }; - }; - }[] - > - >(true); -}); - -test("compositionality", () => { - // selecting a select statement should - // default to { id } - const no_shape = e.select(q1); - - type no_shape = $.BaseTypeToTsType<(typeof no_shape)["__element__"]>; - type q1 = $.BaseTypeToTsType<(typeof q1)["__element__"]>; - tc.assert>(true); - assert.deepEqual(no_shape.__element__.__shape__, q1.__element__.__shape__); - // expect(no_shape.__element__.__shape__).toEqual({id: true}); - - // allow override shape - const override_shape = e.select(q1, () => ({ - id: true, - secret_identity: true, - })); - type override_shape = $.BaseTypeToTsType< - (typeof override_shape)["__element__"] - >; - tc.assert< - tc.IsExact< - override_shape, - { - id: string; - secret_identity: string | null; - } - > - >(true); -}); - -test("polymorphism", () => { - const query = e.select(e.Person, () => ({ - id: true, - name: true, - ...e.is(e.Hero, { secret_identity: true }), - ...e.is(e.Villain, { - nemesis: { name: true }, - }), - })); - // query.__element__. - - assert.deepEqual(query.__kind__, $.ExpressionKind.Select); - assert.deepEqual(query.__element__.__kind__, $.TypeKind.object); - assert.equal(query.__element__.__name__, "default::Person"); - - type result = $.BaseTypeToTsType<(typeof query)["__element__"]>; - tc.assert< - tc.IsExact< - result, - { - id: string; - name: string; - nemesis: { - name: string; - } | null; - secret_identity: string | null; - } - > - >(true); -}); - -test("polymorphic with nested modifiers", () => { - e.is(e.Villain, { - id: true, + }[] + > + >(true); }); - const query = e.select(e.Person, (person) => ({ - id: true, - name: true, - ...e.is(e.Villain, { - nemesis: (hero) => ({ - name: true, - order_by: hero.name, - filter: e.op(hero.name, "=", hero.name), - limit: 1, - offset: 10, - }), - }), - })); + test("compositionality", () => { + // selecting a select statement should + // default to { id } + const no_shape = e.select(q1); - type q = $.setToTsType; -}); + type no_shape = $.BaseTypeToTsType<(typeof no_shape)["__element__"]>; + type q1 = $.BaseTypeToTsType<(typeof q1)["__element__"]>; + tc.assert>(true); + assert.deepEqual(no_shape.__element__.__shape__, q1.__element__.__shape__); + // expect(no_shape.__element__.__shape__).toEqual({id: true}); -test("computables in polymorphics", () => { - const q = e.select(e.Person, (person) => ({ - id: true, - ...e.is(e.Hero, { + // allow override shape + const override_shape = e.select(q1, () => ({ + id: true, secret_identity: true, - }), - ...e.is(e.Villain, { - nemesis: { id: true, computable: e.int64(1234) }, - computable: e.int64(1234), - }), - })); - - type q = $.setToTsType; - tc.assert< - tc.IsExact< - q, - { - id: string; - secret_identity: string | null; - nemesis: { id: string; computable: 1234 } | null; - computable: never; - }[] - > - >(true); -}); + })); + type override_shape = $.BaseTypeToTsType< + (typeof override_shape)["__element__"] + >; + tc.assert< + tc.IsExact< + override_shape, + { + id: string; + secret_identity: string | null; + } + > + >(true); + }); -test("parent type props in polymorphic", () => { - const q = e.select(e.Person, () => ({ - ...e.is(e.Hero, { - // name is prop of Person + test("polymorphism", () => { + const query = e.select(e.Person, () => ({ + id: true, name: true, - secret_identity: true, - }), - ...e.is(e.Villain, { nemesis: { name: true } }), - })); + ...e.is(e.Hero, { secret_identity: true }), + ...e.is(e.Villain, { + nemesis: { name: true }, + }), + })); + // query.__element__. + + assert.deepEqual(query.__kind__, $.ExpressionKind.Select); + assert.deepEqual(query.__element__.__kind__, $.TypeKind.object); + assert.equal(query.__element__.__name__, "default::Person"); + + type result = $.BaseTypeToTsType<(typeof query)["__element__"]>; + tc.assert< + tc.IsExact< + result, + { + id: string; + name: string; + nemesis: { + name: string; + } | null; + secret_identity: string | null; + } + > + >(true); + }); - tc.assert< - tc.IsExact< - $infer, - { - name: string | null; - secret_identity: string | null; - nemesis: { name: string } | null; - }[] - > - >(true); -}); + test("polymorphic with nested modifiers", () => { + e.is(e.Villain, { + id: true, + }); -test("* in polymorphic", async () => { - const q = e.select(e.Person, () => ({ - ...e.is(e.Hero, e.Hero["*"]), - })); + e.select(e.Person, () => ({ + id: true, + name: true, + ...e.is(e.Villain, { + nemesis: (hero) => ({ + name: true, + order_by: hero.name, + filter: e.op(hero.name, "=", hero.name), + limit: 1, + offset: 10, + }), + }), + })); + }); - // 'id' is filtered out since it is not valid in a polymorphic expr - tc.assert< - tc.IsExact< - $infer, - { - name: string | null; - height: string | null; - number_of_movies: number | null; - secret_identity: string | null; - }[] - > - >(true); - - await q.run(client); -}); + test("computables in polymorphics", () => { + const q = e.select(e.Person, () => ({ + id: true, + ...e.is(e.Hero, { + secret_identity: true, + }), + ...e.is(e.Villain, { + nemesis: { id: true, computable: e.int64(1234) }, + computable: e.int64(1234), + }), + })); -test("shape type name", () => { - const name = e.select(e.Hero).__element__.__name__; - tc.assert>(true); -}); + type q = $.setToTsType; + tc.assert< + tc.IsExact< + q, + { + id: string; + secret_identity: string | null; + nemesis: { id: string; computable: 1234 } | null; + computable: never; + }[] + > + >(true); + }); -test("limit/offset inference", () => { - const testSet = e.set(1, 2, 3); - - tc.assert< - tc.IsExact<(typeof testSet)["__cardinality__"], $.Cardinality.AtLeastOne> - >(true); - assert.deepEqual(testSet.__cardinality__, $.Cardinality.AtLeastOne); - - const r0 = e.select(testSet, () => ({})); - tc.assert< - tc.IsExact<(typeof r0)["__cardinality__"], $.Cardinality.AtLeastOne> - >(true); - assert.deepEqual(r0.__cardinality__, $.Cardinality.AtLeastOne); - - const r1 = e.select(testSet, () => ({ limit: 1 })); - tc.assert>( - true - ); - assert.deepEqual(r1.__cardinality__, $.Cardinality.Many); - - const r2 = e.select(testSet, () => ({ offset: 1 })); - tc.assert>( - true - ); - assert.deepEqual(r2.__cardinality__, $.Cardinality.Many); -}); + test("parent type props in polymorphic", () => { + const q = e.select(e.Person, () => ({ + ...e.is(e.Hero, { + // name is prop of Person + name: true, + secret_identity: true, + }), + ...e.is(e.Villain, { nemesis: { name: true } }), + })); + + tc.assert< + tc.IsExact< + $infer, + { + name: string | null; + secret_identity: string | null; + nemesis: { name: string } | null; + }[] + > + >(true); + }); -test("offset", () => { - const q = e.select(e.Hero, () => ({ name: true })); - const r1 = e.select(q, () => ({ offset: 5 })); - assert.equal(r1.__modifiers__.offset?.__element__.__name__, "std::number"); -}); + test("* in polymorphic", async () => { + const q = e.select(e.Person, () => ({ + ...e.is(e.Hero, e.Hero["*"]), + })); + + // 'id' is filtered out since it is not valid in a polymorphic expr + tc.assert< + tc.IsExact< + $infer, + { + name: string | null; + height: string | null; + number_of_movies: number | null; + secret_identity: string | null; + }[] + > + >(true); -test("infer cardinality - scalar filters", () => { - const q = e.select(e.Hero); - const q2 = e.select(q, (hero) => ({ - filter_single: e.op(hero.name, "=", "asdf"), - })); - tc.assert< - tc.IsExact<(typeof q2)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q2.__cardinality__, $.Cardinality.AtMostOne); - - const u3 = e.uuid("asdf"); - const q3 = e.select(q, (hero) => { - return { filter_single: e.op(hero.id, "=", u3) }; + await q.run(client); }); - tc.assert< - tc.IsExact<(typeof q3)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q3.__cardinality__, $.Cardinality.AtMostOne); - - const q4 = q2.secret_identity; - tc.assert< - tc.IsExact<(typeof q4)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q4.__cardinality__, $.Cardinality.AtMostOne); - - const q5 = e.select(q, (hero) => ({ - filter: e.op(hero.secret_identity, "=", "asdf"), - })); - tc.assert>( - true - ); - assert.deepEqual(q5.__cardinality__, $.Cardinality.Many); - const q6 = e.select(e.Villain.nemesis, (nemesis) => ({ - filter_single: e.op(nemesis.name, "=", "asdf"), - })); - tc.assert< - tc.IsExact<(typeof q6)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q6.__cardinality__, $.Cardinality.AtMostOne); - - const strs = e.set(e.str("asdf"), e.str("qwer")); - const q7 = e.select(e.Villain, (villain) => ({ - filter: e.op(villain.name, "=", strs), - })); - tc.assert>( - true - ); - assert.deepEqual(q7.__cardinality__, $.Cardinality.Many); - - const expr8 = e.select(e.Villain, () => ({ id: true, name: true })); - const q8 = e.select(expr8, (villain) => ({ - filter_single: e.op(villain.name, "=", "asdf"), - })); - tc.assert< - tc.IsExact<(typeof q8)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q8.__cardinality__, $.Cardinality.AtMostOne); - - const expr9 = e.select(e.Villain, () => ({ id: true, name: true })); - const q9 = e.select(expr9, (villain) => ({ - filter_single: e.op(villain.name, "=", "asdf"), - })); - tc.assert< - tc.IsExact<(typeof q9)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(q9.__cardinality__, $.Cardinality.AtMostOne); - - // const q10 = e.select(e.Villain, villain => ({ - // filter_single: e.op(villain.name, "=", e.cast(e.str, e.set())) - // })); - // tc.assert>( - // true - // ); - // expect(q10.__cardinality__).toEqual($.Cardinality.Empty); -}); - -test("infer cardinality - object type filters", () => { - const oneHero = e.select(e.Hero, () => ({ limit: 1 })).assert_single(); + test("shape type name", () => { + const name = e.select(e.Hero).__element__.__name__; + tc.assert>(true); + }); - const singleHero = e.select(e.Hero, (hero) => ({ - filter_single: e.op(hero, "=", oneHero), - })); + test("limit/offset inference", () => { + const testSet = e.set(1, 2, 3); + + tc.assert< + tc.IsExact<(typeof testSet)["__cardinality__"], $.Cardinality.AtLeastOne> + >(true); + assert.deepEqual(testSet.__cardinality__, $.Cardinality.AtLeastOne); + + const r0 = e.select(testSet, () => ({})); + tc.assert< + tc.IsExact<(typeof r0)["__cardinality__"], $.Cardinality.AtLeastOne> + >(true); + assert.deepEqual(r0.__cardinality__, $.Cardinality.AtLeastOne); + + const r1 = e.select(testSet, () => ({ limit: 1 })); + tc.assert>( + true + ); + assert.deepEqual(r1.__cardinality__, $.Cardinality.Many); + + const r2 = e.select(testSet, () => ({ offset: 1 })); + tc.assert>( + true + ); + assert.deepEqual(r2.__cardinality__, $.Cardinality.Many); + }); - const c1 = singleHero.__cardinality__; - tc.assert>(true); - assert.deepEqual(c1, $.Cardinality.AtMostOne); + test("offset", () => { + const q = e.select(e.Hero, () => ({ name: true })); + const r1 = e.select(q, () => ({ offset: 5 })); + assert.equal(r1.__modifiers__.offset?.__element__.__name__, "std::number"); + }); - const oneProfile = e.select(e.Hero, () => ({ limit: 1 })).assert_single(); - const singleMovie = e.select(e.Movie, (movie) => ({ - filter_single: e.op(movie.profile, "=", oneProfile), - })); + test("infer cardinality - scalar filters", () => { + const q = e.select(e.Hero); + const q2 = e.select(q, (hero) => ({ + filter_single: e.op(hero.name, "=", "asdf"), + })); + tc.assert< + tc.IsExact<(typeof q2)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q2.__cardinality__, $.Cardinality.AtMostOne); + + const u3 = e.uuid("asdf"); + const q3 = e.select(q, (hero) => { + return { filter_single: e.op(hero.id, "=", u3) }; + }); + tc.assert< + tc.IsExact<(typeof q3)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q3.__cardinality__, $.Cardinality.AtMostOne); + + const q4 = q2.secret_identity; + tc.assert< + tc.IsExact<(typeof q4)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q4.__cardinality__, $.Cardinality.AtMostOne); + + const q5 = e.select(q, (hero) => ({ + filter: e.op(hero.secret_identity, "=", "asdf"), + })); + tc.assert>( + true + ); + assert.deepEqual(q5.__cardinality__, $.Cardinality.Many); + + const q6 = e.select(e.Villain.nemesis, (nemesis) => ({ + filter_single: e.op(nemesis.name, "=", "asdf"), + })); + tc.assert< + tc.IsExact<(typeof q6)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q6.__cardinality__, $.Cardinality.AtMostOne); + + const strs = e.set(e.str("asdf"), e.str("qwer")); + const q7 = e.select(e.Villain, (villain) => ({ + filter: e.op(villain.name, "=", strs), + })); + tc.assert>( + true + ); + assert.deepEqual(q7.__cardinality__, $.Cardinality.Many); + + const expr8 = e.select(e.Villain, () => ({ id: true, name: true })); + const q8 = e.select(expr8, (villain) => ({ + filter_single: e.op(villain.name, "=", "asdf"), + })); + tc.assert< + tc.IsExact<(typeof q8)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q8.__cardinality__, $.Cardinality.AtMostOne); + + const expr9 = e.select(e.Villain, () => ({ id: true, name: true })); + const q9 = e.select(expr9, (villain) => ({ + filter_single: e.op(villain.name, "=", "asdf"), + })); + tc.assert< + tc.IsExact<(typeof q9)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + assert.deepEqual(q9.__cardinality__, $.Cardinality.AtMostOne); + + // const q10 = e.select(e.Villain, villain => ({ + // filter_single: e.op(villain.name, "=", e.cast(e.str, e.set())) + // })); + // tc.assert>( + // true + // ); + // expect(q10.__cardinality__).toEqual($.Cardinality.Empty); + }); - const c2 = singleMovie.__cardinality__; - tc.assert>(true); - assert.deepEqual(c2, $.Cardinality.AtMostOne); - - // not a singleton - - const c3 = e.select(e.Villain, (villain) => ({ - filter: e.op(villain.nemesis, "=", oneHero), - })).__cardinality__; - tc.assert>(true); - assert.deepEqual(c3, $.Cardinality.Many); - - // not a singleton - // technically a bug, but for now this behavior is expected - const c4 = e.select(e.Villain, (villain) => ({ - filter_single: e.op(villain, "=", villain), - })).__cardinality__; - tc.assert>(true); - assert.deepEqual(c4, $.Cardinality.AtMostOne); -}); + test("infer cardinality - object type filters", () => { + const oneHero = e.select(e.Hero, () => ({ limit: 1 })).assert_single(); + + const singleHero = e.select(e.Hero, (hero) => ({ + filter_single: e.op(hero, "=", oneHero), + })); + + const c1 = singleHero.__cardinality__; + tc.assert>(true); + assert.deepEqual(c1, $.Cardinality.AtMostOne); + + const oneProfile = e.select(e.Hero, () => ({ limit: 1 })).assert_single(); + const singleMovie = e.select(e.Movie, (movie) => ({ + filter_single: e.op(movie.profile, "=", oneProfile), + })); + + const c2 = singleMovie.__cardinality__; + tc.assert>(true); + assert.deepEqual(c2, $.Cardinality.AtMostOne); + + // not a singleton + + const c3 = e.select(e.Villain, (villain) => ({ + filter: e.op(villain.nemesis, "=", oneHero), + })).__cardinality__; + tc.assert>(true); + assert.deepEqual(c3, $.Cardinality.Many); + + // not a singleton + // technically a bug, but for now this behavior is expected + const c4 = e.select(e.Villain, (villain) => ({ + filter_single: e.op(villain, "=", villain), + })).__cardinality__; + tc.assert>(true); + assert.deepEqual(c4, $.Cardinality.AtMostOne); + }); -test("non 'e.eq' filters", () => { - const q1 = e.select(e.Hero, (hero) => ({ - filter: e.bool(true), - })); - tc.assert>( - true - ); - assert.deepEqual(q1.__cardinality__, $.Cardinality.Many); + test("non 'e.eq' filters", () => { + const q1 = e.select(e.Hero, () => ({ + filter: e.bool(true), + })); + tc.assert>( + true + ); + assert.deepEqual(q1.__cardinality__, $.Cardinality.Many); + + const q2 = e.select(e.Hero, (hero) => ({ + filter: e.op(true, "if", e.op(hero.name, "=", "Thanos"), "else", false), + })); + tc.assert>( + true + ); + assert.deepEqual(q2.__cardinality__, $.Cardinality.Many); + }); - const q2 = e.select(e.Hero, (hero) => ({ - filter: e.op(true, "if", e.op(hero.name, "=", "Thanos"), "else", false), - })); - tc.assert>( - true - ); - assert.deepEqual(q2.__cardinality__, $.Cardinality.Many); -}); + test("fetch heroes", async () => { + const result = await e.select(e.Hero).run(client); + assert.equal(result.length, 3); + assert.equal( + result.every((h) => typeof h.id === "string"), + true + ); + }); -test("fetch heroes", async () => { - const result = await e.select(e.Hero).run(client); - assert.equal(result.length, 3); - assert.equal(result.every((h) => typeof h.id === "string"), true); -}); + test("filter by id", async () => { + const result = await e + .select(e.Hero, () => ({ + filter_single: { id: data.spidey.id }, + })) + .run(client); -test("filter by id", async () => { - const result = await e - .select(e.Hero, (hero) => ({ - filter_single: { id: data.spidey.id }, - })) - .run(client); + assert.deepEqual(result?.id, data.spidey.id); + }); - assert.deepEqual(result?.id, data.spidey.id); -}); + test("filter by id expr", async () => { + const result = await e + .select(e.Hero, () => ({ + filter_single: { id: e.uuid(data.spidey.id) }, + })) + .run(client); -test("filter by id expr", async () => { - const result = await e - .select(e.Hero, (hero) => ({ - filter_single: { id: e.uuid(data.spidey.id) }, - })) - .run(client); + assert.deepEqual(result?.id, data.spidey.id); + }); - assert.deepEqual(result?.id, data.spidey.id); -}); + test("limit 1", async () => { + const query = e + .select(e.Hero, (hero) => ({ + order_by: hero.name, + offset: 1, + limit: 1, + })) + .assert_single(); + const result = await e.select(query).run(client); + assert.deepEqual(result?.id, data.iron_man.id); + }); -test("limit 1", async () => { - const query = e - .select(e.Hero, (hero) => ({ + test("limit 2", async () => { + const query = e.select(e.Hero, (hero) => ({ order_by: hero.name, offset: 1, - limit: 1, - })) - .assert_single(); - const result = await e.select(query).run(client); - assert.deepEqual(result?.id, data.iron_man.id); -}); - -test("limit 2", async () => { - const query = e.select(e.Hero, (hero) => ({ - order_by: hero.name, - offset: 1, - limit: 2, - })); - const results = await query.run(client); - - assert.equal(results.length, 2); - assert.deepEqual(results, [{ id: data.iron_man.id }, { id: data.spidey.id }]); -}); - -test("order by self", async () => { - const query = e.select(e.Hero, (hero) => ({ - order_by: hero, - })); - const result = await query.run(client); - assert.deepEqual(result, [data.cap, data.spidey, data.iron_man] - .map((h) => ({ id: h.id })) - .sort((a, b) => a.id.localeCompare(b.id))); -}); + limit: 2, + })); + const results = await query.run(client); + + assert.equal(results.length, 2); + assert.deepEqual(results, [ + { id: data.iron_man.id }, + { id: data.spidey.id }, + ]); + }); -test("shapes", async () => { - const query = e.select( - e - .select(e.Hero, (hero) => ({ filter: e.op(hero.name, "=", "Iron Man") })) - .assert_single(), - () => ({ - id: true, - name: true, - secret_identity: true, - villains: { id: true }, - }) - ); + test("order by self", async () => { + const query = e.select(e.Hero, (hero) => ({ + order_by: hero, + })); + const result = await query.run(client); + assert.deepEqual( + result, + [data.cap, data.spidey, data.iron_man] + .map((h) => ({ id: h.id })) + .sort((a, b) => a.id.localeCompare(b.id)) + ); + }); - const result = await query.run(client); - expect(result).toMatchObject(data.iron_man); - assert.deepEqual(result?.villains, [{ id: data.thanos.id }]); -}); + test("shapes", async () => { + const query = e.select( + e + .select(e.Hero, (hero) => ({ + filter: e.op(hero.name, "=", "Iron Man"), + })) + .assert_single(), + () => ({ + id: true, + name: true, + secret_identity: true, + villains: { id: true }, + }) + ); + + const result = await query.run(client); + expect(result).toMatchObject(data.iron_man); + assert.deepEqual(result?.villains, [{ id: data.thanos.id }]); + }); -test("computables", async () => { - const all_heroes = e.select(e.Hero, () => ({ - // __type__: {name: true} - id: true, - })); - const query = e.select( - e - .select(e.Person.is(e.Hero), (hero) => ({ - order_by: hero.name, - limit: 1, - })) - .assert_single(), - (hero) => ({ + test("computables", async () => { + const all_heroes = e.select(e.Hero, () => ({ + // __type__: {name: true} id: true, - computable: e.int64(35), - all_heroes, - }) - ); - - type query = $.setToTsType; - tc.assert< - tc.IsExact< - query, - { - id: string; - computable: 35; - all_heroes: { - // __type__: {name: string} + })); + const query = e.select( + e + .select(e.Person.is(e.Hero), (hero) => ({ + order_by: hero.name, + limit: 1, + })) + .assert_single(), + () => ({ + id: true, + computable: e.int64(35), + all_heroes, + }) + ); + + type query = $.setToTsType; + tc.assert< + tc.IsExact< + query, + { id: string; - }[]; - } | null - > - >(true); - const results = await query.run(client); - - assert.deepEqual(results?.id, data.cap.id); - assert.equal(results?.computable, 35); - // expect( - // results?.all_heroes.every(hero => hero.__type__.name === "default::Hero") - // ).toEqual(true); -}); - -test("type intersections", async () => { - const query = e.select(e.Person.is(e.Hero), () => ({ - id: true, - // __type__: {name: true}, - })); - const results = await query.run(client); - assert.equal(results.every((person) => typeof person.id === "string"), true); - // expect( - // results.every(person => person.__type__.name === "default::Hero") - // ).toEqual(true); -}); - -test("type intersections - static", () => { - const result = e.select(e.Movie.characters).is(e.Villain); - type result = $.setToTsType; - tc.assert>(true); -}); + computable: 35; + all_heroes: { + // __type__: {name: string} + id: string; + }[]; + } | null + > + >(true); + const results = await query.run(client); + + assert.deepEqual(results?.id, data.cap.id); + assert.equal(results?.computable, 35); + // expect( + // results?.all_heroes.every(hero => hero.__type__.name === "default::Hero") + // ).toEqual(true); + }); -test("backlinks", async () => { - const result1 = await e - .select(e.Hero[" ({ + test("type intersections", async () => { + const query = e.select(e.Person.is(e.Hero), () => ({ id: true, // __type__: {name: true}, - title: true, - })) - .run(client); - - const q2 = e.select(e.Hero[" ({ - id: true, - // __type__: {name: true}, - title: true, - })); + })); + const results = await query.run(client); + assert.equal( + results.every((person) => typeof person.id === "string"), + true + ); + // expect( + // results.every(person => person.__type__.name === "default::Hero") + // ).toEqual(true); + }); - const result2 = await q2.run(client); + test("type intersections - static", () => { + const result = e.select(e.Movie.characters).is(e.Villain); + type result = $.setToTsType; + tc.assert>(true); + }); - assert.deepEqual(result1, result2); - assert.equal(Array.isArray(result1), true); - assert.equal( - [data.the_avengers.title, data.civil_war.title].includes(result1[0].title), - true - ); + test("backlinks", async () => { + const result1 = await e + .select(e.Hero[" ({ + id: true, + // __type__: {name: true}, + title: true, + })) + .run(client); - const q3 = e.select(e.Hero, (hero) => ({ - " ({ + const q2 = e.select(e.Hero[" ({ + id: true, + // __type__: {name: true}, title: true, - })), - })); - - const res3 = await q3.run(client); - tc.assert< - tc.IsExact< - typeof res3, - { - " - >(true); - - for (const hero of res3) { - assert.deepEqual(hero[" { - e.select(e.Hero, () => ({ - id: e.uuid("asdf"), - number_of_movies: e.int64(1234), - name: e.str("adsf"), - })); -}); - -test("link properties", async () => { - const query = e.select(e.Movie, (movie) => ({ - id: true, - characters: (char) => ({ - name: true, - "@character_name": true, - }), - })); - - const result = await query.run(client); - - tc.assert< - tc.IsExact< - typeof result, - { - id: string; - characters: { - name: string; - "@character_name": string | null; - }[]; - }[] - > - >(true); -}); + })); + + const result2 = await q2.run(client); + + assert.deepEqual(result1, result2); + assert.equal(Array.isArray(result1), true); + assert.equal( + [data.the_avengers.title, data.civil_war.title].includes( + result1[0].title + ), + true + ); + + const q3 = e.select(e.Hero, (hero) => ({ + " ({ + title: true, + })), + })); + + const res3 = await q3.run(client); + tc.assert< + tc.IsExact< + typeof res3, + { + " + >(true); + + for (const hero of res3) { + assert.deepEqual(hero[" { - const query = e.select(e.Movie, (movie) => ({ - id: true, - characters: (char) => ({ - name: true, - "@character_name": true, - char_name: char["@character_name"], - person_name: char.name, + test("overrides with implicit casting", () => { + e.select(e.Hero, () => ({ + id: e.uuid("asdf"), + number_of_movies: e.int64(1234), + name: e.str("adsf"), + })); + }); - filter: e.op(char["@character_name"], "ilike", "a%"), - }), - })); + test("link properties", async () => { + const query = e.select(e.Movie, () => ({ + id: true, + characters: () => ({ + name: true, + "@character_name": true, + }), + })); - const result = await query.run(client); + const result = await query.run(client); - tc.assert< - tc.IsExact< - typeof result, - { - id: string; - characters: { - name: string; - "@character_name": string | null; - char_name: string | null; - person_name: string; - }[]; - }[] - > - >(true); -}); + tc.assert< + tc.IsExact< + typeof result, + { + id: string; + characters: { + name: string; + "@character_name": string | null; + }[]; + }[] + > + >(true); + }); -test("polymorphic link properties in expressions", async () => { - const query = e.select(e.Object, (obj) => ({ - id: true, - ...e.is(e.Movie, { - title: true, + test("link properties in expressions", async () => { + const query = e.select(e.Movie, () => ({ + id: true, characters: (char) => ({ name: true, "@character_name": true, @@ -760,118 +748,148 @@ test("polymorphic link properties in expressions", async () => { filter: e.op(char["@character_name"], "ilike", "a%"), }), - }), - })); + })); - query.__element__.__shape__.characters; + const result = await query.run(client); - const result = await query.run(client); + tc.assert< + tc.IsExact< + typeof result, + { + id: string; + characters: { + name: string; + "@character_name": string | null; + char_name: string | null; + person_name: string; + }[]; + }[] + > + >(true); + }); - tc.assert< - tc.IsExact< - typeof result, - { - id: string; - title: string | null; - characters: - | { - name: string; - "@character_name": string | null; - char_name: string | null; - person_name: string; - }[] - | null; - }[] - > - >(true); -}); + test("polymorphic link properties in expressions", async () => { + const query = e.select(e.Object, () => ({ + id: true, + ...e.is(e.Movie, { + title: true, + characters: (char) => ({ + name: true, + "@character_name": true, + char_name: char["@character_name"], + person_name: char.name, -// test("assert_single this check", () => { -// const inner = e.select(e.Hero); -// const outer = e.select(e.Hero).assert_single().__args__[0]; -// tc.assert>(true); -// }); + filter: e.op(char["@character_name"], "ilike", "a%"), + }), + }), + })); -test("filters in subqueries", async () => { - const q1 = e.select(e.Hero, (hero) => ({ - name: true, - villains: { - id: true, - name: true, - }, - filter_single: e.op(hero.name, "=", data.spidey.name), - })); + query.__element__.__shape__.characters; - const res1 = await q1.run(client); + const result = await query.run(client); - assert.ok(res1); - assert.equal(res1!.villains.length, 1); + tc.assert< + tc.IsExact< + typeof result, + { + id: string; + title: string | null; + characters: + | { + name: string; + "@character_name": string | null; + char_name: string | null; + person_name: string; + }[] + | null; + }[] + > + >(true); + }); - const q2 = e.select(e.Hero, (hero) => ({ - name: true, - villains: (v) => ({ - id: true, - name: true, - filter: e.op(v.name, "ilike", "%n%"), - }), - filter_single: e.op(hero.name, "=", data.spidey.name), - })); + // test("assert_single this check", () => { + // const inner = e.select(e.Hero); + // const outer = e.select(e.Hero).assert_single().__args__[0]; + // tc.assert>(true); + // }); - const res2 = await q2.run(client); + test("filters in subqueries", async () => { + const q1 = e.select(e.Hero, (hero) => ({ + name: true, + villains: { + id: true, + name: true, + }, + filter_single: e.op(hero.name, "=", data.spidey.name), + })); - assert.ok(res2); - assert.equal(res2!.villains.length, 0); + const res1 = await q1.run(client); - tc.assert< - tc.IsExact< - typeof res1, - { - name: string; - villains: { - id: string; + tc.assert< + tc.IsExact< + typeof res1, + { name: string; - }[]; - } | null - > - >(true); + villains: { + id: string; + name: string; + }[]; + } | null + > + >(true); - tc.assert>(true); + assert.ok(res1); + assert.equal(res1.villains.length, 1); - const q3 = e.select(e.Hero, (hero) => ({ - name: true, - villains: (v) => ({ - id: true, - name: true, - filter: e.op(v.name, "=", "Thanos"), - }), - thanos: e.select(hero.villains, (v) => ({ + const q2 = e.select(e.Hero, (hero) => ({ name: true, - filter_single: e.op(v.name, "=", "Thanos"), - })), - })); + villains: (v) => ({ + id: true, + name: true, + filter: e.op(v.name, "ilike", "%n%"), + }), + filter_single: e.op(hero.name, "=", data.spidey.name), + })); + + const res2 = await q2.run(client); + + assert.ok(res2); + assert.equal(res2.villains.length, 0); - const test = await e - .select(e.Hero.villains, (v) => ({ + tc.assert>(true); + + const q3 = e.select(e.Hero, (hero) => ({ name: true, - filter: e.op(v.name, "=", "Thanos"), - })) - .run(client); + villains: (v) => ({ + id: true, + name: true, + filter: e.op(v.name, "=", "Thanos"), + }), + thanos: e.select(hero.villains, (v) => ({ + name: true, + filter_single: e.op(v.name, "=", "Thanos"), + })), + })); - const arg = q3.__element__.__shape__.thanos.__element__.__shape__; + await e + .select(e.Hero.villains, (v) => ({ + name: true, + filter: e.op(v.name, "=", "Thanos"), + })) + .run(client); - // q3.__modifiers__. - const res3 = await q3.run(client); + const res3 = await q3.run(client); - assert.equal(Array.isArray(res3), true); - const ironMan = res3.find((r) => r.name === "Iron Man"); - assert.ok(ironMan); - assert.equal(Array.isArray(ironMan!.villains), true); - assert.equal(Array.isArray(ironMan!.thanos), false); + assert.equal(Array.isArray(res3), true); + const ironMan = res3.find((r) => r.name === "Iron Man"); + assert.ok(ironMan); + assert.equal(Array.isArray(ironMan.villains), true); + assert.equal(Array.isArray(ironMan.thanos), false); - tc.assert< - tc.IsExact< - typeof res3, - /** + tc.assert< + tc.IsExact< + typeof res3, + /** * onst res3: { name: string; @@ -884,35 +902,37 @@ test("filters in subqueries", async () => { } | null; }[] */ - { - name: string; - villains: { - id: string; - name: string; - }[]; - thanos: { + { name: string; - } | null; - }[] - > - >(true); -}); + villains: { + id: string; + name: string; + }[]; + thanos: { + name: string; + } | null; + }[] + > + >(true); + }); -test("repeated computed", async () => { - const query = e.select(e.Villain, () => ({ - id: true, - name: true, - nemesis: (nemesis) => { - const nameLen = e.len(nemesis.name); - return { - name: true, - nameLen, - nameLen2: nameLen, - }; - }, - })); + test("repeated computed", async () => { + const query = e.select(e.Villain, () => ({ + id: true, + name: true, + nemesis: (nemesis) => { + const nameLen = e.len(nemesis.name); + return { + name: true, + nameLen, + nameLen2: nameLen, + }; + }, + })); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `WITH __scope_0_defaultVillain := DETACHED default::Villain SELECT __scope_0_defaultVillain { id, @@ -933,49 +953,52 @@ SELECT __scope_0_defaultVillain { single nameLen2 := __scope_1_defaultHero.__withVar_2 } ) -}`); +}` + ); - const res = await query.run(client); + const res = await query.run(client); - tc.assert< - tc.IsExact< - typeof res, - { - id: string; - name: string; - nemesis: { + tc.assert< + tc.IsExact< + typeof res, + { + id: string; name: string; - nameLen: number; - nameLen2: number; - } | null; - }[] - > - >(true); -}); + nemesis: { + name: string; + nameLen: number; + nameLen2: number; + } | null; + }[] + > + >(true); + }); -test("polymorphic subqueries", async () => { - const query = e.select(e.Movie.characters, (character) => ({ - id: true, - name: true, - ...e.is(e.Villain, { nemesis: true }), - ...e.is(e.Hero, { - secret_identity: true, - villains: { - id: true, - name: true, - nemesis: (nemesis) => { - const nameLen = e.len(nemesis.name); - return { - name: true, - nameLen, - nameLen2: nameLen, - }; + test("polymorphic subqueries", async () => { + const query = e.select(e.Movie.characters, () => ({ + id: true, + name: true, + ...e.is(e.Villain, { nemesis: true }), + ...e.is(e.Hero, { + secret_identity: true, + villains: { + id: true, + name: true, + nemesis: (nemesis) => { + const nameLen = e.len(nemesis.name); + return { + name: true, + nameLen, + nameLen2: nameLen, + }; + }, }, - }, - }), - })); + }), + })); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `WITH __scope_0_defaultPerson := DETACHED default::Movie.characters SELECT __scope_0_defaultPerson { id, @@ -1006,430 +1029,358 @@ SELECT __scope_0_defaultPerson { ) } ) -}`); +}` + ); - const res = await query.run(client); + const res = await query.run(client); - tc.assert< - tc.IsExact< - typeof res, - { - id: string; - name: string; - nemesis: { + tc.assert< + tc.IsExact< + typeof res, + { id: string; - } | null; - secret_identity: string | null; - villains: - | { - id: string; - name: string; - nemesis: { + name: string; + nemesis: { + id: string; + } | null; + secret_identity: string | null; + villains: + | { + id: string; name: string; - nameLen: number; - nameLen2: number; - } | null; - }[] - | null; - }[] - > - >(true); -}); - -test("polymorphic field in nested shape", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - characters: (char) => ({ - name: true, - order_by: char.name, - ...e.is(e.Hero, { secret_identity: true }), - }), - filter_single: e.op(movie.title, "=", "The Avengers"), - })); + nemesis: { + name: string; + nameLen: number; + nameLen2: number; + } | null; + }[] + | null; + }[] + > + >(true); + }); - const result = await query.run(client); - assert.deepEqual(JSON.parse(JSON.stringify(result)), { - title: data.the_avengers.title, - characters: [ - { - name: data.cap.name, - secret_identity: data.cap.secret_identity, - }, - { - name: data.iron_man.name, - secret_identity: data.iron_man.secret_identity, - }, - ], + test("polymorphic field in nested shape", async () => { + const query = e.select(e.Movie, (movie) => ({ + title: true, + characters: (char) => ({ + name: true, + order_by: char.name, + ...e.is(e.Hero, { secret_identity: true }), + }), + filter_single: e.op(movie.title, "=", "The Avengers"), + })); + + const result = await query.run(client); + assert.deepEqual(JSON.parse(JSON.stringify(result)), { + title: data.the_avengers.title, + characters: [ + { + name: data.cap.name, + secret_identity: data.cap.secret_identity, + }, + { + name: data.iron_man.name, + secret_identity: data.iron_man.secret_identity, + }, + ], + }); + + tc.assert< + tc.IsExact< + typeof result, + { + title: string; + characters: { + name: string; + secret_identity: string | null; + }[]; + } | null + > + >(true); }); - tc.assert< - tc.IsExact< - typeof result, - { - title: string; - characters: { - name: string; - secret_identity: string | null; - }[]; - } | null - > - >(true); -}); + test("correlated path select", async () => { + const query = e.select( + e.op(e.op(e.Hero.name, "++", " is "), "++", e.Hero.secret_identity) + ); -test("correlated path select", async () => { - const query = e.select( - e.op(e.op(e.Hero.name, "++", " is "), "++", e.Hero.secret_identity) - ); + const correlatedQuery = e.with([e.Hero], query); - const correlatedQuery = e.with([e.Hero], query); + const heros = [data.cap, data.iron_man, data.spidey]; - const heros = [data.cap, data.iron_man, data.spidey]; + assert.deepEqual( + (await query.run(client)).sort(), + $.util + .flatMap(heros, (h1) => + heros.map((h2) => `${h1.name} is ${h2.secret_identity}`) + ) + .sort() + ); - assert.deepEqual((await query.run(client)).sort(), $.util - .flatMap(heros, (h1) => - heros.map((h2) => `${h1.name} is ${h2.secret_identity}`) - ) - .sort()); + assert.deepEqual( + (await correlatedQuery.run(client)).sort(), + heros.map((h) => `${h.name} is ${h.secret_identity}`).sort() + ); + }); - assert.deepEqual( - (await correlatedQuery.run(client)).sort(), - heros.map((h) => `${h.name} is ${h.secret_identity}`).sort() - ); -}); + test("modifiers on scalar selects", async () => { + // filter + const q1 = e.select(e.Hero.name, (el) => ({ + filter: e.op(el, "ilike", "%man%"), + })); + const res1 = await q1.run(client); + tc.assert>(true); + assert.deepEqual( + res1.sort(), + [data.iron_man.name, data.spidey.name].sort() + ); + + // order + const unorderedSet = e.set( + e.int64(2), + e.int64(4), + e.int64(1), + e.int64(5), + e.int64(3) + ); + + const q2 = e.select(unorderedSet, (el) => ({ + order_by: el, + })); + const res2 = await q2.run(client); + tc.assert>(true); + assert.deepEqual(res2, [1, 2, 3, 4, 5]); + + const q3 = e.select(unorderedSet, (el) => ({ + order_by: { expression: el, direction: e.DESC }, + })); + const res3 = await q3.run(client); + tc.assert>(true); + assert.deepEqual(res3, [5, 4, 3, 2, 1]); + + // offset and limit + const q4 = e + .select(unorderedSet, () => ({ + offset: 2, + limit: 1, + })) + .assert_single(); + const res4 = await e.select(q4).run(client); + tc.assert>(true); + assert.equal(res4, 1); + }); -test("modifiers on scalar selects", async () => { - // filter - const q1 = e.select(e.Hero.name, (el) => ({ - filter: e.op(el, "ilike", "%man%"), - })); - const res1 = await q1.run(client); - tc.assert>(true); - assert.deepEqual(res1.sort(), [data.iron_man.name, data.spidey.name].sort()); - - // order - const unorderedSet = e.set( - e.int64(2), - e.int64(4), - e.int64(1), - e.int64(5), - e.int64(3) - ); - - const q2 = e.select(unorderedSet, (el) => ({ - order_by: el, - })); - const res2 = await q2.run(client); - tc.assert>(true); - assert.deepEqual(res2, [1, 2, 3, 4, 5]); + test("nested matching scopes", async () => { + const q = e.select(e.Hero, (h) => ({ + name: h.name, + otherHeros: e.select(e.Hero, (h2) => ({ + name: true, + names: e.op(h.name, "++", h2.name), + order_by: h2.name, + })), + order_by: h.name, + })); - const q3 = e.select(unorderedSet, (el) => ({ - order_by: { expression: el, direction: e.DESC }, - })); - const res3 = await q3.run(client); - tc.assert>(true); - assert.deepEqual(res3, [5, 4, 3, 2, 1]); - - // offset and limit - const q4 = e - .select(unorderedSet, (el) => ({ - offset: 2, - limit: 1, - })) - .assert_single(); - const res4 = await e.select(q4).run(client); - tc.assert>(true); - assert.equal(res4, 1); -}); + const result = await q.run(client); -test("nested matching scopes", async () => { - const q = e.select(e.Hero, (h) => ({ - name: h.name, - otherHeros: e.select(e.Hero, (h2) => ({ - name: true, - names: e.op(h.name, "++", h2.name), - order_by: h2.name, - })), - order_by: h.name, - })); + const heros = [data.cap, data.iron_man, data.spidey]; - const result = await q.run(client); + const expectedResult = heros.map((h) => ({ + name: h.name, + otherHeros: heros.map((h2) => ({ + name: h2.name, + names: h.name + h2.name, + })), + })); - const heros = [data.cap, data.iron_man, data.spidey]; + assert.deepEqual(JSON.stringify(result), JSON.stringify(expectedResult)); + }); - const expectedResult = heros.map((h) => ({ - name: h.name, - otherHeros: heros.map((h2) => ({ - name: h2.name, - names: h.name + h2.name, - })), - })); + test("runnable expressions", async () => { + const expr = e.op("Hello ", "++", "World"); - assert.deepEqual(JSON.stringify(result), JSON.stringify(expectedResult)); -}); + assert.equal(await expr.run(client), `Hello World`); + }); -test("runnable expressions", async () => { - const expr = e.op("Hello ", "++", "World"); + test("computed property path", async () => { + const numbers = e.set(1, 2, 3); + const expr = e.select({ + numbers, + }); + const query = e.select(expr.numbers); - assert.equal(await expr.run(client), `Hello World`); -}); + assert.deepEqual(await query.run(client), [1, 2, 3]); + }); -test("computed property path", async () => { - const numbers = e.set(1, 2, 3); - const expr = e.select({ - numbers, + test("select with enums", async () => { + const query = e.select(e.Movie, (movie) => ({ + title: true, + genre: true, + filter: e.op(movie.genre, "=", e.Genre.Action), + })); + const result = await query.run(client); + assert.equal(result.length, 2); }); - const query = e.select(expr.numbers); - assert.deepEqual(await query.run(client), [1, 2, 3]); -}); + test("filter by sequence", async () => { + await e.op(e.Bag.seqField, "=", 1).run(client); + }); -test("select with enums", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - genre: true, - filter: e.op(movie.genre, "=", e.Genre.Action), - })); - const result = await query.run(client); - assert.equal(result.length, 2); -}); + test("Date type", async () => { + const dates = await e.select(e.Bag.datetimeField).run(client); + tc.assert>(true); + }); -test("filter by sequence", async () => { - await e.op(e.Bag.seqField, "=", 1).run(client); -}); + test("select *", async () => { + const allFields = await e + .select(e.Movie, (movie) => ({ + ...e.Movie["*"], + filter: e.op(movie.title, "=", data.the_avengers.title), + })) + .run(client); -test("Date type", async () => { - const dates = await e.select(e.Bag.datetimeField).run(client); - tc.assert>(true); -}); + const { characters: _characters, ...movie } = data.the_avengers; + assert.deepEqual(allFields, [movie]); + }); -test("select *", async () => { - const allFields = await e - .select(e.Movie, (movie) => ({ - ...e.Movie["*"], - filter: e.op(movie.title, "=", data.the_avengers.title), - })) - .run(client); - - assert.deepEqual(allFields, [ - { - ...data.the_avengers, - characters: undefined, - }, - ]); -}); + test("select required multi link", async () => { + const query = e.select(e.User, () => ({ + username: true, + favourite_movies: { + title: true, + }, + })); -test("select required multi link", async () => { - const query = e.select(e.User, () => ({ - username: true, - favourite_movies: { + await query.run(client); + }); + + test("filter on link prop", async () => { + const query = e.select(e.Movie, () => ({ title: true, - }, - })); + characters: (c) => ({ + name: true, + "@character_name": true, + filter: e.op(c["@character_name"], "=", "Tony Stark"), + }), + })); + await query.run(client); + }); - await query.run(client); -}); + test("filter on link prop in nested path", async () => { + const query = e.select(e.Movie, (movie) => ({ + filter: e.op("Iron Man", "in", movie.characters["@character_name"]), + title: true, + })); + await query.run(client); + }); -test("filter on link prop", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - characters: (c) => ({ - name: true, - "@character_name": true, - filter: e.op(c["@character_name"], "=", "Tony Stark"), - }), - })); - await query.run(client); -}); + test("cardinality of linkprop in scopified object", async () => { + const query = e.select(e.Movie.characters, (c) => { + assert.deepEqual( + c["@character_name"].__cardinality__, + $.Cardinality.AtMostOne + ); + return { + name: true, + // doesn't work yet + // ["@character_name"]: true, + }; + }); + await query.run(client); + }); -test("filter on link prop in nested path", async () => { - const query = e.select(e.Movie, (movie) => ({ - filter: e.op("Iron Man", "in", movie.characters["@character_name"]), - title: true, - })); - await query.run(client); -}); + test("portable shape", async () => { + const baseShape = e.shape(e.Movie, (movie) => ({ + ...movie["*"], + })); + const query = e.select(e.Movie, (m) => { + return { + ...baseShape(m), + characters: { name: true }, + filter_single: e.op(m.title, "=", "The Avengers"), + }; + }); -test("cardinality of linkprop in scopified object", async () => { - const query = e.select(e.Movie.characters, (c) => { - assert.deepEqual(c["@character_name"].__cardinality__, $.Cardinality.AtMostOne); - return { - name: true, - // doesn't work yet - // ["@character_name"]: true, - }; + const result = await query.run(client); + assert.ok(result?.rating); + assert.ok(result?.characters); }); - await query.run(client); -}); -test("portable shape", async () => { - const baseShape = e.shape(e.Movie, (movie) => ({ - ...movie["*"], - })); - const query = e.select(e.Movie, (m) => { - return { - ...baseShape(m), - characters: { name: true }, - filter_single: e.op(m.title, "=", "The Avengers"), - }; + test("filter_single id", async () => { + const query = e.select(e.Movie, () => ({ + title: true, + filter_single: { title: "The Avengers" }, + })); + const result = await query.run(client); + assert.equal(result?.title, "The Avengers"); }); - const result = await query.run(client); - assert.ok(result?.rating); - assert.ok(result?.characters); -}); - -test("filter_single id", async () => { - const query = e.select(e.Movie, () => ({ - title: true, - filter_single: { title: "The Avengers" }, - })); - const result = await query.run(client); - assert.equal(result?.title, "The Avengers"); -}); - -test("filter_single exclusive prop", async () => { - const query = e.select(e.Movie, () => ({ - title: true, - filter_single: { title: "The Avengers" }, - })); - const result = await query.run(client); - assert.equal(result?.title, "The Avengers"); -}); + test("filter_single exclusive prop", async () => { + const query = e.select(e.Movie, () => ({ + title: true, + filter_single: { title: "The Avengers" }, + })); + const result = await query.run(client); + assert.equal(result?.title, "The Avengers"); + }); -test("filter_single composite", async () => { - const query = e.select(e.Movie, () => ({ - title: true, - filter_single: { title: "The Avengers", release_year: 2012 }, - })); - const result = await query.run(client); - assert.equal(result?.title, "The Avengers"); -}); + test("filter_single composite", async () => { + const query = e.select(e.Movie, () => ({ + title: true, + filter_single: { title: "The Avengers", release_year: 2012 }, + })); + const result = await query.run(client); + assert.equal(result?.title, "The Avengers"); + }); -test("filter_single composite truple", async () => { - const query = e.select(e.Profile, () => ({ - slug: true, - filter_single: { - a: "adsf", - b: "adsf", - c: "adsf", - }, - })); + test("filter_single composite truple", async () => { + const query = e.select(e.Profile, () => ({ + slug: true, + filter_single: { + a: "adsf", + b: "adsf", + c: "adsf", + }, + })); - await query.run(client); -}); + await query.run(client); + }); -test("filter_single expect error", async () => { - // @ts-expect-error - e.select(e.Movie, () => ({ - title: true, - filter_single: { genre: e.Genre.Horror }, - })); -}); + test("filter_single expect error", async () => { + // @ts-expect-error filter_single only types exclusive props + e.select(e.Movie, () => ({ + title: true, + filter_single: { genre: e.Genre.Horror }, + })); + }); -test("filter_single card mismatch", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - filter_single: e.op(movie.genre, "=", e.Genre.Action), - })); + test("filter_single card mismatch", async () => { + const query = e.select(e.Movie, (movie) => ({ + title: true, + filter_single: e.op(movie.genre, "=", e.Genre.Action), + })); - await expect(query.run(client)).rejects.toThrow(CardinalityViolationError); -}); + await expect(query.run(client)).rejects.toThrow(CardinalityViolationError); + }); -// EdgeQL limitation -// test("link prop on backlink", async()=>{ -// const query = e.select(e.Person, person => ({ -// movies: e.select(person[" ({ -// title: true, -// "@character_name": true, -// })), -// })); -// await query.run(client); -// }) - -test("type union links", async () => { - const query = e.select(e.Z, (z) => ({ - xy: { - a: true, - ...e.is(e.X, { - b: true, - }), - }, - })); + test("type union links", async () => { + const query = e.select(e.Z, () => ({ + xy: { + a: true, + ...e.is(e.X, { + b: true, + }), + }, + })); - const result = await query.run(client); + const result = await query.run(client); - tc.assert< - tc.IsExact< - typeof result, - { xy: { a: string | null; b: number | null } | null }[] - > - >(true); + tc.assert< + tc.IsExact< + typeof result, + { xy: { a: string | null; b: number | null } | null }[] + > + >(true); + }); }); - -// Modifier methods removed for now, until we can fix typescript inference -// problems / excessively deep errors - -// test("modifier methods", async () => { -// const strs = ["c", "a", "aa", "b", "cc", "bb"]; -// let q3 = e.select(e.set(...strs), vals => ({ -// order_by: {expression: e.len(vals), direction: e.DESC}, -// })); - -// // reassignment allowed -// q3 = q3.order_by(vals => vals); -// tc.assert>( -// true -// ); - -// expect(await q3.run(client)).toEqual(["aa", "bb", "cc", "a", "b", "c"]); - -// const q4 = e -// .select(e.Hero, hero => ({ -// order_by: hero.name, -// })) -// .limit(2); -// const r4 = await q4.run(client); - -// expect(r4.length).toEqual(2); -// expect(await q4.limit(1).offset(1).run(client)).toEqual(r4.slice(1, 2)); - -// const q5 = e -// .select(e.Hero, hero => ({ -// name: true, -// nameLen: e.len(hero.name), -// })) -// .order_by(hero => hero.nameLen); - -// const r5 = await q5.run(client); -// }); - -// test("modifier methods", async () => { -// let freeQuery = e.select({ -// heroes: e.Hero, -// }); - -// const filteredFreeQuery = freeQuery.filter(arg => e.bool(false)); -// // methods do not change change cardinality -// tc.assert< -// tc.IsExact -// >(true); -// expect(filteredFreeQuery.__cardinality__).toEqual($.Cardinality.One); - -// const offsetFreeQuery = freeQuery.offset(3); -// // methods do not change change cardinality -// tc.assert< -// tc.IsExact -// >(true); -// expect(offsetFreeQuery.__cardinality__).toEqual($.Cardinality.One); - -// const limitFreeQuery = freeQuery.limit(1); -// // methods do not change change cardinality -// tc.assert< -// tc.IsExact -// >(true); -// expect(limitFreeQuery.__cardinality__).toEqual($.Cardinality.One); - -// // should allow reassignment -// freeQuery = freeQuery.offset(1).filter(e.bool(false)); -// expect(await freeQuery.run(client)).toEqual(null); -// }); From dea7563e360e2944066e810d5626bfaedb8cda78 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 15:04:39 -0400 Subject: [PATCH 04/20] Fix with tests --- packages/generate/test/with.test.ts | 257 +++++++++++++++++----------- 1 file changed, 154 insertions(+), 103 deletions(-) diff --git a/packages/generate/test/with.test.ts b/packages/generate/test/with.test.ts index 5270f93ed..6dca3d10f 100644 --- a/packages/generate/test/with.test.ts +++ b/packages/generate/test/with.test.ts @@ -6,18 +6,24 @@ import { tc } from "./setupTeardown"; test("simple repeated expression", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal(e.select(e.op(numbers, "+", numbers)).toEdgeQL(), `WITH + assert.equal( + e.select(e.op(numbers, "+", numbers)).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 } -SELECT (__withVar_0 + __withVar_0)`); +SELECT (__withVar_0 + __withVar_0)` + ); }); test("simple expression with alias", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal(e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL(), `WITH + assert.equal( + e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 }, __withVar_1 := __withVar_0 -SELECT (__withVar_0 + __withVar_1)`); +SELECT (__withVar_0 + __withVar_1)` + ); }); test("implicit WITH vars referencing each other", () => { @@ -38,7 +44,9 @@ test("implicit WITH vars referencing each other", () => { hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), }); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `WITH __withVar_4 := 10, __withVar_3 := ( WITH @@ -62,7 +70,8 @@ SELECT { multi pageResults := (__withVar_1 {id, name}), single nextOffset := (__withVar_4 + std::count(__withVar_1)), single hasMore := (SELECT (std::count(__withVar_3) > 10)) -}`); +}` + ); type queryType = $.BaseTypeToTsType<(typeof query)["__element__"]>; tc.assert< @@ -89,25 +98,31 @@ test("simple repeated expression not in select expr", () => { test("explicit WITH block", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal(e.with([numbers], e.select(numbers)).toEdgeQL(), `WITH + assert.equal( + e.with([numbers], e.select(numbers)).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 } -SELECT __withVar_0`); +SELECT __withVar_0` + ); }); test("explicit WITH block in nested query", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal(e - .select({ - nested: e.with([numbers], e.select(numbers)), - }) - .toEdgeQL(), `SELECT { + assert.equal( + e + .select({ + nested: e.with([numbers], e.select(numbers)), + }) + .toEdgeQL(), + `SELECT { multi nested := assert_exists(( WITH __withVar_0 := { 1, 2, 3 } SELECT __withVar_0 )) -}`); +}` + ); }); test("explicit WITH in nested query, var used outside WITH block", () => { @@ -128,12 +143,14 @@ test("explicit WITH block nested in implicit WITH block", () => { const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal(e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -142,7 +159,8 @@ test("explicit WITH block nested in implicit WITH block", () => { SELECT { multi numbers := assert_exists(__withVar_0), multi numbers2 := assert_exists(__withVar_0) -}`); +}` + ); }); test("explicit WITH block nested in explicit WITH block", () => { @@ -150,14 +168,16 @@ test("explicit WITH block nested in explicit WITH block", () => { const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal(e - .with( - [explicitWith], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), `WITH + assert.equal( + e + .with( + [explicitWith], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -165,7 +185,8 @@ test("explicit WITH block nested in explicit WITH block", () => { ) SELECT { multi numbers := assert_exists(__withVar_0) -}`); +}` + ); }); test("explicit WITH block nested in explicit WITH block, sub expr explicitly extracted", () => { @@ -174,14 +195,16 @@ test("explicit WITH block nested in explicit WITH block, sub expr explicitly ext const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal(e - .with( - [explicitWith, number], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), `WITH + assert.equal( + e + .with( + [explicitWith, number], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -190,7 +213,8 @@ test("explicit WITH block nested in explicit WITH block, sub expr explicitly ext ) SELECT { multi numbers := assert_exists(__withVar_0) -}`); +}` + ); }); test("explicit WITH nested in explicit WITH, expr declared in both", () => { @@ -217,15 +241,17 @@ test("explicit WITH block nested in explicit WITH block, sub expr implicitly ext const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal(e - .with( - [explicitWith], - e.select({ - number, - numbers: explicitWith, - }) - ) - .toEdgeQL(), `WITH + assert.equal( + e + .with( + [explicitWith], + e.select({ + number, + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -235,7 +261,8 @@ test("explicit WITH block nested in explicit WITH block, sub expr implicitly ext SELECT { single number := __withVar_2, multi numbers := assert_exists(__withVar_0) -}`); +}` + ); }); test("implicit WITH and explicit WITH in sub expr", () => { @@ -258,7 +285,9 @@ test("implicit WITH and explicit WITH in sub expr", () => { hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), }); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `WITH __withVar_5 := 10, __withVar_4 := ( WITH @@ -286,7 +315,8 @@ SELECT { SELECT __withVar_2 ), single hasMore := (SELECT (std::count(__withVar_4) > 10)) -}`); +}` + ); }); test("explicit WITH nested in implicit WITH + alias implicit", () => { @@ -296,12 +326,14 @@ test("explicit WITH nested in implicit WITH + alias implicit", () => { const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - assert.equal(e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -314,7 +346,8 @@ test("explicit WITH nested in implicit WITH + alias implicit", () => { SELECT { single numbers := __withVar_0, single numbers2 := __withVar_0 -}`); +}` + ); }); test("explicit WITH nested in implicit WITH + alias explicit", () => { @@ -327,12 +360,14 @@ test("explicit WITH nested in implicit WITH + alias explicit", () => { e.select({ numbers, numbersAlias }) ); - assert.equal(e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -345,7 +380,8 @@ test("explicit WITH nested in implicit WITH + alias explicit", () => { SELECT { single numbers := __withVar_0, single numbers2 := __withVar_0 -}`); +}` + ); }); test("explicit WITH nested in implicit WITH + alias outside WITH", () => { @@ -381,14 +417,16 @@ test( e.select(e.op(numbers, "+", numbersAlias)) ); - assert.equal(e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), `WITH + assert.equal( + e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_1 := { 1, 2, 3 }, __withVar_0 := ( WITH @@ -397,7 +435,8 @@ test( ) SELECT { multi numbers := assert_exists(__withVar_0) -}`); +}` + ); } ); @@ -416,14 +455,17 @@ test( e.select(e.op(numbers, "+", numbersAlias2)) ); - assert.equal(e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), `WITH + assert.equal( + e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `\ +WITH __withVar_1 := { 1, 2, 3 }, __withVar_2 := __withVar_1, __withVar_0 := ( @@ -433,7 +475,8 @@ test( ) SELECT { multi numbers := assert_exists(__withVar_0) -}`); +}` + ); } ); @@ -446,27 +489,31 @@ test("query with no WITH block", () => { limit: 1, })); - assert.equal(query.toEdgeQL(), `WITH -__scope_0_defaultHero := DETACHED default::Person[IS default::Hero] + assert.equal( + query.toEdgeQL(), + `\ +WITH + __scope_0_defaultHero := DETACHED default::Person[IS default::Hero] SELECT __scope_0_defaultHero { -id, -single computable := 35, -multi all_heroes := ( - WITH - __scope_1_defaultHero := DETACHED default::Hero - SELECT __scope_1_defaultHero { - __type__ := ( - WITH - __scope_2_schemaObjectType := __scope_1_defaultHero.__type__ - SELECT __scope_2_schemaObjectType { - name - } - ) - } -) + id, + single computable := 35, + multi all_heroes := ( + WITH + __scope_1_defaultHero := DETACHED default::Hero + SELECT __scope_1_defaultHero { + __type__ := ( + WITH + __scope_2_schemaObjectType := __scope_1_defaultHero.__type__ + SELECT __scope_2_schemaObjectType { + name + } + ) + } + ) } ORDER BY __scope_0_defaultHero.name -LIMIT 1`); +LIMIT 1` + ); }); test("repeated expression referencing scoped select object", () => { @@ -483,7 +530,10 @@ test("repeated expression referencing scoped select object", () => { }; }); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `\ +WITH __scope_0_defaultHero_expr := DETACHED default::Hero, __scope_0_defaultHero := (FOR __scope_0_defaultHero_inner IN {__scope_0_defaultHero_expr} UNION ( WITH @@ -496,7 +546,8 @@ SELECT __scope_0_defaultHero { name, single secret := __scope_0_defaultHero.__withVar_1, single secret2 := __scope_0_defaultHero.__withVar_1 -}`); +}` + ); }); test("repeated expr used outside scope", () => { From 95769121a086d0643a3251d84789cb92760953d0 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 15:05:34 -0400 Subject: [PATCH 05/20] Fix for tests --- packages/generate/test/for.test.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/generate/test/for.test.ts b/packages/generate/test/for.test.ts index 2c828c5df..f3715d227 100644 --- a/packages/generate/test/for.test.ts +++ b/packages/generate/test/for.test.ts @@ -4,10 +4,11 @@ import e from "../dbschema/edgeql-js"; test("simple for loop", () => { assert.equal( e.for(e.set(1, 2, 3), (x) => e.op(e.op(x, "*", 2), "+", x)).toEdgeQL(), - `FOR __forVar__0 IN {{ 1, 2, 3 }} - UNION ( - ((__forVar__0 * 2) + __forVar__0) - )` + `\ +FOR __forVar__0 IN {{ 1, 2, 3 }} +UNION ( + ((__forVar__0 * 2) + __forVar__0) +)` ); }); @@ -20,7 +21,9 @@ test("with vars in for loop", () => { }); }); - assert.equal(q1.toEdgeQL(), `FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal( + q1.toEdgeQL(), + `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_0 := std::to_str(__forVar__0) @@ -33,7 +36,8 @@ UNION ( ) ) }) -)`); +)` + ); const q2 = e.for(e.set(1, 2, 3), (i) => { const str = e.to_str(i); @@ -52,7 +56,9 @@ UNION ( })); }); - assert.equal(q2.toEdgeQL(), `FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal( + q2.toEdgeQL(), + `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_1 := std::to_str(__forVar__0) @@ -66,5 +72,6 @@ UNION ( UPDATE __scope_0_defaultHero SET { name := __withVar_1 }))) -)`); +)` + ); }); From b013c57593338b8e0703ca9a20dc7a68b1185082 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 15:29:47 -0400 Subject: [PATCH 06/20] Fix the rest of the tests --- packages/generate/test/insert.test.ts | 718 +++++++++++---------- packages/generate/test/interfaces.test.ts | 1 - packages/generate/test/objectTypes.test.ts | 41 +- packages/generate/test/params.test.ts | 548 ++++++++-------- 4 files changed, 672 insertions(+), 636 deletions(-) diff --git a/packages/generate/test/insert.test.ts b/packages/generate/test/insert.test.ts index f7bff9b6a..cc1f88ae5 100644 --- a/packages/generate/test/insert.test.ts +++ b/packages/generate/test/insert.test.ts @@ -1,423 +1,431 @@ import assert from "node:assert/strict"; -import type { Client } from "edgedb"; +import { type Client, $ } from "edgedb"; import type { Villain } from "../dbschema/edgeql-js/modules/default"; import type { InsertShape } from "../dbschema/edgeql-js/insert"; import e from "../dbschema/edgeql-js"; -import { $ } from "edgedb"; import { setupTests, teardownTests, - TestData, tc, testIfVersionGTE, } from "./setupTeardown"; -let client: Client; -let data: TestData; +describe("insert", () => { + let client: Client; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -test("insert shape check", async () => { - type insertVillainShape = InsertShape<(typeof Villain)["__element__"]>; - const c1: insertVillainShape = { name: e.str("adf") }; -}); - -test("basic insert", async () => { - const q1 = e.insert(e.Movie, { - title: "Black Widow", - genre: e.Genre.Action, - rating: 5, + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); }); - assert.deepEqual(q1.__cardinality__, $.Cardinality.One); - tc.assert>( - true - ); - - await q1.run(client); - await client.execute(`DELETE Movie FILTER .title = 'Black Widow';`); -}); - -test("insert with keyword enum", async () => { - const q1 = e.insert(e.Movie, { - title: "A fine selection", - genre: e.Genre.Select, - rating: 2, + afterAll(async () => { + await teardownTests(client); }); - await q1.run(client); - await e - .delete(e.Movie, (movie) => ({ - filter: e.op(movie.title, "=", "A fine selection"), - })) - .run(client); - await client.execute(`DELETE Movie FILTER .title = 'A fine selection';`); -}); + test("insert shape check", async () => { + type insertVillainShape = InsertShape<(typeof Villain)["__element__"]>; + const c1 = { name: e.str("adf") }; + tc.assert>(true); + }); -test("unless conflict", async () => { - const q0 = e - .insert(e.Movie, { - title: "The Avengers", - rating: 11, - }) - .unlessConflict(); - - assert.deepEqual(q0.__cardinality__, $.Cardinality.AtMostOne); - tc.assert< - tc.IsExact<(typeof q0)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - - const q1 = e - .insert(e.Movie, { - title: "The Avengers", - rating: 11, - }) - .unlessConflict((movie) => ({ - on: movie.title, - })); + test("basic insert", async () => { + const q1 = e.insert(e.Movie, { + title: "Black Widow", + genre: e.Genre.Action, + rating: 5, + }); - assert.deepEqual(q1.__cardinality__, $.Cardinality.AtMostOne); - tc.assert< - tc.IsExact<(typeof q1)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - - const r1 = await q1.run(client); - - assert.equal(r1, null); - tc.assert>(true); - - const q2 = e - .insert(e.Movie, { - title: "The Avengers", - rating: 11, - }) - .unlessConflict((movie) => ({ - on: movie.title, - else: e.update(movie, () => ({ - set: { - rating: 11, - }, - })), - })); + assert.deepEqual(q1.__cardinality__, $.Cardinality.One); + tc.assert>( + true + ); - const r2 = await q2.run(client); + await q1.run(client); + await client.execute(`DELETE Movie FILTER .title = 'Black Widow';`); + }); - const allMovies = await e - .select(e.Movie, () => ({ id: true, title: true, rating: true })) - .run(client); + test("insert with keyword enum", async () => { + const q1 = e.insert(e.Movie, { + title: "A fine selection", + genre: e.Genre.Select, + rating: 2, + }); + + await q1.run(client); + await e + .delete(e.Movie, (movie) => ({ + filter: e.op(movie.title, "=", "A fine selection"), + })) + .run(client); + await client.execute(`DELETE Movie FILTER .title = 'A fine selection';`); + }); - for (const movie of allMovies) { - if (movie.title === "The Avengers") { - assert.equal(movie.rating, 11); - assert.deepEqual(r2.id, movie.id); - } else { - assert.notDeepEqual(movie.rating, 11); + test("unless conflict", async () => { + const q0 = e + .insert(e.Movie, { + title: "The Avengers", + rating: 11, + }) + .unlessConflict(); + + assert.deepEqual(q0.__cardinality__, $.Cardinality.AtMostOne); + tc.assert< + tc.IsExact<(typeof q0)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + + const q1 = e + .insert(e.Movie, { + title: "The Avengers", + rating: 11, + }) + .unlessConflict((movie) => ({ + on: movie.title, + })); + + assert.deepEqual(q1.__cardinality__, $.Cardinality.AtMostOne); + tc.assert< + tc.IsExact<(typeof q1)["__cardinality__"], $.Cardinality.AtMostOne> + >(true); + + const r1 = await q1.run(client); + tc.assert>(true); + + assert.equal(r1, null); + + const q2 = e + .insert(e.Movie, { + title: "The Avengers", + rating: 11, + }) + .unlessConflict((movie) => ({ + on: movie.title, + else: e.update(movie, () => ({ + set: { + rating: 11, + }, + })), + })); + + const r2 = await q2.run(client); + + const allMovies = await e + .select(e.Movie, () => ({ id: true, title: true, rating: true })) + .run(client); + + for (const movie of allMovies) { + if (movie.title === "The Avengers") { + assert.equal(movie.rating, 11); + assert.deepEqual(r2.id, movie.id); + } else { + assert.notDeepEqual(movie.rating, 11); + } } - } - - const q3 = e - .insert(e.Movie, { - title: "The Avengers", - rating: 11, - }) - .unlessConflict((movie) => ({ - on: movie.title, - else: e.select(e.Hero, () => ({ name: true })), - })); - assert.deepEqual(q3.__cardinality__, $.Cardinality.Many); - tc.assert>( - true - ); - assert.equal(q3.__element__.__name__, "std::Object"); - tc.assert>( - true - ); + const q3 = e + .insert(e.Movie, { + title: "The Avengers", + rating: 11, + }) + .unlessConflict((movie) => ({ + on: movie.title, + else: e.select(e.Hero, () => ({ name: true })), + })); + + assert.deepEqual(q3.__cardinality__, $.Cardinality.Many); + tc.assert>( + true + ); + assert.equal(q3.__element__.__name__, "std::Object"); + tc.assert< + tc.IsExact<(typeof q3)["__element__"]["__name__"], "std::Object"> + >(true); + + const r3 = await q3.run(client); + + tc.assert>(true); + }); - const r3 = await q3.run(client); + test("nested insert", async () => { + const q1 = e.insert(e.Villain, { + name: e.str("villain"), + nemesis: e.insert(e.Hero, { + name: "hero", + }), + }); - tc.assert>(true); -}); + const q2 = e.select(q1, () => ({ + name: true, + nemesis: { name: true }, + })); -test("nested insert", async () => { - const q1 = e.insert(e.Villain, { - name: e.str("villain"), - nemesis: e.insert(e.Hero, { - name: "hero", - }), + const result = await q2.run(client); + + assert.deepEqual(result, { + ...result, + name: "villain", + nemesis: { + ...result.nemesis, + name: "hero", + }, + }); + + // cleanup + await client.execute(`delete Villain filter .name = '${result.name}';`); + await client.execute( + `delete Hero filter .name = '${result.nemesis.name}';` + ); + return; }); - const q2 = e.select(q1, () => ({ - name: true, - nemesis: { name: true }, - })); + test("insert type enforcement", async () => { + e.insert(e.Villain, { + // @ts-expect-error card mismatch + nemesis: e.select(e.Hero), + }); - const result = await q2.run(client); + // @ts-expect-error missing required field + e.insert(e.Villain, {}); - expect(result).toMatchObject({ - name: "villain", - nemesis: { name: "hero" }, - }); + e.insert(e.Villain, { + name: e.cast(e.str, e.set()), + }); - // cleanup - await client.execute(`delete Villain filter .name = '${result.name}';`); - await client.execute(`delete Hero filter .name = '${result.nemesis!.name}';`); - return; -}); + e.insert(e.Hero, { + // @ts-expect-error testing invalid type + name: 1234, + // @ts-expect-error testing invalid type + number_of_movies: "Ronin", + }); -test("insert type enforcement", async () => { - e.insert(e.Villain, { - // @ts-expect-error card mismatch - nemesis: e.select(e.Hero), - }); + // should not error on missing required prop 'release_year' + // since it has a default value + e.insert(e.Movie, { + title: "test_movie", + }); - // @ts-expect-error missing required field - e.insert(e.Villain, {}); + e.insert(e.Movie, { + title: "test movie", + rating: null, + profile: null, + // @ts-expect-error release_year is required prop + release_year: null, + }).toEdgeQL(); + + e.insert(e.User, { + username: "spidey", + favourite_movies: e.select(e.Movie, (movie) => ({ + filter: e.op(movie.title, "=", "The Avengers"), + })), + }); - e.insert(e.Villain, { - name: e.cast(e.str, e.set()), + return; }); - e.insert(e.Hero, { - // @ts-expect-error - name: 1234, - // @ts-expect-error - number_of_movies: "Ronin", + test("optional sequence fields", async () => { + const query = e.insert(e.Bag, { + stringsMulti: "asdf", + }); + await query.run(client); }); - // should not error on missing required prop 'release_year' - // since it has a default value - e.insert(e.Movie, { - title: "test_movie", + test("complex raw data in inserts", async () => { + const strings = ["aaa", "bbb"]; + const query = e.insert(e.Bag, { + stringsArr: strings, + stringsMulti: strings as ["aaa", "bbb"], + stringMultiArr: [strings], + boolField: true, + }); + const final = e.select(query, () => ({ + id: true, + stringsMulti: true, + stringsArr: true, + stringMultiArr: true, + boolField: true, + })); + const result = await final.run(client); + assert.deepEqual(result, { + ...result, + stringsMulti: strings, + stringsArr: strings, + stringMultiArr: [strings], + boolField: true, + }); + + e.insert(e.Bag, { + // @ts-expect-error must be string or non-empty array of strings + stringsMulti: strings, + }); }); - e.insert(e.Movie, { - title: "test movie", - rating: null, - profile: null, - // @ts-expect-error release_year is required prop - release_year: null, - }).toEdgeQL(); - - e.insert(e.User, { - username: "spidey", - favourite_movies: e.select(e.Movie, (movie) => ({ - filter: e.op(movie.title, "=", "The Avengers"), - })), - }); + test("insert readonly prop", async () => { + const iq = e.insert(e.Profile, { + slug: "movieslug", + plot_summary: "Stuff happens.", + }); - return; -}); + const qq = e.select(iq, () => ({ + slug: true, + plot_summary: true, + })); -test("optional sequence fields", async () => { - const query = e.insert(e.Bag, { - stringsMulti: "asdf", + const result = await qq.run(client); + assert.deepEqual(result, { + ...result, + slug: "movieslug", + plot_summary: "Stuff happens.", + }); }); - await query.run(client); -}); -test("complex raw data in inserts", async () => { - const strings = ["aaa", "bbb"]; - const query = e.insert(e.Bag, { - stringsArr: strings, - stringsMulti: strings as ["aaa", "bbb"], - stringMultiArr: [strings], - boolField: true, - }); - const final = e.select(query, () => ({ - id: true, - stringsMulti: true, - stringsArr: true, - stringMultiArr: true, - boolField: true, - })); - const result = await final.run(client); - expect(result).toMatchObject({ - stringsMulti: strings, - stringsArr: strings, - stringMultiArr: [strings], - boolField: true, + test("exclude readonly props", () => { + type insertProfileShape = InsertShape<(typeof e)["Profile"]["__element__"]>; + tc.assert< + "plot_summary" | "slug" extends keyof insertProfileShape ? true : false + >(true); }); - e.insert(e.Bag, { - // @ts-expect-error - stringsMulti: strings, - }); -}); - -test("insert readonly prop", async () => { - const iq = e.insert(e.Profile, { - slug: "movieslug", - plot_summary: "Stuff happens.", - }); + test("insert link prop in nested select", async () => { + const inserted = e.insert(e.Movie, { + title: "Iron Man 3", + release_year: 2013, + characters: e.select(e.Hero, (hero) => ({ + filter: e.op(hero.name, "=", "Iron Man"), + "@character_name": e.str("Tony Stark"), + })), + }); - const qq = e.select(iq, () => ({ - slug: true, - plot_summary: true, - })); + const selected = e.select(inserted, () => ({ + characters: { + name: true, + "@character_name": true, + }, + })); - const result = await qq.run(client); - expect(result).toMatchObject({ - slug: "movieslug", - plot_summary: "Stuff happens.", + const result = await selected.run(client); + assert.equal(result.characters[0]["@character_name"], "Tony Stark"); + assert.equal(result.characters[0].name, "Iron Man"); }); -}); -test("exclude readonly props", () => { - type insertProfileShape = InsertShape<(typeof e)["Profile"]["__element__"]>; - tc.assert< - "plot_summary" | "slug" extends keyof insertProfileShape ? true : false - >(true); -}); + test("insert link prop in nested insert", async () => { + const inserted = e.insert(e.Movie, { + title: "Iron Man 2", + release_year: 2010, + characters: e.insert(e.Villain, { + name: "Whiplash", + "@character_name": e.str("Ivan Vanko"), + }), + }); -test("insert link prop in nested select", async () => { - const inserted = e.insert(e.Movie, { - title: "Iron Man 3", - release_year: 2013, - characters: e.select(e.Hero, (hero) => ({ - filter: e.op(hero.name, "=", "Iron Man"), - "@character_name": e.str("Tony Stark"), - })), - }); + const selected = e.select(inserted, () => ({ + characters: { + name: true, + "@character_name": true, + }, + })); - const selected = e.select(inserted, () => ({ - characters: { - name: true, - "@character_name": true, - }, - })); + const result = await selected.run(client); + assert.equal(result.characters[0]["@character_name"], "Ivan Vanko"); + assert.equal(result.characters[0].name, "Whiplash"); + }); - const result = await selected.run(client); - assert.equal(result.characters[0]["@character_name"], "Tony Stark"); - assert.equal(result.characters[0].name, "Iron Man"); -}); + test("no plain data as link prop", async () => { + expect(() => + e.insert(e.Movie, { + title: "Guardians", + release_year: 2014, + characters: e.insert(e.Hero, { + name: "Star-Lord", + "@character_name": "Peter Quill", + }), + }) + ).toThrow(); + }); -test("insert link prop in nested insert", async () => { - const inserted = e.insert(e.Movie, { - title: "Iron Man 2", - release_year: 2010, - characters: e.insert(e.Villain, { - name: "Whiplash", - "@character_name": e.str("Ivan Vanko"), - }), + test("undefined in insert", async () => { + const result = await e + .insert(e.Movie, { + title: "The Eternals", + release_year: undefined, + }) + .run(client); + assert.ok(result.id); }); - const selected = e.select(inserted, () => ({ - characters: { - name: true, - "@character_name": true, - }, - })); + test("invalid insert", async () => { + assert.throws(() => + e + // @ts-expect-error testing invalid type + .insert(e.Movie, () => ({ + title: "Invalid", + })) + .toEdgeQL() + ); + }); - const result = await selected.run(client); - assert.equal(result.characters[0]["@character_name"], "Ivan Vanko"); - assert.equal(result.characters[0].name, "Whiplash"); -}); + test("empty shape insert", async () => { + const res = await e.insert(e.Profile, {}).run(client); -test("no plain data as link prop", async () => { - expect(() => - e.insert(e.Movie, { - title: "Guardians", - release_year: 2014, - characters: e.insert(e.Hero, { - name: "Star-Lord", - "@character_name": "Peter Quill", - }), - }) - ).toThrow(); -}); - -test("undefined in insert", async () => { - const result = await e - .insert(e.Movie, { - title: "The Eternals", - release_year: undefined, - }) - .run(client); - assert.ok(result.id); -}); + assert.deepEqual(Object.keys(res), ["id"]); + }); -test("invalid insert", async () => { - expect(() => - e - // @ts-ignore - .insert(e.Movie, () => ({ - title: "Invalid", + testIfVersionGTE(2)("insert custom ID", async () => { + await e + .insert(e.Hero, { + id: "00000000-0000-0000-0000-000000000000", + name: "asdf", + }) + .run(client); + + await e + .delete(e.Hero, (hero) => ({ + filter: e.op( + hero.id, + "=", + e.uuid("00000000-0000-0000-0000-000000000000") + ), })) - .toEdgeQL() - ).toThrowError(); -}); - -test("empty shape insert", async () => { - const res = await e.insert(e.Profile, {}).run(client); - - assert.deepEqual(Object.keys(res), ["id"]); -}); - -testIfVersionGTE(2)("insert custom ID", async () => { - await e - .insert(e.Hero, { - id: "00000000-0000-0000-0000-000000000000", - name: "asdf", - }) - .run(client); - - await e - .delete(e.Hero, (hero) => ({ - filter: e.op( - hero.id, - "=", - e.uuid("00000000-0000-0000-0000-000000000000") - ), - })) - .run(client); -}); - -test("empty arrays for array and multi properties", async () => { - const query = e.insert(e.Bag, { - stringsMulti: ["asdf"], - stringMultiArr: [], - stringsArr: [], + .run(client); }); - const result = await query.run(client); -}); -test("insert named tuple as shape", async () => { - const query = e.params( - { - profiles: e.array( - e.tuple({ - a: e.str, - b: e.str, - c: e.str, - }) - ), - }, - (params) => - e.for(e.array_unpack(params.profiles), (profile) => - e.insert(e.Profile, profile) - ) - ); - - const result = await query.run(client, { - profiles: [{ a: "a", b: "b", c: "c" }], + test("empty arrays for array and multi properties", async () => { + const query = e.insert(e.Bag, { + stringsMulti: ["asdf"], + stringMultiArr: [], + stringsArr: [], + }); + await query.run(client); }); -}); -test("type union links", async () => { - const query = e.insert(e.Z, { - xy: e.insert(e.Y, { - c: true, - }), + test("insert named tuple as shape", async () => { + const query = e.params( + { + profiles: e.array( + e.tuple({ + a: e.str, + b: e.str, + c: e.str, + }) + ), + }, + (params) => + e.for(e.array_unpack(params.profiles), (profile) => + e.insert(e.Profile, profile) + ) + ); + + await query.run(client, { + profiles: [{ a: "a", b: "b", c: "c" }], + }); }); - await query.run(client); + test("type union links", async () => { + const query = e.insert(e.Z, { + xy: e.insert(e.Y, { + c: true, + }), + }); + + await query.run(client); + }); }); diff --git a/packages/generate/test/interfaces.test.ts b/packages/generate/test/interfaces.test.ts index 027c2414f..df1caa351 100644 --- a/packages/generate/test/interfaces.test.ts +++ b/packages/generate/test/interfaces.test.ts @@ -1,4 +1,3 @@ -import * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; import type { Movie, X, Y, Z } from "../dbschema/interfaces"; diff --git a/packages/generate/test/objectTypes.test.ts b/packages/generate/test/objectTypes.test.ts index 7256bed43..3435c7fa3 100644 --- a/packages/generate/test/objectTypes.test.ts +++ b/packages/generate/test/objectTypes.test.ts @@ -21,10 +21,14 @@ test("property hydration", () => { assert.equal($Hero.__pointers__.name.exclusive, true); assert.equal($Hero.__pointers__.secret_identity.exclusive, false); - assert.equal(e.default.Movie.__element__.__pointers__.profile.exclusive, true); - // expect(e.default.Movie.profile.__exclusive__).toEqual(true); - assert.equal(e.default.Movie.__element__.__pointers__.characters.exclusive, false); - // expect(e.default.Movie.characters.__exclusive__).toEqual(false); + assert.equal( + e.default.Movie.__element__.__pointers__.profile.exclusive, + true + ); + assert.equal( + e.default.Movie.__element__.__pointers__.characters.exclusive, + false + ); }); test("link hydration", () => { @@ -36,19 +40,25 @@ test("link hydration", () => { // type union link assert.equal($Z.__pointers__.xy.__kind__, "link"); - assert.equal($Z.__pointers__.xy.target.__name__, "default::X | default::Y"); assert.deepEqual(Object.keys($Z.__pointers__.xy.target.__pointers__).sort(), [ "__type__", "a", "id", ]); - assert.equal($Z.__pointers__.xy.target.__pointers__.a.target.__name__, "std::str"); + assert.equal( + $Z.__pointers__.xy.target.__pointers__.a.target.__name__, + "std::str" + ); + assert.equal($Z.__pointers__.xy.target.__name__, "default::X | default::Y"); }); const link = $AnnotationSubject.__pointers__.annotations; test("link properties", () => { assert.equal(link.properties["@value"].target.__name__, "std::str"); - assert.deepEqual(link.properties["@value"].cardinality, $.Cardinality.AtMostOne); + assert.deepEqual( + link.properties["@value"].cardinality, + $.Cardinality.AtMostOne + ); assert.equal(link.properties["@value"].__kind__, "property"); }); @@ -106,17 +116,26 @@ test("backlinks", () => { const heroMovie = e.Hero[" ({ limit: 1 })).assert_single().nemesis - .__cardinality__, $.Cardinality.AtMostOne); + assert.deepEqual( + e.select(e.Villain, () => ({ limit: 1 })).assert_single().nemesis + .__cardinality__, + $.Cardinality.AtMostOne + ); assert.equal(e.Profile[" { - const setup = await setupTests(); - ({ client } = setup); -}); +describe("params", () => { + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("simple params", () => { - const query = e.params( - { - str: e.str, - numArr: e.array(e.int64), - optBool: e.optional(e.bool), - }, - (params) => - e.select({ - str: params.str, - nums: e.array_unpack(params.numArr), - x: e.op("true", "if", params.optBool, "else", "false"), - }) - ); - - assert.equal(query.toEdgeQL(), `WITH + test("simple params", () => { + const query = e.params( + { + str: e.str, + numArr: e.array(e.int64), + optBool: e.optional(e.bool), + }, + (params) => + e.select({ + str: params.str, + nums: e.array_unpack(params.numArr), + x: e.op("true", "if", params.optBool, "else", "false"), + }) + ); + + assert.equal( + query.toEdgeQL(), + `\ +WITH __param__str := $str, __param__numArr := >$numArr, __param__optBool := $optBool @@ -43,270 +47,276 @@ SELECT (SELECT { single str := __param__str, multi nums := std::array_unpack(__param__numArr), single x := ("true" IF __param__optBool ELSE "false") -})`); - - expect(() => e.select(query).toEdgeQL()).toThrow(); +})` + ); + + assert.throws(() => e.select(query).toEdgeQL()); + + type paramsType = Parameters[1]; + tc.assert< + tc.IsExact< + paramsType, + { + str: string; + numArr: readonly number[]; + optBool?: boolean | null; + } + > + >(true); + + assert.rejects( + // @ts-expect-error need to pass a params object + query.run(client) + ); + }); - type paramsType = Parameters[1]; - tc.assert< - tc.IsExact< - paramsType, + test("complex params", async () => { + const query = e.params( { - str: string; - numArr: readonly number[]; - optBool?: boolean | null; - } - > - >(true); - - expect( - // @ts-expect-error - query.run(client) - ).rejects.toThrowError(); -}); - -test("complex params", async () => { - const query = e.params( - { - str: e.str, - numArr: e.array(e.int64), - optBool: e.optional(e.bool), - tuple: e.tuple([e.str, e.int32, e.array(e.bool)]), - namedTuple: e.tuple({ a: e.float64, b: e.array(e.bigint), c: e.str }), - jsonTuple: e.tuple([e.json]), - people: e.array( - e.tuple({ name: e.str, age: e.int64, tags: e.array(e.str) }) - ), - }, - (params) => - e.select({ - str: params.str, - nums: e.array_unpack(params.numArr), - x: e.op("true", "if", params.optBool, "else", "false"), - tuple: params.tuple, - tupleArrSlice: params.tuple[2].slice(1, null), - namedTuple: params.namedTuple, - namedTupleA: params.namedTuple.a, - jsonTuple: params.jsonTuple, - people: params.people, - }) - ); - - type paramsType = Parameters[1]; - - tc.assert< - tc.IsExact< - paramsType, + str: e.str, + numArr: e.array(e.int64), + optBool: e.optional(e.bool), + tuple: e.tuple([e.str, e.int32, e.array(e.bool)]), + namedTuple: e.tuple({ a: e.float64, b: e.array(e.bigint), c: e.str }), + jsonTuple: e.tuple([e.json]), + people: e.array( + e.tuple({ name: e.str, age: e.int64, tags: e.array(e.str) }) + ), + }, + (params) => + e.select({ + str: params.str, + nums: e.array_unpack(params.numArr), + x: e.op("true", "if", params.optBool, "else", "false"), + tuple: params.tuple, + tupleArrSlice: params.tuple[2].slice(1, null), + namedTuple: params.namedTuple, + namedTupleA: params.namedTuple.a, + jsonTuple: params.jsonTuple, + people: params.people, + }) + ); + + type paramsType = Parameters[1]; + + tc.assert< + tc.IsExact< + paramsType, + { + str: string; + numArr: readonly number[]; + optBool?: boolean | null; + tuple: readonly [string, number, boolean[]]; + namedTuple: Readonly<{ a: number; b: bigint[]; c: string }>; + jsonTuple: readonly [unknown]; + people: Readonly<{ name: string; age: number; tags: string[] }[]>; + } + > + >(true); + + const result = await query.run(client, { + str: "test string", + numArr: [1, 2, 3], + tuple: ["str", 123, [true, false]], + namedTuple: { a: 123, b: [BigInt(4), BigInt(5)], c: "str" }, + jsonTuple: [{ a: 123, b: ["c", "d"] }], + people: [ + { name: "person a", age: 23, tags: ["a", "b"] }, + { name: "person b", age: 45, tags: ["b", "c"] }, + ], + }); + + assert.deepEqual( + { + ...result, + nums: [...result.nums], + tuple: [...result.tuple], + namedTuple: { + a: result.namedTuple.a, + b: result.namedTuple.b, + c: result.namedTuple.c, + }, + jsonTuple: [...result.jsonTuple], + people: result.people.map((p) => ({ + name: p.name, + age: p.age, + tags: [...p.tags], + })), + }, { - str: string; - numArr: readonly number[]; - optBool?: boolean | null; - tuple: readonly [string, number, boolean[]]; - namedTuple: Readonly<{ a: number; b: bigint[]; c: string }>; - jsonTuple: readonly [unknown]; - people: Readonly<{ name: string; age: number; tags: string[] }[]>; + str: "test string", + nums: [1, 2, 3], + x: null, + tuple: ["str", 123, [true, false]], + tupleArrSlice: [false], + namedTuple: { a: 123, b: [BigInt(4), BigInt(5)], c: "str" }, + namedTupleA: 123, + jsonTuple: [{ a: 123, b: ["c", "d"] }], + people: [ + { name: "person a", age: 23, tags: ["a", "b"] }, + { name: "person b", age: 45, tags: ["b", "c"] }, + ], } - > - >(true); - - const result = await query.run(client, { - str: "test string", - numArr: [1, 2, 3], - tuple: ["str", 123, [true, false]], - namedTuple: { a: 123, b: [BigInt(4), BigInt(5)], c: "str" }, - jsonTuple: [{ a: 123, b: ["c", "d"] }], - people: [ - { name: "person a", age: 23, tags: ["a", "b"] }, - { name: "person b", age: 45, tags: ["b", "c"] }, - ], - }); - - assert.deepEqual({ - ...result, - nums: [...result.nums], - tuple: [...result.tuple], - namedTuple: { - a: result.namedTuple.a, - b: result.namedTuple.b, - c: result.namedTuple.c, - }, - jsonTuple: [...result.jsonTuple], - people: result.people.map((p) => ({ - name: p.name, - age: p.age, - tags: [...p.tags], - })), - }, { - id: (result as any).id, - str: "test string", - nums: [1, 2, 3], - x: null, - tuple: ["str", 123, [true, false]], - tupleArrSlice: [false], - namedTuple: { a: 123, b: [BigInt(4), BigInt(5)], c: "str" }, - namedTupleA: 123, - jsonTuple: [{ a: 123, b: ["c", "d"] }], - people: [ - { name: "person a", age: 23, tags: ["a", "b"] }, - { name: "person b", age: 45, tags: ["b", "c"] }, - ], + ); }); -}); -test("native tuple type params", async () => { - const query = e.params({ test: e.tuple([e.str, e.int64]) }, ($) => - e.select($.test) - ); + test("native tuple type params", async () => { + const query = e.params({ test: e.tuple([e.str, e.int64]) }, ($) => + e.select($.test) + ); - if (versionGTE(3)) { - assert.equal(query.toEdgeQL(), `WITH + if (versionGTE(3)) { + assert.equal( + query.toEdgeQL(), + `WITH __param__test := >$test -SELECT (SELECT __param__test)`); - } else { - assert.equal(query.toEdgeQL(), `WITH +SELECT (SELECT __param__test)` + ); + } else { + assert.equal( + query.toEdgeQL(), + `WITH __param__test := >to_json($test) -SELECT (SELECT __param__test)`); - } - - await query.run(client, { test: ["str", 123] }); -}); +SELECT (SELECT __param__test)` + ); + } -test("all param types", async () => { - const params = { - int16: e.int16, - int32: e.int32, - int64: e.int64, - float32: e.float32, - float64: e.float64, - bigint: e.bigint, - decimal: e.decimal, - bool: e.bool, - json: e.json, - str: e.str, - bytes: e.bytes, - uuid: e.uuid, - datetime: e.datetime, - genre: e.Genre, - duration: e.duration, - local_date: e.cal.local_date, - local_time: e.cal.local_time, - local_datetime: e.cal.local_datetime, - relative_duration: e.cal.relative_duration, - date_duration: e.cal.date_duration, - memory: e.cfg.memory, - }; - - const query = e.params(params, (p) => e.select(p)); - - const args = { - int16: 1, - int32: 2, - int64: 3, - float32: 4, - float64: 5, - bigint: BigInt(6), - decimal: "123.4567890123456789", - bool: true, - json: '{"name": "test"}', - str: "test str", - bytes: new TextEncoder().encode("buffer"), - uuid: "d476ccc2-3e7b-11ec-af13-0f07004006ce", - datetime: new Date(), - genre: "Action" as const, - - duration: new edgedb.Duration(0, 0, 0, 0, 1), - local_date: new edgedb.LocalDate(2021, 11, 25), - local_time: new edgedb.LocalTime(12, 34), - local_datetime: new edgedb.LocalDateTime(2021, 11, 25, 1, 2, 3), - relative_duration: new edgedb.RelativeDuration(1, 2, 3), - date_duration: new edgedb.DateDuration(1, 2, 3, 4), - memory: new edgedb.ConfigMemory(BigInt(125952)), - }; - - const result = await query.run(client, args); - - assert.deepEqual(result, { - // @ts-ignore - id: result.id, - ...args, + await query.run(client, { test: ["str", 123] }); }); - tc.assert< - tc.IsExact< - typeof result, + test("all param types", async () => { + const params = { + int16: e.int16, + int32: e.int32, + int64: e.int64, + float32: e.float32, + float64: e.float64, + bigint: e.bigint, + decimal: e.decimal, + bool: e.bool, + json: e.json, + str: e.str, + bytes: e.bytes, + uuid: e.uuid, + datetime: e.datetime, + genre: e.Genre, + duration: e.duration, + local_date: e.cal.local_date, + local_time: e.cal.local_time, + local_datetime: e.cal.local_datetime, + relative_duration: e.cal.relative_duration, + date_duration: e.cal.date_duration, + memory: e.cfg.memory, + }; + + const query = e.params(params, (p) => e.select(p)); + + const args = { + int16: 1, + int32: 2, + int64: 3, + float32: 4, + float64: 5, + bigint: BigInt(6), + decimal: "123.4567890123456789", + bool: true, + json: '{"name": "test"}', + str: "test str", + bytes: new TextEncoder().encode("buffer"), + uuid: "d476ccc2-3e7b-11ec-af13-0f07004006ce", + datetime: new Date(), + genre: "Action" as const, + + duration: new edgedb.Duration(0, 0, 0, 0, 1), + local_date: new edgedb.LocalDate(2021, 11, 25), + local_time: new edgedb.LocalTime(12, 34), + local_datetime: new edgedb.LocalDateTime(2021, 11, 25, 1, 2, 3), + relative_duration: new edgedb.RelativeDuration(1, 2, 3), + date_duration: new edgedb.DateDuration(1, 2, 3, 4), + memory: new edgedb.ConfigMemory(BigInt(125952)), + }; + + const result = await query.run(client, args); + + tc.assert< + tc.IsExact< + typeof result, + { + int16: number; + int32: number; + int64: number; + float32: number; + float64: number; + bigint: bigint; + decimal: string; + bool: boolean; + json: unknown; + str: string; + bytes: Uint8Array; + uuid: string; + datetime: Date; + genre: "Horror" | "Action" | "RomCom" | "Science Fiction" | "Select"; + duration: edgedb.Duration; + local_date: edgedb.LocalDate; + local_time: edgedb.LocalTime; + local_datetime: edgedb.LocalDateTime; + relative_duration: edgedb.RelativeDuration; + date_duration: edgedb.DateDuration; + memory: edgedb.ConfigMemory; + } + > + >(true); + + assert.deepEqual(result, args); + + const complexQuery = e.params( { - int16: number; - int32: number; - int64: number; - float32: number; - float64: number; - bigint: bigint; - decimal: string; - bool: boolean; - json: unknown; - str: string; - bytes: Uint8Array; - uuid: string; - datetime: Date; - genre: "Horror" | "Action" | "RomCom" | "Science Fiction" | "Select"; - duration: edgedb.Duration; - local_date: edgedb.LocalDate; - local_time: edgedb.LocalTime; - local_datetime: edgedb.LocalDateTime; - relative_duration: edgedb.RelativeDuration; - date_duration: edgedb.DateDuration; - memory: edgedb.ConfigMemory; - } - > - >(true); - - const complexQuery = e.params( - { - tuple: e.tuple(params), - }, - (p) => e.select(p) - ); - - const complexResult = await complexQuery.run(client, { - tuple: args, - }); - - assert.deepEqual(Object.values(complexResult.tuple as any), Object.values(args)); -}); + tuple: e.tuple(params), + }, + (p) => e.select(p) + ); -testIfVersionGTE(2)("v2 param types", async () => { - const params = { - date_duration: e.cal.date_duration, - }; + const complexResult = await complexQuery.run(client, { + tuple: args, + }); - const query = e.params(params, (p) => e.select(p)); - - const args = { - date_duration: new edgedb.DateDuration(1, 2, 3, 4), - }; - - const result = await query.run(client, args); - - assert.deepEqual(result, { - // @ts-ignore - id: result.id, - ...args, + assert.deepEqual(Object.values(complexResult.tuple), Object.values(args)); }); - tc.assert< - tc.IsExact< - typeof result, - { - date_duration: edgedb.DateDuration; - } - > - >(true); -}); + testIfVersionGTE(2)("v2 param types", async () => { + const params = { + date_duration: e.cal.date_duration, + }; + + const query = e.params(params, (p) => e.select(p)); + + const args = { + date_duration: new edgedb.DateDuration(1, 2, 3, 4), + }; + + const result = await query.run(client, args); + + tc.assert< + tc.IsExact< + typeof result, + { + date_duration: edgedb.DateDuration; + } + > + >(true); + + assert.deepEqual(result, { + // @ts-expect-error result includes an id + id: result.id, + ...args, + }); + }); -test("non-runnable return expression", () => { - const reusedExpr = e.set(1, 2, 3); + test("non-runnable return expression", () => { + const reusedExpr = e.set(1, 2, 3); - const query = e.params({}, ($) => e.set(reusedExpr, reusedExpr)); + const query = e.params({}, () => e.set(reusedExpr, reusedExpr)); - expect(() => query.toEdgeQL()).not.toThrow(); + expect(() => query.toEdgeQL()).not.toThrow(); + }); }); From 7a1e320df56b4fe364772369df3adf13c5d1f87e Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 15:36:41 -0400 Subject: [PATCH 07/20] Convert `expect()[.not].throws()` --- packages/generate/test/group.test.ts | 5 ++-- packages/generate/test/insert.test.ts | 5 ++-- packages/generate/test/literals.test.ts | 7 ++--- packages/generate/test/params.test.ts | 2 +- packages/generate/test/primitives.test.ts | 4 +-- packages/generate/test/sets.test.ts | 34 +++++++++++------------ packages/generate/test/with.test.ts | 21 ++++++-------- 7 files changed, 34 insertions(+), 44 deletions(-) diff --git a/packages/generate/test/group.test.ts b/packages/generate/test/group.test.ts index 6ad8fb22d..160ac5d57 100644 --- a/packages/generate/test/group.test.ts +++ b/packages/generate/test/group.test.ts @@ -354,7 +354,7 @@ SELECT __scope_0_defaultMovie_groups { }); test("key override error", async () => { - expect(() => + assert.throws(() => e.group(e.Movie, (movie) => { return { by: { @@ -366,8 +366,7 @@ SELECT __scope_0_defaultMovie_groups { }), }, }; - }) - ).toThrow(); + })); }); // clause ordering in `using` diff --git a/packages/generate/test/insert.test.ts b/packages/generate/test/insert.test.ts index cc1f88ae5..dc2c0985a 100644 --- a/packages/generate/test/insert.test.ts +++ b/packages/generate/test/insert.test.ts @@ -330,7 +330,7 @@ describe("insert", () => { }); test("no plain data as link prop", async () => { - expect(() => + assert.throws(() => e.insert(e.Movie, { title: "Guardians", release_year: 2014, @@ -338,8 +338,7 @@ describe("insert", () => { name: "Star-Lord", "@character_name": "Peter Quill", }), - }) - ).toThrow(); + })); }); test("undefined in insert", async () => { diff --git a/packages/generate/test/literals.test.ts b/packages/generate/test/literals.test.ts index fbda98adc..812f65599 100644 --- a/packages/generate/test/literals.test.ts +++ b/packages/generate/test/literals.test.ts @@ -91,10 +91,9 @@ test("enum literals", () => { expect(e.Genre.__values__).toContain("Horror"); - expect(() => (e.Genre as any).NotAGenre.toEdgeQL()).toThrow(); - expect(() => - e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL() - ).toThrow(); + assert.throws(() => (e.Genre as any).NotAGenre.toEdgeQL()); + assert.throws(() => + e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL()); }); testIfVersionGTE(2)("constructing with strings", async () => { diff --git a/packages/generate/test/params.test.ts b/packages/generate/test/params.test.ts index 75879e1ea..adf9234c4 100644 --- a/packages/generate/test/params.test.ts +++ b/packages/generate/test/params.test.ts @@ -317,6 +317,6 @@ SELECT (SELECT __param__test)` const query = e.params({}, () => e.set(reusedExpr, reusedExpr)); - expect(() => query.toEdgeQL()).not.toThrow(); + assert.doesNotThrow(() => query.toEdgeQL()); }); }); diff --git a/packages/generate/test/primitives.test.ts b/packages/generate/test/primitives.test.ts index ac2cb5cff..fd79ba599 100644 --- a/packages/generate/test/primitives.test.ts +++ b/packages/generate/test/primitives.test.ts @@ -77,8 +77,8 @@ test("range primitives", async () => { assert.equal(e.range(3).toEdgeQL(), `std::range(3)`); assert.equal(e.range(undefined, 8).toEdgeQL(), `std::range({}, 8)`); - expect(() => e.range(new edgedb.Range(null, null))).toThrow(); - expect(() => e.range(edgedb.Range.empty())).toThrow(); + assert.throws(() => e.range(new edgedb.Range(null, null))); + assert.throws(() => e.range(edgedb.Range.empty())); const res = await e .select({ diff --git a/packages/generate/test/sets.test.ts b/packages/generate/test/sets.test.ts index f1b493981..bce2cfcd7 100644 --- a/packages/generate/test/sets.test.ts +++ b/packages/generate/test/sets.test.ts @@ -121,23 +121,23 @@ test("scalar set contructor", () => { }); test("invalid sets", () => { - expect(() => { + assert.throws(() => { // @ts-expect-error e.set(e.Hero, e.int64(1243)); - }).toThrow(); + }); // @ts-expect-error - expect(() => e.set(e.int64(5), e.bigint(BigInt(1234)))).toThrow(); + assert.throws(() => e.set(e.int64(5), e.bigint(BigInt(1234)))); // never - expect(() => { + assert.throws(() => { // @ts-expect-error e.set(e.str("asdf"), e.int64(1243)); - }).toThrow(); - expect(() => { + }); + assert.throws(() => { // @ts-expect-error e.set(e.bool(true), e.bigint(BigInt(14))); - }).toThrow(); + }); }); test("enums", () => { @@ -147,7 +147,7 @@ test("enums", () => { "{ default::Genre.Action, default::Genre.Horror, default::Genre.`Select` }" ); - expect(() => e.set(e.Genre.Action, e.sys.VersionStage.dev as any)).toThrow(); + assert.throws(() => e.set(e.Genre.Action, e.sys.VersionStage.dev as any)); }); test("tuples", async () => { @@ -163,8 +163,8 @@ test("tuples", async () => { [3, "asdf", 5], ]); - expect(() => e.set(e.tuple([1]), e.tuple([1, 2]))).toThrow(); - expect(() => e.set(e.tuple([1]), e.tuple(["asdf"]))).toThrow(); + assert.throws(() => e.set(e.tuple([1]), e.tuple([1, 2]))); + assert.throws(() => e.set(e.tuple([1]), e.tuple(["asdf"]))); }); test("named tuples", async () => { @@ -178,12 +178,11 @@ test("named tuples", async () => { { a: 3, b: "asdf", c: 5 }, ]); - expect(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd" }))).toThrow(); + assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd" }))); expect(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd", b: "qwer" }))); - expect(() => - e.set(e.tuple({ a: "asfd", b: "qwer" }), e.tuple({ a: 1 })) - ).toThrow(); - expect(() => e.set(e.tuple({ a: 1 }), e.tuple({ b: "asfd" }))).toThrow(); + assert.throws(() => + e.set(e.tuple({ a: "asfd", b: "qwer" }), e.tuple({ a: 1 }))); + assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ b: "asfd" }))); }); test("array", async () => { @@ -192,7 +191,6 @@ test("array", async () => { assert.deepEqual(await q1.run(client), [[5, 67], [6]]); - expect(() => - e.set(e.array([e.int16(5)]), e.array(["asdf"]) as any) - ).toThrow(); + assert.throws(() => + e.set(e.array([e.int16(5)]), e.array(["asdf"]) as any)); }); diff --git a/packages/generate/test/with.test.ts b/packages/generate/test/with.test.ts index 6dca3d10f..8ec65a457 100644 --- a/packages/generate/test/with.test.ts +++ b/packages/generate/test/with.test.ts @@ -92,7 +92,7 @@ SELECT { test("simple repeated expression not in select expr", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect(() => e.op(numbers, "+", numbers).toEdgeQL()).toThrow(); + assert.throws(() => e.op(numbers, "+", numbers).toEdgeQL()); }); test("explicit WITH block", () => { @@ -128,14 +128,13 @@ test("explicit WITH block in nested query", () => { test("explicit WITH in nested query, var used outside WITH block", () => { const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - expect(() => + assert.throws(() => e .select({ numbers, nested: e.with([numbers], e.select(numbers)), }) - .toEdgeQL() - ).toThrow(); + .toEdgeQL()); }); test("explicit WITH block nested in implicit WITH block", () => { @@ -223,7 +222,7 @@ test("explicit WITH nested in explicit WITH, expr declared in both", () => { const explicitWith = e.with([numbers], e.select(numbers)); - expect(() => + assert.throws(() => e .with( [explicitWith, numbers], @@ -231,8 +230,7 @@ test("explicit WITH nested in explicit WITH, expr declared in both", () => { numbers: explicitWith, }) ) - .toEdgeQL() - ).toThrow(); + .toEdgeQL()); }); test("explicit WITH block nested in explicit WITH block, sub expr implicitly extracted", () => { @@ -391,15 +389,14 @@ test("explicit WITH nested in implicit WITH + alias outside WITH", () => { const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - expect(() => + assert.throws(() => e .select({ numbers: explicitWith, numbers2: explicitWith, numbersAlias, }) - .toEdgeQL() - ).toThrow(); + .toEdgeQL()); }); test( @@ -554,7 +551,5 @@ test("repeated expr used outside scope", () => { const expr = e.to_str(e.int64(123)); const query = e.tuple([expr, e.select(expr)]); - expect(() => query.toEdgeQL()).toThrow( - /Cannot extract repeated expression into 'WITH' block, expression used outside of 'WITH'able expression/ - ); + assert.throws(() => query.toEdgeQL()); }); From ce34f14096114309b06be899c02b988c2e5647be Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 16:08:17 -0400 Subject: [PATCH 08/20] Convert `toMatchObject` --- packages/generate/test/group.test.ts | 157 ++++---- packages/generate/test/json.test.ts | 182 ++++----- packages/generate/test/literals.test.ts | 35 +- packages/generate/test/operators.test.ts | 458 ++++++++++++----------- packages/generate/test/select.test.ts | 22 +- packages/generate/test/sets.test.ts | 356 +++++++++--------- packages/generate/test/update.test.ts | 20 +- 7 files changed, 614 insertions(+), 616 deletions(-) diff --git a/packages/generate/test/group.test.ts b/packages/generate/test/group.test.ts index 160ac5d57..804105087 100644 --- a/packages/generate/test/group.test.ts +++ b/packages/generate/test/group.test.ts @@ -2,27 +2,32 @@ import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; -import e, { $infer } from "../dbschema/edgeql-js"; +import e, { type $infer } from "../dbschema/edgeql-js"; import { setupTests, teardownTests, - TestData, + type TestData, versionGTE, } from "./setupTeardown"; -let client: edgedb.Client; -let data: TestData; +describe("group", () => { + let client: edgedb.Client; + let data: TestData; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client, data } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -if (versionGTE(2)) { + if (!versionGTE(2)) { + return test.skip("group requires EdgeDB 2+", () => { + assert.ok(true); + }); + } test("basic group", async () => { const query = e.group(e.Movie, (movie) => { const release_year = movie.release_year; @@ -59,15 +64,9 @@ if (versionGTE(2)) { > >(true); - expect(result).toMatchObject([ - { - grouping: ["release_year"], - }, - { - grouping: ["release_year"], - }, - ]); assert.equal(result.length, 2); + assert.equal(result[0].grouping[0], "release_year"); + assert.equal(result[1].grouping[0], "release_year"); assert.equal(result[0].elements.length, 1); assert.ok(result[0].elements[0].title); assert.ok(result[1].elements[0].release_year); @@ -113,12 +112,8 @@ if (versionGTE(2)) { > >(true); - expect(result).toMatchObject([ - { - grouping: ["release_year"], - }, - ]); assert.equal(result.length, 1); + assert.equal(result[0].grouping[0], "release_year"); assert.equal(result[0].elements.length, 1); assert.ok(result[0].elements[0].title); assert.ok(result[0].elements[0].release_year); @@ -157,15 +152,19 @@ if (versionGTE(2)) { assert.equal(result.length, 2); assert.equal(result[0].elements.length, 1); - expect( - result.filter((val) => val.key.title === data.civil_war.title)[0] - ).toMatchObject({ + const civilWar = result.find( + (val) => val.key.title === data.civil_war.title + ); + assert.deepEqual(civilWar, { + ...civilWar, key: { title: data.civil_war.title, ry: data.civil_war.release_year }, grouping: ["title", "ry"], }); - expect( - result.filter((val) => val.key.title === data.the_avengers.title)[0] - ).toMatchObject({ + const theAvengers = result.find( + (val) => val.key.title === data.the_avengers.title + ); + assert.deepEqual(theAvengers, { + ...theAvengers, key: { title: data.the_avengers.title, ry: data.the_avengers.release_year, @@ -190,18 +189,10 @@ if (versionGTE(2)) { }; }); - // TODO: switch back after https://github.com/edgedb/edgedb/issues/3967 - // is fixed - // expect(query.toEdgeQL()).toEqual(`WITH - // __scope_0_defaultMovie := DETACHED default::Movie - // GROUP __scope_0_defaultMovie - // USING - // __withVar_1 := std::len(__scope_0_defaultMovie.title), - // title1 := __withVar_1, - // title2 := __withVar_1, - // title3 := __withVar_1 - // BY title1, title2, title3`); - assert.equal(query.toEdgeQL(), `WITH + assert.equal( + query.toEdgeQL(), + `\ +WITH __scope_0_defaultMovie_expr := DETACHED default::Movie, __scope_0_defaultMovie := (FOR __scope_0_defaultMovie_inner IN {__scope_0_defaultMovie_expr} UNION ( WITH @@ -226,7 +217,8 @@ SELECT __scope_0_defaultMovie_groups { release_year, single len := __scope_0_defaultMovie_groups.elements.__withVar_1 } -}`); +}` + ); const result = await query.run(client); type result = typeof result; @@ -272,12 +264,10 @@ SELECT __scope_0_defaultMovie_groups { const result = await query.run(client); assert.equal(result.length, 4); - expect(result).toMatchObject([ - { grouping: ["title", "year"] }, - { grouping: ["title", "year"] }, - { grouping: ["title", "rating"] }, - { grouping: ["title", "rating"] }, - ]); + assert.deepEqual(result[0].grouping, ["title", "year"]); + assert.deepEqual(result[1].grouping, ["title", "year"]); + assert.deepEqual(result[2].grouping, ["title", "rating"]); + assert.deepEqual(result[3].grouping, ["title", "rating"]); assert.equal(result[0].elements.length, 1); }); @@ -298,13 +288,11 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - assert.equal(query.toEdgeQL().includes(`BY (title, len), (year, rating)`), true); - expect(result[0].grouping).toMatchObject([ - "title", - "len", - "year", - "rating", - ]); + assert.equal( + query.toEdgeQL().includes(`BY (title, len), (year, rating)`), + true + ); + assert.deepEqual(result[0].grouping, ["title", "len", "year", "rating"]); assert.equal(result.length, 2); }); @@ -340,16 +328,22 @@ SELECT __scope_0_defaultMovie_groups { }); const result = await query.run(client); - assert.equal(query.toEdgeQL().includes(`BY rollup(title, len, year)`), true); - assert.equal(result - .map((r) => r.grouping) - .every((g) => { - return ( - (!g[0] || g[0] === "title") && - (!g[1] || g[1] === "len") && - (!g[2] || g[2] === "year") - ); - }), true); + assert.equal( + query.toEdgeQL().includes(`BY rollup(title, len, year)`), + true + ); + assert.equal( + result + .map((r) => r.grouping) + .every((g) => { + return ( + (!g[0] || g[0] === "title") && + (!g[1] || g[1] === "len") && + (!g[2] || g[2] === "year") + ); + }), + true + ); assert.equal(result.length, 7); }); @@ -366,7 +360,8 @@ SELECT __scope_0_defaultMovie_groups { }), }, }; - })); + }) + ); }); // clause ordering in `using` @@ -389,28 +384,4 @@ SELECT __scope_0_defaultMovie_groups { const result = await query.run(client); assert.deepEqual(result[0].grouping, ["ccc", "ccc2", "len", "len2"]); }); - - // depends on https://github.com/edgedb/edgedb/issues/3951 - // test("composition", async () => { - // const group = e.group(e.Movie, movie => ({ - // by: {ry: movie.release_year}, - // })); - - // const query = e.select(group, () => ({ - // grouping: true, - // key: {ry: true}, - // elements: { - // title: true, - // release_year: true, - // }, - // })); - - // const result = await query.run(client); - - // expect(result.length).toEqual(2); - // expect(result[0].elements[0].title).toBeDefined(); - // expect(result[1].elements[0].release_year).toBeDefined(); - // }); -} else { - test.skip("group only supported in EdgeDB v2", () => {}); -} +}); diff --git a/packages/generate/test/json.test.ts b/packages/generate/test/json.test.ts index fee8e8407..6d14b64db 100644 --- a/packages/generate/test/json.test.ts +++ b/packages/generate/test/json.test.ts @@ -3,103 +3,111 @@ import * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; import e from "../dbschema/edgeql-js"; -import { setupTests, teardownTests, TestData } from "./setupTeardown"; +import { setupTests, teardownTests } from "./setupTeardown"; -let client: edgedb.Client; -let data: TestData; +describe("json", () => { + let client: edgedb.Client; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("basic select", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - order_by: movie.title, - })); + test("basic select", async () => { + const query = e.select(e.Movie, (movie) => ({ + title: true, + order_by: movie.title, + })); - const result = await query.runJSON(client); - tc.assert>(true); - assert.equal( - result, - '[{"title" : "Captain America: Civil War"}, {"title" : "The Avengers"}]' - ); -}); + const result = await query.runJSON(client); + tc.assert>(true); + assert.equal( + result, + '[{"title" : "Captain America: Civil War"}, {"title" : "The Avengers"}]' + ); + }); -test("select one", async () => { - const query = e.select(e.Movie, (movie) => ({ - title: true, - filter: e.op(movie.title, "=", "The Avengers"), - })); + test("select one", async () => { + const query = e.select(e.Movie, (movie) => ({ + title: true, + filter: e.op(movie.title, "=", "The Avengers"), + })); - const result = await query.runJSON(client); - tc.assert>(true); - assert.equal(result, '[{"title" : "The Avengers"}]'); -}); + const result = await query.runJSON(client); + tc.assert>(true); + assert.equal(result, '[{"title" : "The Avengers"}]'); + }); -test("json properties", async () => { - const jsonData = { arg: { nested: ["hello", 1234, true, null] } }; - const inserted = await e - .insert(e.Bag, { - stringsMulti: ["asdf"], - jsonField: jsonData, - }) - .run(client); + test("json properties", async () => { + const jsonData = { arg: { nested: ["hello", 1234, true, null] } }; + const inserted = await e + .insert(e.Bag, { + stringsMulti: ["asdf"], + jsonField: jsonData, + }) + .run(client); - const selected = await e - .select(e.Bag, (bag) => ({ - filter_single: e.op(bag.id, "=", e.uuid(inserted.id)), - id: true, - jsonField: true, - })) - .run(client); - tc.assert< - tc.IsExact - >(true); - expect(selected?.jsonField).toMatchObject(jsonData); -}); + const selected = await e + .select(e.Bag, (bag) => ({ + filter_single: e.op(bag.id, "=", e.uuid(inserted.id)), + id: true, + jsonField: true, + })) + .run(client); + tc.assert< + tc.IsExact + >(true); + assert.ok(selected); + assert.deepEqual(selected.jsonField, { + ...(selected.jsonField as Record), + ...jsonData, + }); + }); -test("json param", async () => { - const jsonData = { arg: { nested: ["hello", 1234, true, null] } }; - const result = await e - .params({ data: e.json }, (params) => - e.select({ - data: params.data, - }) - ) - .run(client, { data: jsonData }); - expect(result.data).toMatchObject(jsonData); -}); + test("json param", async () => { + const jsonData = { arg: { nested: ["hello", 1234, true, null] } }; + const result = await e + .params({ data: e.json }, (params) => + e.select({ + data: params.data, + }) + ) + .run(client, { data: jsonData }); + assert.deepEqual(result.data, { + ...(result.data as Record), + ...jsonData, + }); + }); -test("json read/write equivalents", async () => { - const data = [5, "asdf", { sup: [3] }, ["asdf", 1234, false, null]]; - for (const datum of data) { - assert.deepEqual(await e.json(datum).run(client), datum); - } -}); + test("json read/write equivalents", async () => { + const data = [5, "asdf", { sup: [3] }, ["asdf", 1234, false, null]]; + for (const datum of data) { + assert.deepEqual(await e.json(datum).run(client), datum); + } + }); -test("serialize data classes", async () => { - const datum = [ - new Date("2022-07-18T21:42:46.569Z"), - new edgedb.LocalDate(2020, 1, 1), - new edgedb.LocalDateTime(2020, 1, 1), - new edgedb.LocalTime(2, 22), - new edgedb.Duration(3), - new edgedb.RelativeDuration(3), - new edgedb.DateDuration(1), - ]; - assert.deepEqual(await e.json(datum).run(client), [ - "2022-07-18T21:42:46.569Z", - "2020-01-01", - "2020-01-01T00:00:00", - "02:22:00", - "P3Y", - "P3Y", - "P1Y", - ]); + test("serialize data classes", async () => { + const datum = [ + new Date("2022-07-18T21:42:46.569Z"), + new edgedb.LocalDate(2020, 1, 1), + new edgedb.LocalDateTime(2020, 1, 1), + new edgedb.LocalTime(2, 22), + new edgedb.Duration(3), + new edgedb.RelativeDuration(3), + new edgedb.DateDuration(1), + ]; + assert.deepEqual(await e.json(datum).run(client), [ + "2022-07-18T21:42:46.569Z", + "2020-01-01", + "2020-01-01T00:00:00", + "02:22:00", + "P3Y", + "P3Y", + "P1Y", + ]); + }); }); diff --git a/packages/generate/test/literals.test.ts b/packages/generate/test/literals.test.ts index 812f65599..40de04da6 100644 --- a/packages/generate/test/literals.test.ts +++ b/packages/generate/test/literals.test.ts @@ -28,8 +28,14 @@ test("literals", () => { e.std.datetime(new Date("2021-06-25T02:01:13.681Z")).toEdgeQL(), `'2021-06-25T02:01:13.681Z'` ); - assert.equal(e.std.decimal("1234.1234n").toEdgeQL(), `"1234.1234n"`); - assert.equal(e.std.duration(duration).toEdgeQL(), `'PT5H6M7.00800901S'`); + assert.equal( + e.std.decimal("1234.1234n").toEdgeQL(), + `"1234.1234n"` + ); + assert.equal( + e.std.duration(duration).toEdgeQL(), + `'PT5H6M7.00800901S'` + ); assert.equal(e.std.int16(144.1235).toEdgeQL(), `144.1235`); assert.equal(e.std.int64(1234.15).toEdgeQL(), `1234.15`); assert.equal(e.std.float64(1234.1234).toEdgeQL(), `1234.1234`); @@ -55,12 +61,18 @@ test("literals", () => { e.std.uuid(uuid).toEdgeQL(), `"317fee4c-0da5-45aa-9980-fedac211bfb6"` ); - assert.equal(e.cal.local_date(localdate).toEdgeQL(), `'2021-10-31'`); + assert.equal( + e.cal.local_date(localdate).toEdgeQL(), + `'2021-10-31'` + ); assert.equal( e.cal.local_datetime(localdatetime).toEdgeQL(), `'2021-10-31T21:45:30'` ); - assert.equal(e.cal.local_time(localtime).toEdgeQL(), `'15:15:00'`); + assert.equal( + e.cal.local_time(localtime).toEdgeQL(), + `'15:15:00'` + ); assert.equal( e.cal.relative_duration(relduration).toEdgeQL(), `'P1Y2M21D'` @@ -87,20 +99,25 @@ test("enum literals", () => { assert.deepEqual(e.Genre.Horror.__element__.__kind__, TypeKind.enum); assert.deepEqual(horror.__element__, e.Genre); assert.deepEqual(horror.__cardinality__, edgedb.$.Cardinality.One); - assert.equal(e.literal(e.Genre, "Horror").toEdgeQL(), `default::Genre.Horror`); + assert.equal( + e.literal(e.Genre, "Horror").toEdgeQL(), + `default::Genre.Horror` + ); - expect(e.Genre.__values__).toContain("Horror"); + assert.ok(e.Genre.__values__.includes("Horror")); assert.throws(() => (e.Genre as any).NotAGenre.toEdgeQL()); - assert.throws(() => - e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL()); + assert.throws(() => e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL()); }); testIfVersionGTE(2)("constructing with strings", async () => { const { client } = await setupTests(); const dateString = new Date().toISOString(); - assert.deepEqual(await (await e.datetime(dateString).run(client)).toISOString(), dateString); + assert.deepEqual( + (await e.datetime(dateString).run(client)).toISOString(), + dateString + ); await e.int64("12341234").run(client); await e.cal.local_datetime("1999-03-31T15:17:00").run(client); diff --git a/packages/generate/test/operators.test.ts b/packages/generate/test/operators.test.ts index ba708d368..90eec5aa6 100644 --- a/packages/generate/test/operators.test.ts +++ b/packages/generate/test/operators.test.ts @@ -4,234 +4,236 @@ import type { Client } from "edgedb"; import e from "../dbschema/edgeql-js"; import * as $ from "../src/syntax/reflection"; -import { TestData, setupTests, teardownTests } from "./setupTeardown"; - -let client: Client; -let data: TestData; - -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -function checkOperatorExpr( - expr: T, - name: T["__name__"], - args: any[], - returnType: T["__element__"], - cardinality: T["__cardinality__"], - edgeql?: string -) { - assert.deepEqual(expr.__name__, name); - assert.deepEqual( - superjson.stringify(expr.__args__), - superjson.stringify(args.filter((arg) => arg !== undefined)) - ); - assert.deepEqual(expr.__element__, returnType); - assert.deepEqual(expr.__cardinality__, cardinality); - - if (edgeql) { - assert.deepEqual(expr.toEdgeQL(), edgeql); +import { setupTests, teardownTests } from "./setupTeardown"; + +describe("operators", () => { + let client: Client; + + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); + + afterAll(async () => { + await teardownTests(client); + }); + + function checkOperatorExpr( + expr: T, + name: T["__name__"], + args: any[], + returnType: T["__element__"], + cardinality: T["__cardinality__"], + edgeql?: string + ) { + assert.deepEqual(expr.__name__, name); + assert.deepEqual( + superjson.stringify(expr.__args__), + superjson.stringify(args.filter((arg) => arg !== undefined)) + ); + assert.deepEqual(expr.__element__, returnType); + assert.deepEqual(expr.__cardinality__, cardinality); + + if (edgeql) { + assert.deepEqual(expr.toEdgeQL(), edgeql); + } } -} - -test("slice and index ops", () => { - checkOperatorExpr( - e.str("test string")["2:5"], - "[]", - [e.str("test string"), [e.int64(2), e.int64(5)]], - e.str, - $.Cardinality.One, - `"test string"[2:5]` - ); - - checkOperatorExpr( - e.str("test string").slice(e.int64(2), e.int64(5)), - "[]", - [e.str("test string"), [e.int64(2), e.int64(5)]], - e.str, - $.Cardinality.One, - `"test string"[2:5]` - ); - - checkOperatorExpr( - e.array([BigInt(1), BigInt(2), BigInt(3)])["1:2"], - "[]", - [e.array([BigInt(1), BigInt(2), BigInt(3)]), [e.int64(1), e.int64(2)]], - e.array(e.bigint), - $.Cardinality.One, - `[1n, 2n, 3n][1:2]` - ); - - checkOperatorExpr( - e.str("test string")[3], - "[]", - [e.str("test string"), e.int64(3)], - e.str, - $.Cardinality.One, - `"test string"[3]` - ); - - checkOperatorExpr( - e.str("test string").index(e.int64(3)), - "[]", - [e.str("test string"), e.int64(3)], - e.str, - $.Cardinality.One, - `"test string"[3]` - ); - - checkOperatorExpr( - e.array([BigInt(1), BigInt(2), BigInt(3)])[2], - "[]", - [e.array([BigInt(1), BigInt(2), BigInt(3)]), e.int64(2)], - e.bigint, - $.Cardinality.One, - `[1n, 2n, 3n][2]` - ); - - checkOperatorExpr( - e.to_json(e.str(`{"name":"Bob"}`)).name, - "[]", - [e.to_json(e.str(`{"name":"Bob"}`)), e.str("name")], - e.json, - $.Cardinality.One, - `std::to_json("{\\\"name\\\":\\\"Bob\\\"}")["name"]` - ); - - checkOperatorExpr( - e.to_json(e.str(`{"name":"Bob"}`)).destructure(e.str("name")), - "[]", - [e.to_json(e.str(`{"name":"Bob"}`)), e.str("name")], - e.json, - $.Cardinality.One, - `std::to_json("{\\\"name\\\":\\\"Bob\\\"}")["name"]` - ); -}); - -test("if else op", () => { - checkOperatorExpr( - e.op( - "this", - "if", - e.op(42, "=", e.literal(e.float32, 42)), - "else", - e.str("that") - ), - "if_else", - [e.str("this"), e.op(42, "=", e.literal(e.float32, 42)), e.str("that")], - e.str, - $.Cardinality.One, - `"this" IF (42 = 42) ELSE "that"` - ); - - checkOperatorExpr( - e.op("this", "if", e.cast(e.bool, e.set()), "else", "that"), - "if_else", - [e.str("this"), e.cast(e.bool, e.set()), e.str("that")], - e.str, - $.Cardinality.Empty, - `"this" IF {} ELSE "that"` - ); - - checkOperatorExpr( - e.op("this", "if", e.set(e.bool(true), e.bool(false)), "else", "that"), - "if_else", - [e.str("this"), e.set(e.bool(true), e.bool(false)), e.str("that")], - e.str, - $.Cardinality.AtLeastOne, - `"this" IF { true, false } ELSE "that"` - ); - - checkOperatorExpr( - e.op( - e.str("this"), - "if", - e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), - "else", - e.set(e.str("that"), e.str("other")) - ), - "if_else", - [ - e.str("this"), - e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), - e.set(e.str("that"), e.str("other")), - ], - e.str, - $.Cardinality.AtLeastOne, - `"this" IF (42 = 42) ELSE { "that", "other" }` - ); - - checkOperatorExpr( - e.op( - e.cast(e.str, e.set()), - "if", - e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), - "else", - e.set(e.str("that"), e.str("other")) - ), - "if_else", - [ - e.cast(e.str, e.set()), - e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), - e.set(e.str("that"), e.str("other")), - ], - e.str, - $.Cardinality.Many, - `{} IF (42 = 42) ELSE { "that", "other" }` - ); - - checkOperatorExpr( - e.op( - "this", - "if", - e.op(42, "=", e.literal(e.float32, 42)), - "else", - e.cast(e.str, e.set()) - ), - "if_else", - [ - e.str("this"), - e.op(42, "=", e.literal(e.float32, 42)), - e.cast(e.str, e.set()), - ], - e.str, - $.Cardinality.AtMostOne, - `"this" IF (42 = 42) ELSE {}` - ); -}); - -test("non-literal args", async () => { - const loki = e.select(e.Hero, (hero) => ({ - filter: e.op(hero.name, "=", "Loki"), - })); - const thanos = e.select(e.Villain, (villain) => ({ - filter: e.op(villain.name, "=", "Thanos"), - })); - - const expr = e.op(loki, "??", thanos); - - expect(expr.run(client)).resolves.not.toThrow(); -}); - -test("cardinalities for set of operators", async () => { - const t1 = e.op(e.cast(e.str, e.set()), "??", "default"); - assert.deepEqual(t1.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(await t1.run(client), "default"); - - const t2 = e.op(e.cast(e.str, e.set()), "union", "default"); - assert.deepEqual(t2.__cardinality__, $.Cardinality.One); - assert.equal(await t1.run(client), "default"); - - const t3 = e.op("one", "union", "two"); - assert.deepEqual(t3.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(await t3.run(client), ["one", "two"]); - const t4 = e.op("distinct", "default"); - assert.deepEqual(t4.__cardinality__, $.Cardinality.One); - assert.equal(await t4.run(client), "default"); + test("slice and index ops", () => { + checkOperatorExpr( + e.str("test string")["2:5"], + "[]", + [e.str("test string"), [e.int64(2), e.int64(5)]], + e.str, + $.Cardinality.One, + `"test string"[2:5]` + ); + + checkOperatorExpr( + e.str("test string").slice(e.int64(2), e.int64(5)), + "[]", + [e.str("test string"), [e.int64(2), e.int64(5)]], + e.str, + $.Cardinality.One, + `"test string"[2:5]` + ); + + checkOperatorExpr( + e.array([BigInt(1), BigInt(2), BigInt(3)])["1:2"], + "[]", + [e.array([BigInt(1), BigInt(2), BigInt(3)]), [e.int64(1), e.int64(2)]], + e.array(e.bigint), + $.Cardinality.One, + `[1n, 2n, 3n][1:2]` + ); + + checkOperatorExpr( + e.str("test string")[3], + "[]", + [e.str("test string"), e.int64(3)], + e.str, + $.Cardinality.One, + `"test string"[3]` + ); + + checkOperatorExpr( + e.str("test string").index(e.int64(3)), + "[]", + [e.str("test string"), e.int64(3)], + e.str, + $.Cardinality.One, + `"test string"[3]` + ); + + checkOperatorExpr( + e.array([BigInt(1), BigInt(2), BigInt(3)])[2], + "[]", + [e.array([BigInt(1), BigInt(2), BigInt(3)]), e.int64(2)], + e.bigint, + $.Cardinality.One, + `[1n, 2n, 3n][2]` + ); + + checkOperatorExpr( + e.to_json(e.str(`{"name":"Bob"}`)).name, + "[]", + [e.to_json(e.str(`{"name":"Bob"}`)), e.str("name")], + e.json, + $.Cardinality.One, + `std::to_json("{\\\"name\\\":\\\"Bob\\\"}")["name"]` + ); + + checkOperatorExpr( + e.to_json(e.str(`{"name":"Bob"}`)).destructure(e.str("name")), + "[]", + [e.to_json(e.str(`{"name":"Bob"}`)), e.str("name")], + e.json, + $.Cardinality.One, + `std::to_json("{\\\"name\\\":\\\"Bob\\\"}")["name"]` + ); + }); + + test("if else op", () => { + checkOperatorExpr( + e.op( + "this", + "if", + e.op(42, "=", e.literal(e.float32, 42)), + "else", + e.str("that") + ), + "if_else", + [e.str("this"), e.op(42, "=", e.literal(e.float32, 42)), e.str("that")], + e.str, + $.Cardinality.One, + `"this" IF (42 = 42) ELSE "that"` + ); + + checkOperatorExpr( + e.op("this", "if", e.cast(e.bool, e.set()), "else", "that"), + "if_else", + [e.str("this"), e.cast(e.bool, e.set()), e.str("that")], + e.str, + $.Cardinality.Empty, + `"this" IF {} ELSE "that"` + ); + + checkOperatorExpr( + e.op("this", "if", e.set(e.bool(true), e.bool(false)), "else", "that"), + "if_else", + [e.str("this"), e.set(e.bool(true), e.bool(false)), e.str("that")], + e.str, + $.Cardinality.AtLeastOne, + `"this" IF { true, false } ELSE "that"` + ); + + checkOperatorExpr( + e.op( + e.str("this"), + "if", + e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), + "else", + e.set(e.str("that"), e.str("other")) + ), + "if_else", + [ + e.str("this"), + e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), + e.set(e.str("that"), e.str("other")), + ], + e.str, + $.Cardinality.AtLeastOne, + `"this" IF (42 = 42) ELSE { "that", "other" }` + ); + + checkOperatorExpr( + e.op( + e.cast(e.str, e.set()), + "if", + e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), + "else", + e.set(e.str("that"), e.str("other")) + ), + "if_else", + [ + e.cast(e.str, e.set()), + e.op(e.literal(e.int64, 42), "=", e.literal(e.float32, 42)), + e.set(e.str("that"), e.str("other")), + ], + e.str, + $.Cardinality.Many, + `{} IF (42 = 42) ELSE { "that", "other" }` + ); + + checkOperatorExpr( + e.op( + "this", + "if", + e.op(42, "=", e.literal(e.float32, 42)), + "else", + e.cast(e.str, e.set()) + ), + "if_else", + [ + e.str("this"), + e.op(42, "=", e.literal(e.float32, 42)), + e.cast(e.str, e.set()), + ], + e.str, + $.Cardinality.AtMostOne, + `"this" IF (42 = 42) ELSE {}` + ); + }); + + test("non-literal args", async () => { + const loki = e.select(e.Hero, (hero) => ({ + filter: e.op(hero.name, "=", "Loki"), + })); + const thanos = e.select(e.Villain, (villain) => ({ + filter: e.op(villain.name, "=", "Thanos"), + })); + + const expr = e.op(loki, "??", thanos); + + const result = await expr.run(client); + assert.ok(result); + }); + + test("cardinalities for set of operators", async () => { + const t1 = e.op(e.cast(e.str, e.set()), "??", "default"); + assert.deepEqual(t1.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(await t1.run(client), "default"); + + const t2 = e.op(e.cast(e.str, e.set()), "union", "default"); + assert.deepEqual(t2.__cardinality__, $.Cardinality.One); + assert.equal(await t1.run(client), "default"); + + const t3 = e.op("one", "union", "two"); + assert.deepEqual(t3.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await t3.run(client), ["one", "two"]); + + const t4 = e.op("distinct", "default"); + assert.deepEqual(t4.__cardinality__, $.Cardinality.One); + assert.equal(await t4.run(client), "default"); + }); }); diff --git a/packages/generate/test/select.test.ts b/packages/generate/test/select.test.ts index a2b028a49..7bf72bf95 100644 --- a/packages/generate/test/select.test.ts +++ b/packages/generate/test/select.test.ts @@ -190,7 +190,6 @@ describe("select", () => { type q1 = $.BaseTypeToTsType<(typeof q1)["__element__"]>; tc.assert>(true); assert.deepEqual(no_shape.__element__.__shape__, q1.__element__.__shape__); - // expect(no_shape.__element__.__shape__).toEqual({id: true}); // allow override shape const override_shape = e.select(q1, () => ({ @@ -436,14 +435,6 @@ describe("select", () => { tc.IsExact<(typeof q9)["__cardinality__"], $.Cardinality.AtMostOne> >(true); assert.deepEqual(q9.__cardinality__, $.Cardinality.AtMostOne); - - // const q10 = e.select(e.Villain, villain => ({ - // filter_single: e.op(villain.name, "=", e.cast(e.str, e.set())) - // })); - // tc.assert>( - // true - // ); - // expect(q10.__cardinality__).toEqual($.Cardinality.Empty); }); test("infer cardinality - object type filters", () => { @@ -586,8 +577,9 @@ describe("select", () => { ); const result = await query.run(client); - expect(result).toMatchObject(data.iron_man); - assert.deepEqual(result?.villains, [{ id: data.thanos.id }]); + assert.ok(result); + assert.deepEqual(result, { ...result, ...data.iron_man }); + assert.deepEqual(result.villains, [{ id: data.thanos.id }]); }); test("computables", async () => { @@ -627,9 +619,6 @@ describe("select", () => { assert.deepEqual(results?.id, data.cap.id); assert.equal(results?.computable, 35); - // expect( - // results?.all_heroes.every(hero => hero.__type__.name === "default::Hero") - // ).toEqual(true); }); test("type intersections", async () => { @@ -642,9 +631,6 @@ describe("select", () => { results.every((person) => typeof person.id === "string"), true ); - // expect( - // results.every(person => person.__type__.name === "default::Hero") - // ).toEqual(true); }); test("type intersections - static", () => { @@ -1361,7 +1347,7 @@ SELECT __scope_0_defaultPerson { filter_single: e.op(movie.genre, "=", e.Genre.Action), })); - await expect(query.run(client)).rejects.toThrow(CardinalityViolationError); + assert.rejects(() => query.run(client), CardinalityViolationError); }); test("type union links", async () => { diff --git a/packages/generate/test/sets.test.ts b/packages/generate/test/sets.test.ts index bce2cfcd7..74c1465a4 100644 --- a/packages/generate/test/sets.test.ts +++ b/packages/generate/test/sets.test.ts @@ -1,196 +1,208 @@ import assert from "node:assert/strict"; -import { $, Client } from "edgedb"; +import { $, type Client } from "edgedb"; import { tc } from "./setupTeardown"; -import e, { $infer } from "../dbschema/edgeql-js"; -import { setupTests, teardownTests, TestData } from "./setupTeardown"; +import e, { type $infer } from "../dbschema/edgeql-js"; +import { setupTests, teardownTests } from "./setupTeardown"; import { TypeKind } from "edgedb/dist/reflection"; -let client: Client; -let data: TestData; +describe("sets", () => { + let client: Client; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -test("empty sets", async () => { - assert.equal(e.set(), null); - - const stringSet = e.cast(e.str, e.set()); - assert.equal(stringSet.toEdgeQL(), `{}`); - tc.assert, null>>(true); + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); - const $Hero = e.Hero.__element__; - const heroSet = e.cast($Hero, e.set()); - assert.equal(heroSet.toEdgeQL(), `{}`); - tc.assert, null>>(true); + afterAll(async () => { + await teardownTests(client); + }); - const int32Set = e.cast(e.int32, e.set()); - assert.equal(int32Set.toEdgeQL(), `{}`); - tc.assert, null>>(true); - tc.assert< - tc.IsExact<(typeof int32Set)["__element__"]["__name__"], "std::number"> - >(true); + test("empty sets", async () => { + assert.equal(e.set(), null); - assert.equal(await e.cast(e.int64, e.set()).run(client), null); -}); + const stringSet = e.cast(e.str, e.set()); + assert.equal(stringSet.toEdgeQL(), `{}`); + tc.assert, null>>(true); -test("object set contructor", async () => { - const hero = e.set(e.default.Hero); - assert.equal(hero.id.__element__.__name__, "std::uuid"); - assert.equal(hero.name.__element__.__name__, "std::str"); - assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); - - const person = e.set(e.default.Hero, e.default.Villain); - assert.equal(person.id.__element__.__name__, "std::uuid"); - assert.equal(person.name.__element__.__name__, "std::str"); - assert.deepEqual((person as any).number_of_movies, undefined); - assert.equal(person.__element__.__name__, "default::Hero UNION default::Villain"); - - const merged = e.set(e.default.Hero, e.default.Villain, e.default.Person); - assert.equal( - merged.__element__.__name__, - "default::Hero UNION default::Villain UNION default::Person" - ); - - assert.equal( - e.set(e.select(e.Hero), e.select(e.Villain)).toEdgeQL(), - `{ (SELECT DETACHED default::Hero), (SELECT DETACHED default::Villain) }` - ); - - assert.deepEqual(await e - .select(e.set(e.select(e.Hero), e.select(e.Villain)), (obj) => ({ - name: true, - filter: e.op(obj.name, "=", "Thanos"), - })) - .assert_single() - .run(client), { name: "Thanos" }); - - assert.deepEqual(await e - .select(e.set(e.Hero, e.Villain), (obj) => ({ - name: true, - filter: e.op(obj.name, "=", "Thanos"), - })) - .assert_single() - .run(client), { name: "Thanos" }); -}); + const $Hero = e.Hero.__element__; + const heroSet = e.cast($Hero, e.set()); + assert.equal(heroSet.toEdgeQL(), `{}`); + tc.assert, null>>(true); -test("scalar set contructor", () => { - // single elements - const _f1 = e.set("asdf"); - assert.equal(_f1.__element__.__name__, "std::str"); - assert.deepEqual(_f1.__cardinality__, $.Cardinality.One); - assert.deepEqual(_f1.__element__.__kind__, $.TypeKind.scalar); - assert.equal(_f1.toEdgeQL(), `{ "asdf" }`); - type _f1 = $infer; - tc.assert>(true); - - const _f4 = e.set(e.int32(42)); - assert.equal(_f4.__element__.__name__, "std::int32"); - assert.deepEqual(_f4.__cardinality__, $.Cardinality.One); - assert.deepEqual(_f4.__element__.__kind__, $.TypeKind.scalar); - assert.equal(_f4.toEdgeQL(), `{ 42 }`); - type _f4 = $infer; - tc.assert>(true); - - // multiple elements - const _f2 = e.set("asdf", "qwer", e.str("poiu")); - assert.equal(_f2.__element__.__name__, "std::str"); - assert.deepEqual(_f2.__cardinality__, $.Cardinality.AtLeastOne); - assert.equal(_f2.toEdgeQL(), `{ "asdf", "qwer", "poiu" }`); - type _f2 = $infer; - tc.assert>(true); - - const _f3 = e.set(1, 2, 3); - assert.equal(_f3.__element__.__name__, "std::number"); - assert.deepEqual(_f3.__cardinality__, $.Cardinality.AtLeastOne); - assert.equal(_f3.toEdgeQL(), `{ 1, 2, 3 }`); - type _f3 = $infer; - tc.assert>(true); - - // implicit casting - const _f5 = e.set(5, e.literal(e.float32, 1234.5)); - assert.equal(_f5.__element__.__name__, "std::number"); - assert.equal(_f5.toEdgeQL(), `{ 5, 1234.5 }`); - type _f5 = $infer; - tc.assert>(true); -}); + const int32Set = e.cast(e.int32, e.set()); + assert.equal(int32Set.toEdgeQL(), `{}`); + tc.assert, null>>(true); + tc.assert< + tc.IsExact<(typeof int32Set)["__element__"]["__name__"], "std::number"> + >(true); -test("invalid sets", () => { - assert.throws(() => { - // @ts-expect-error - e.set(e.Hero, e.int64(1243)); + assert.equal(await e.cast(e.int64, e.set()).run(client), null); }); - // @ts-expect-error - assert.throws(() => e.set(e.int64(5), e.bigint(BigInt(1234)))); + test("object set contructor", async () => { + const hero = e.set(e.default.Hero); + assert.equal(hero.id.__element__.__name__, "std::uuid"); + assert.equal(hero.name.__element__.__name__, "std::str"); + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); + + const person = e.set(e.default.Hero, e.default.Villain); + assert.equal(person.id.__element__.__name__, "std::uuid"); + assert.equal(person.name.__element__.__name__, "std::str"); + assert.deepEqual((person as any).number_of_movies, undefined); + assert.equal( + person.__element__.__name__, + "default::Hero UNION default::Villain" + ); + + const merged = e.set(e.default.Hero, e.default.Villain, e.default.Person); + assert.equal( + merged.__element__.__name__, + "default::Hero UNION default::Villain UNION default::Person" + ); + + assert.equal( + e.set(e.select(e.Hero), e.select(e.Villain)).toEdgeQL(), + `{ (SELECT DETACHED default::Hero), (SELECT DETACHED default::Villain) }` + ); + + assert.deepEqual( + await e + .select(e.set(e.select(e.Hero), e.select(e.Villain)), (obj) => ({ + name: true, + filter: e.op(obj.name, "=", "Thanos"), + })) + .assert_single() + .run(client), + { name: "Thanos" } + ); + + assert.deepEqual( + await e + .select(e.set(e.Hero, e.Villain), (obj) => ({ + name: true, + filter: e.op(obj.name, "=", "Thanos"), + })) + .assert_single() + .run(client), + { name: "Thanos" } + ); + }); - // never - assert.throws(() => { - // @ts-expect-error - e.set(e.str("asdf"), e.int64(1243)); + test("scalar set contructor", () => { + // single elements + const _f1 = e.set("asdf"); + assert.equal(_f1.__element__.__name__, "std::str"); + assert.deepEqual(_f1.__cardinality__, $.Cardinality.One); + assert.deepEqual(_f1.__element__.__kind__, $.TypeKind.scalar); + assert.equal(_f1.toEdgeQL(), `{ "asdf" }`); + type _f1 = $infer; + tc.assert>(true); + + const _f4 = e.set(e.int32(42)); + assert.equal(_f4.__element__.__name__, "std::int32"); + assert.deepEqual(_f4.__cardinality__, $.Cardinality.One); + assert.deepEqual(_f4.__element__.__kind__, $.TypeKind.scalar); + assert.equal(_f4.toEdgeQL(), `{ 42 }`); + type _f4 = $infer; + tc.assert>(true); + + // multiple elements + const _f2 = e.set("asdf", "qwer", e.str("poiu")); + assert.equal(_f2.__element__.__name__, "std::str"); + assert.deepEqual(_f2.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(_f2.toEdgeQL(), `{ "asdf", "qwer", "poiu" }`); + type _f2 = $infer; + tc.assert>(true); + + const _f3 = e.set(1, 2, 3); + assert.equal(_f3.__element__.__name__, "std::number"); + assert.deepEqual(_f3.__cardinality__, $.Cardinality.AtLeastOne); + assert.equal(_f3.toEdgeQL(), `{ 1, 2, 3 }`); + type _f3 = $infer; + tc.assert>(true); + + // implicit casting + const _f5 = e.set(5, e.literal(e.float32, 1234.5)); + assert.equal(_f5.__element__.__name__, "std::number"); + assert.equal(_f5.toEdgeQL(), `{ 5, 1234.5 }`); + type _f5 = $infer; + tc.assert>(true); }); - assert.throws(() => { - // @ts-expect-error - e.set(e.bool(true), e.bigint(BigInt(14))); + + test("invalid sets", () => { + assert.throws(() => { + // @ts-expect-error invalid set + e.set(e.Hero, e.int64(1243)); + }); + + // @ts-expect-error invalid set + assert.throws(() => e.set(e.int64(5), e.bigint(BigInt(1234)))); + + // never + assert.throws(() => { + // @ts-expect-error invalid set + e.set(e.str("asdf"), e.int64(1243)); + }); + assert.throws(() => { + // @ts-expect-error invalid set + e.set(e.bool(true), e.bigint(BigInt(14))); + }); }); -}); -test("enums", () => { - const query = e.set(e.Genre.Action, e.Genre.Horror, e.Genre.Select); - assert.equal( - query.toEdgeQL(), - "{ default::Genre.Action, default::Genre.Horror, default::Genre.`Select` }" - ); + test("enums", () => { + const query = e.set(e.Genre.Action, e.Genre.Horror, e.Genre.Select); + assert.equal( + query.toEdgeQL(), + "{ default::Genre.Action, default::Genre.Horror, default::Genre.`Select` }" + ); - assert.throws(() => e.set(e.Genre.Action, e.sys.VersionStage.dev as any)); -}); + assert.throws(() => e.set(e.Genre.Action, e.sys.VersionStage.dev as any)); + }); -test("tuples", async () => { - const q1 = e.set( - e.tuple([1, "asdf", e.int16(214)]), - e.tuple([3, "asdf", e.int64(5)]) - ); - assert.deepEqual(q1.__element__.__kind__, TypeKind.tuple); - assert.equal(q1.__element__.__items__[0].__name__, "std::number"); - assert.equal(q1.__element__.__items__[1].__name__, "std::str"); - expect(await q1.run(client)).toMatchObject([ - [1, "asdf", 214], - [3, "asdf", 5], - ]); - - assert.throws(() => e.set(e.tuple([1]), e.tuple([1, 2]))); - assert.throws(() => e.set(e.tuple([1]), e.tuple(["asdf"]))); -}); + test("tuples", async () => { + const q1 = e.set( + e.tuple([1, "asdf", e.int16(214)]), + e.tuple([3, "asdf", e.int64(5)]) + ); + assert.deepEqual(q1.__element__.__kind__, TypeKind.tuple); + assert.equal(q1.__element__.__items__[0].__name__, "std::number"); + assert.equal(q1.__element__.__items__[1].__name__, "std::str"); + assert.deepEqual(await q1.run(client), [ + [1, "asdf", 214], + [3, "asdf", 5], + ]); + + assert.throws(() => e.set(e.tuple([1]), e.tuple([1, 2]))); + assert.throws(() => e.set(e.tuple([1]), e.tuple(["asdf"]))); + }); -test("named tuples", async () => { - const q1 = e.set( - e.tuple({ a: 1, b: "asdf", c: e.int16(214) }), - e.tuple({ a: 3, b: "asdf", c: e.int64(5) }) - ); - assert.deepEqual(q1.__element__.__kind__, TypeKind.namedtuple); - expect(await q1.run(client)).toMatchObject([ - { a: 1, b: "asdf", c: 214 }, - { a: 3, b: "asdf", c: 5 }, - ]); - - assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd" }))); - expect(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd", b: "qwer" }))); - assert.throws(() => - e.set(e.tuple({ a: "asfd", b: "qwer" }), e.tuple({ a: 1 }))); - assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ b: "asfd" }))); -}); + test("named tuples", async () => { + const q1 = e.set( + e.tuple({ a: 1, b: "asdf", c: e.int16(214) }), + e.tuple({ a: 3, b: "asdf", c: e.int64(5) }) + ); + assert.deepEqual(q1.__element__.__kind__, TypeKind.namedtuple); + assert.deepEqual(await q1.run(client), [ + { a: 1, b: "asdf", c: 214 }, + { a: 3, b: "asdf", c: 5 }, + ]); + + assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd" }))); + assert.throws(() => + e.set(e.tuple({ a: 1 }), e.tuple({ a: "asfd", b: "qwer" })) + ); + assert.throws(() => + e.set(e.tuple({ a: "asfd", b: "qwer" }), e.tuple({ a: 1 })) + ); + assert.throws(() => e.set(e.tuple({ a: 1 }), e.tuple({ b: "asfd" }))); + }); -test("array", async () => { - const q1 = e.set(e.array([e.int16(5), e.int64(67)]), e.array([6])); - assert.deepEqual(q1.__element__.__kind__, TypeKind.array); + test("array", async () => { + const q1 = e.set(e.array([e.int16(5), e.int64(67)]), e.array([6])); + assert.deepEqual(q1.__element__.__kind__, TypeKind.array); - assert.deepEqual(await q1.run(client), [[5, 67], [6]]); + assert.deepEqual(await q1.run(client), [[5, 67], [6]]); - assert.throws(() => - e.set(e.array([e.int16(5)]), e.array(["asdf"]) as any)); + assert.throws(() => e.set(e.array([e.int16(5)]), e.array(["asdf"]) as any)); + }); }); diff --git a/packages/generate/test/update.test.ts b/packages/generate/test/update.test.ts index 2769d18ef..db7d965f0 100644 --- a/packages/generate/test/update.test.ts +++ b/packages/generate/test/update.test.ts @@ -95,12 +95,15 @@ test("scoped update", async () => { assert.deepEqual(result, { id: data.spidey.id }); - assert.deepEqual(await e - .select(e.Hero, (hero) => ({ - name: true, - filter_single: e.op(hero.id, "=", e.uuid(result!.id)), - })) - .run(client), { name: `The Amazing ${data.spidey.name}` }); + assert.deepEqual( + await e + .select(e.Hero, (hero) => ({ + name: true, + filter_single: e.op(hero.id, "=", e.uuid(result!.id)), + })) + .run(client), + { name: `The Amazing ${data.spidey.name}` } + ); }); test("update link property", async () => { @@ -204,9 +207,8 @@ test("exclude readonly props", () => { }); test("empty update", async () => { - expect( - e.update(e.Movie, () => ({ set: {} })).run(client) - ).resolves.not.toThrow(); + const result = await e.update(e.Movie, () => ({ set: {} })).run(client); + assert.ok(result); }); test("update with filter_single", async () => { From c033f7539d1f4c92c95958f4f9fd4049dc22b703 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 18 May 2023 16:19:30 -0400 Subject: [PATCH 09/20] Wrap all suites in a describe block --- packages/generate/test/cardinality.test.ts | 166 +-- packages/generate/test/casts.test.ts | 80 +- packages/generate/test/cli.test.ts | 16 +- packages/generate/test/collections.test.ts | 893 +++++++------- packages/generate/test/delete.test.ts | 94 +- packages/generate/test/detached.test.ts | 72 +- packages/generate/test/for.test.ts | 76 +- packages/generate/test/functions.test.ts | 1220 ++++++++++---------- packages/generate/test/globals.test.ts | 154 ++- packages/generate/test/interfaces.test.ts | 9 +- packages/generate/test/literals.test.ts | 227 ++-- packages/generate/test/objectTypes.test.ts | 363 +++--- packages/generate/test/paths.test.ts | 237 ++-- packages/generate/test/primitives.test.ts | 300 ++--- packages/generate/test/queries.test.ts | 79 +- packages/generate/test/update.test.ts | 390 +++---- packages/generate/test/with.test.ts | 637 +++++----- 17 files changed, 2593 insertions(+), 2420 deletions(-) diff --git a/packages/generate/test/cardinality.test.ts b/packages/generate/test/cardinality.test.ts index 799210c68..38f4fb43c 100644 --- a/packages/generate/test/cardinality.test.ts +++ b/packages/generate/test/cardinality.test.ts @@ -2,96 +2,98 @@ import type { $ } from "edgedb"; import type { cardutil } from "../src/syntax/cardinality"; import { tc } from "./setupTeardown"; -test("multiply$.Cardinality", () => { - tc.assert< - tc.IsExact< - cardutil.multiplyCardinalities<$.Cardinality.One, $.Cardinality.One>, - $.Cardinality.One - > - >(true); - tc.assert< - tc.IsExact< - cardutil.multiplyCardinalities< - $.Cardinality.AtLeastOne, +describe("cardinality", () => { + test("multiply$.Cardinality", () => { + tc.assert< + tc.IsExact< + cardutil.multiplyCardinalities<$.Cardinality.One, $.Cardinality.One>, + $.Cardinality.One + > + >(true); + tc.assert< + tc.IsExact< + cardutil.multiplyCardinalities< + $.Cardinality.AtLeastOne, + $.Cardinality.Many + >, $.Cardinality.Many - >, - $.Cardinality.Many - > - >(true); - tc.assert< - tc.IsExact< - cardutil.multiplyCardinalities< - $.Cardinality.AtLeastOne, + > + >(true); + tc.assert< + tc.IsExact< + cardutil.multiplyCardinalities< + $.Cardinality.AtLeastOne, + $.Cardinality.AtLeastOne + >, $.Cardinality.AtLeastOne - >, - $.Cardinality.AtLeastOne - > - >(true); - tc.assert< - tc.IsExact< - cardutil.multiplyCardinalities< - $.Cardinality.AtMostOne, + > + >(true); + tc.assert< + tc.IsExact< + cardutil.multiplyCardinalities< + $.Cardinality.AtMostOne, + $.Cardinality.AtMostOne + >, $.Cardinality.AtMostOne - >, - $.Cardinality.AtMostOne - > - >(true); - tc.assert< - tc.IsExact< - cardutil.multiplyCardinalities<$.Cardinality.Empty, $.Cardinality.Many>, - $.Cardinality.Empty - > - >(true); -}); + > + >(true); + tc.assert< + tc.IsExact< + cardutil.multiplyCardinalities<$.Cardinality.Empty, $.Cardinality.Many>, + $.Cardinality.Empty + > + >(true); + }); -test("merge$.Cardinality", () => { - tc.assert< - tc.IsExact< - cardutil.mergeCardinalities<$.Cardinality.AtMostOne, $.Cardinality.One>, - $.Cardinality.AtLeastOne - > - >(true); + test("merge$.Cardinality", () => { + tc.assert< + tc.IsExact< + cardutil.mergeCardinalities<$.Cardinality.AtMostOne, $.Cardinality.One>, + $.Cardinality.AtLeastOne + > + >(true); - tc.assert< - tc.IsExact< - cardutil.mergeCardinalities< - $.Cardinality.AtMostOne, - $.Cardinality.AtMostOne - >, - $.Cardinality.Many - > - >(true); + tc.assert< + tc.IsExact< + cardutil.mergeCardinalities< + $.Cardinality.AtMostOne, + $.Cardinality.AtMostOne + >, + $.Cardinality.Many + > + >(true); - tc.assert< - tc.IsExact< - cardutil.mergeCardinalities<$.Cardinality.One, $.Cardinality.One>, - $.Cardinality.AtLeastOne - > - >(true); + tc.assert< + tc.IsExact< + cardutil.mergeCardinalities<$.Cardinality.One, $.Cardinality.One>, + $.Cardinality.AtLeastOne + > + >(true); - tc.assert< - tc.IsExact< - cardutil.mergeCardinalities< - $.Cardinality.Empty, + tc.assert< + tc.IsExact< + cardutil.mergeCardinalities< + $.Cardinality.Empty, + $.Cardinality.AtLeastOne + >, $.Cardinality.AtLeastOne - >, - $.Cardinality.AtLeastOne - > - >(true); + > + >(true); - tc.assert< - tc.IsExact< - cardutil.mergeCardinalities<$.Cardinality.One, $.Cardinality.Many>, - $.Cardinality.AtLeastOne - > - >(true); + tc.assert< + tc.IsExact< + cardutil.mergeCardinalities<$.Cardinality.One, $.Cardinality.Many>, + $.Cardinality.AtLeastOne + > + >(true); - tc.assert< - tc.IsExact< - cardutil.mergeCardinalitiesVariadic< - [$.Cardinality.One, $.Cardinality.Empty, $.Cardinality.AtMostOne] - >, - $.Cardinality.AtLeastOne - > - >(true); + tc.assert< + tc.IsExact< + cardutil.mergeCardinalitiesVariadic< + [$.Cardinality.One, $.Cardinality.Empty, $.Cardinality.AtMostOne] + >, + $.Cardinality.AtLeastOne + > + >(true); + }); }); diff --git a/packages/generate/test/casts.test.ts b/packages/generate/test/casts.test.ts index 5fbb51439..6280dbeb6 100644 --- a/packages/generate/test/casts.test.ts +++ b/packages/generate/test/casts.test.ts @@ -2,42 +2,50 @@ import assert from "node:assert/strict"; import e from "../dbschema/edgeql-js"; import type { $Movie } from "../dbschema/edgeql-js/modules/default"; -import { setupTests, tc, TestData, teardownTests } from "./setupTeardown"; +import { setupTests, tc, teardownTests } from "./setupTeardown"; import type { Client } from "edgedb"; -let client: Client; -let data: TestData; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -test("casting", () => { - const primitiveCast = e.cast(e.float32, e.float64(3.14)); - tc.assert< - tc.IsExact<(typeof primitiveCast)["__element__"], (typeof e)["float64"]> - >(true); - assert.equal(primitiveCast.toEdgeQL(), `(3.14)`); -}); - -test("enums", async () => { - assert.equal(e.cast(e.Genre, e.str("Horror")).toEdgeQL(), `("Horror")`); - const result = await e.cast(e.Genre, e.str("Horror")).run(client); - assert.equal(result, "Horror"); -}); - -test("scalar literals", () => { - assert.equal(e.cast(e.json, "hello").toEdgeQL(), `("hello")`); -}); - -test("object type empty set", () => { - const expr = e.cast(e.Movie, e.set()); - - assert.equal(expr.toEdgeQL(), `{}`); - - tc.assert>(true); +describe("casts", () => { + let client: Client; + + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); + + afterAll(async () => { + await teardownTests(client); + }); + + test("casting", () => { + const primitiveCast = e.cast(e.float32, e.float64(3.14)); + tc.assert< + tc.IsExact<(typeof primitiveCast)["__element__"], (typeof e)["float64"]> + >(true); + assert.equal( + primitiveCast.toEdgeQL(), + `(3.14)` + ); + }); + + test("enums", async () => { + assert.equal( + e.cast(e.Genre, e.str("Horror")).toEdgeQL(), + `("Horror")` + ); + const result = await e.cast(e.Genre, e.str("Horror")).run(client); + assert.equal(result, "Horror"); + }); + + test("scalar literals", () => { + assert.equal(e.cast(e.json, "hello").toEdgeQL(), `("hello")`); + }); + + test("object type empty set", () => { + const expr = e.cast(e.Movie, e.set()); + + assert.equal(expr.toEdgeQL(), `{}`); + + tc.assert>(true); + }); }); diff --git a/packages/generate/test/cli.test.ts b/packages/generate/test/cli.test.ts index 06baf80f5..8af133fae 100644 --- a/packages/generate/test/cli.test.ts +++ b/packages/generate/test/cli.test.ts @@ -5,10 +5,12 @@ import { execSync } from "child_process"; const QBDIR = path.resolve(__dirname, ".."); -test("basic generate", async () => { - execSync(`yarn generate edgeql-js --force-overwrite`, { - stdio: "inherit", - }); - const qbIndex = path.resolve(QBDIR, "dbschema", "edgeql-js", "index.ts"); - assert.equal(await adapter.exists(qbIndex), true); -}, 60000); +describe("cli", () => { + test("basic generate", async () => { + execSync(`yarn generate edgeql-js --force-overwrite`, { + stdio: "inherit", + }); + const qbIndex = path.resolve(QBDIR, "dbschema", "edgeql-js", "index.ts"); + assert.equal(await adapter.exists(qbIndex), true); + }, 60000); +}); diff --git a/packages/generate/test/collections.test.ts b/packages/generate/test/collections.test.ts index a218b4ed4..e43299bee 100644 --- a/packages/generate/test/collections.test.ts +++ b/packages/generate/test/collections.test.ts @@ -1,446 +1,493 @@ import assert from "node:assert/strict"; import type { Client } from "edgedb"; import * as $ from "../src/syntax/reflection"; -import e, { $infer, objectTypeToTupleType } from "../dbschema/edgeql-js"; +import e, { type $infer, objectTypeToTupleType } from "../dbschema/edgeql-js"; import type { sys } from "../dbschema/interfaces"; import { tc } from "./setupTeardown"; -import { setupTests, teardownTests, TestData } from "./setupTeardown"; +import { setupTests, teardownTests, type TestData } from "./setupTeardown"; import type { $Genre, $year } from "../dbschema/edgeql-js/modules/default"; import type { $float64, $str, $uuid } from "../dbschema/edgeql-js/modules/std"; -let client: Client; -let data: TestData; +describe("collections", () => { + let client: Client; + let data: TestData; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -test("array literal", async () => { - const strArrayType = e.array(e.str); - assert.deepEqual(strArrayType.__kind__, $.TypeKind.array); - assert.deepEqual(strArrayType.__element__.__kind__, $.TypeKind.scalar); - assert.equal(strArrayType.__element__.__name__, "std::str"); - - const arg = e.array(["asdf", e.str("qwer")]); - - type arg = $.setToTsType; - tc.assert>(true); - assert.deepEqual(arg.__kind__, $.ExpressionKind.Array); - assert.deepEqual(arg.__element__.__kind__, $.TypeKind.array); - assert.deepEqual(arg.__cardinality__, $.Cardinality.One); - assert.deepEqual(arg.__element__.__element__.__kind__, $.TypeKind.scalar); - assert.equal(arg.__element__.__element__.__name__, "std::str"); - const result = await client.querySingle(e.select(arg).toEdgeQL()); - assert.deepEqual(result, ["asdf", "qwer"]); - - const arg1 = arg[1]; - tc.assert>( - true - ); - assert.deepEqual(arg1.__kind__, $.ExpressionKind.Operator); - tc.assert>( - true - ); - assert.deepEqual(arg1.__cardinality__, $.Cardinality.One); - tc.assert>( - true - ); - assert.equal(arg1.__element__.__name__, "std::str"); - assert.equal(await e.select(arg1).run(client), "qwer"); - - const multiArray = e.array(["asdf", e.set(e.str("qwer"), e.str("erty"))]); - - type multiArray = $.setToTsType; - tc.assert>(true); - assert.deepEqual(multiArray.__kind__, $.ExpressionKind.Array); - assert.deepEqual(multiArray.__element__.__kind__, $.TypeKind.array); - - assert.deepEqual(multiArray.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(multiArray.__element__.__element__.__kind__, $.TypeKind.scalar); - assert.equal(multiArray.__element__.__element__.__name__, "std::str"); - const multiArrayResult = await client.query(e.select(multiArray).toEdgeQL()); - assert.deepEqual(multiArrayResult, [ - ["asdf", "qwer"], - ["asdf", "erty"], - ]); - - const multi0 = multiArray[0]; - tc.assert< - tc.IsExact<(typeof multi0)["__cardinality__"], $.Cardinality.AtLeastOne> - >(true); - assert.deepEqual(multi0.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(await e.select(multi0).run(client), ["asdf", "asdf"]); - - // array slicing - const arr = e.str_split(e.str("zxcvbnm"), e.str("")); - const sliceResult = await e - .select({ - reverseIndex: arr["-2"], - slice24: arr["2:4"], - slice2: arr["2:"], - slice4: arr[":4"], - reverseSlice2: arr["-2:"], - reverseSlice4: arr[":-4"], - reverseSlice24: arr["-4:-2"], - }) - .run(client); - tc.assert< - tc.IsExact< - typeof sliceResult, - { - reverseIndex: string; - slice24: string[]; - slice2: string[]; - slice4: string[]; - reverseSlice2: string[]; - reverseSlice4: string[]; - reverseSlice24: string[]; - } - > - >(true); - assert.deepEqual(JSON.stringify(sliceResult), JSON.stringify({ - reverseIndex: "n", - slice24: ["c", "v"], - slice2: ["c", "v", "b", "n", "m"], - slice4: ["z", "x", "c", "v"], - reverseSlice2: ["n", "m"], - reverseSlice4: ["z", "x", "c"], - reverseSlice24: ["v", "b"], - })); - - // @ts-expect-error - arr["str"]; - // @ts-expect-error - arr[":"]; -}); - -test("tuple literal", async () => { - const tupleType = e.tuple([e.str, e.int64]); - assert.deepEqual(tupleType.__kind__, $.TypeKind.tuple); - assert.deepEqual(tupleType.__items__[0].__kind__, $.TypeKind.scalar); - assert.equal(tupleType.__items__[0].__name__, "std::str"); - assert.deepEqual(tupleType.__items__[1].__kind__, $.TypeKind.scalar); - assert.equal(tupleType.__items__[1].__name__, "std::int64"); - - const myTuple = e.tuple(["asdf", 45]); - type myTuple = $.setToTsType; - tc.assert>(true); - assert.deepEqual(myTuple.__element__.__kind__, $.TypeKind.tuple); - assert.deepEqual(myTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); - assert.equal(myTuple.__element__.__items__[0].__name__, "std::str"); - assert.deepEqual(myTuple.__element__.__items__[1].__kind__, $.TypeKind.scalar); - assert.equal(myTuple.__element__.__items__[1].__name__, "std::number"); - const myTupleResult = await client.querySingle(e.select(myTuple).toEdgeQL()); - assert.deepEqual(myTupleResult, ["asdf", 45]); - const myTuplePath0 = myTuple[0]; - const myTuplePath1 = myTuple[1]; - tc.assert, string>>(true); - tc.assert, number>>(true); - assert.equal(await e.select(myTuplePath0).run(client), "asdf"); - assert.equal(await e.select(myTuplePath1).run(client), 45); - - const multiTuple = e.tuple(["asdf", e.set(e.str("qwer"), e.str("erty"))]); - tc.assert< - tc.IsExact< - $infer, - [[string, string], ...[string, string][]] - > - >(true); - assert.deepEqual(multiTuple.__kind__, $.ExpressionKind.Tuple); - assert.deepEqual(multiTuple.__element__.__kind__, $.TypeKind.tuple); - assert.deepEqual(multiTuple.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(multiTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); - assert.equal(multiTuple.__element__.__items__[0].__name__, "std::str"); - assert.equal(multiTuple.__element__.__items__[1].__name__, "std::str"); - const multiTupleResult = await client.query(e.select(multiTuple).toEdgeQL()); - assert.deepEqual(multiTupleResult, [ - ["asdf", "qwer"], - ["asdf", "erty"], - ]); - const multiTuplePath = multiTuple[0]; - tc.assert, [string, ...string[]]>>( - true - ); - tc.assert< - tc.IsExact< - (typeof multiTuplePath)["__cardinality__"], - $.Cardinality.AtLeastOne - > - >(true); - assert.deepEqual(multiTuplePath.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(await e.select(multiTuplePath).run(client), ["asdf", "asdf"]); - - const singleTuple = e.tuple([e.str("asdf")]); - type singleTuple = $infer; - tc.assert>(true); - assert.deepEqual(singleTuple.__element__.__kind__, $.TypeKind.tuple); - assert.deepEqual(singleTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); - assert.equal(singleTuple.__element__.__items__[0].__name__, "std::str"); - const singleTupleResult = await client.querySingle( - e.select(singleTuple).toEdgeQL() - ); - assert.deepEqual(singleTupleResult, ["asdf"]); - - const nestedTuple = e.tuple([ - "a", - e.tuple(["b", e.set(e.str("c"), e.str("d"))]), - ]); - type nestedTuple = $infer; - tc.assert< - tc.IsExact< - nestedTuple, - [[string, [string, string]], ...[string, [string, string]][]] - > - >(true); - const nestedTupleResult = await e.select(nestedTuple).run(client); - assert.deepEqual(nestedTupleResult, [ - ["a", ["b", "c"]], - ["a", ["b", "d"]], - ]); - const nestedTuplePathResult = await e - .select({ - tup0: nestedTuple[0], - tup1: nestedTuple[1], - tup10: nestedTuple[1][0], - tup11: nestedTuple[1][1], - }) - .run(client); - tc.assert< - tc.IsExact< - typeof nestedTuplePathResult, - { - tup0: [string, ...string[]]; - tup1: [[string, string], ...[string, string][]]; - tup10: [string, ...string[]]; - tup11: [string, ...string[]]; - } - > - >(true); - assert.deepEqual(JSON.parse(JSON.stringify(nestedTuplePathResult)), { - tup0: ["a", "a"], - tup1: [ - ["b", "c"], - ["b", "d"], - ], - tup10: ["b", "b"], - tup11: ["c", "d"], + beforeAll(async () => { + const setup = await setupTests(); + ({ client, data } = setup); }); - const heroNamesTuple = e.tuple([e.Hero.name]); - type heroNamesTuple = $infer; - tc.assert>(true); - assert.deepEqual(heroNamesTuple.__element__.__kind__, $.TypeKind.tuple); - assert.deepEqual(heroNamesTuple.__element__.__items__[0].__kind__, $.TypeKind.scalar); - assert.equal(heroNamesTuple.__element__.__items__[0].__name__, "std::str"); - const heroNamesTupleResult = await e.select(heroNamesTuple).run(client); - assert.deepEqual( - heroNamesTupleResult.sort((a, b) => a[0].localeCompare(b[0])), - [[data.cap.name], [data.iron_man.name], [data.spidey.name]].sort((a, b) => - a[0].localeCompare(b[0]) - ) - ); -}); - -test("namedTuple literal", async () => { - const tupleType = e.tuple({ - string: e.str, - number: e.int64, + afterAll(async () => { + await teardownTests(client); }); - assert.deepEqual(tupleType.__kind__, $.TypeKind.namedtuple); - assert.deepEqual(tupleType.__shape__.string.__kind__, $.TypeKind.scalar); - assert.equal(tupleType.__shape__.string.__name__, "std::str"); - assert.deepEqual(tupleType.__shape__.number.__kind__, $.TypeKind.scalar); - assert.equal(tupleType.__shape__.number.__name__, "std::int64"); - - const named = e.tuple({ - string: "asdf", - number: 1234, + + test("array literal", async () => { + const strArrayType = e.array(e.str); + assert.deepEqual(strArrayType.__kind__, $.TypeKind.array); + assert.deepEqual(strArrayType.__element__.__kind__, $.TypeKind.scalar); + assert.equal(strArrayType.__element__.__name__, "std::str"); + + const arg = e.array(["asdf", e.str("qwer")]); + + type arg = $.setToTsType; + tc.assert>(true); + assert.deepEqual(arg.__kind__, $.ExpressionKind.Array); + assert.deepEqual(arg.__element__.__kind__, $.TypeKind.array); + assert.deepEqual(arg.__cardinality__, $.Cardinality.One); + assert.deepEqual(arg.__element__.__element__.__kind__, $.TypeKind.scalar); + assert.equal(arg.__element__.__element__.__name__, "std::str"); + const result = await client.querySingle(e.select(arg).toEdgeQL()); + assert.deepEqual(result, ["asdf", "qwer"]); + + const arg1 = arg[1]; + tc.assert>( + true + ); + assert.deepEqual(arg1.__kind__, $.ExpressionKind.Operator); + tc.assert>( + true + ); + assert.deepEqual(arg1.__cardinality__, $.Cardinality.One); + tc.assert>( + true + ); + assert.equal(arg1.__element__.__name__, "std::str"); + assert.equal(await e.select(arg1).run(client), "qwer"); + + const multiArray = e.array(["asdf", e.set(e.str("qwer"), e.str("erty"))]); + + type multiArray = $.setToTsType; + tc.assert>(true); + assert.deepEqual(multiArray.__kind__, $.ExpressionKind.Array); + assert.deepEqual(multiArray.__element__.__kind__, $.TypeKind.array); + + assert.deepEqual(multiArray.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual( + multiArray.__element__.__element__.__kind__, + $.TypeKind.scalar + ); + assert.equal(multiArray.__element__.__element__.__name__, "std::str"); + const multiArrayResult = await client.query( + e.select(multiArray).toEdgeQL() + ); + assert.deepEqual(multiArrayResult, [ + ["asdf", "qwer"], + ["asdf", "erty"], + ]); + + const multi0 = multiArray[0]; + tc.assert< + tc.IsExact<(typeof multi0)["__cardinality__"], $.Cardinality.AtLeastOne> + >(true); + assert.deepEqual(multi0.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await e.select(multi0).run(client), ["asdf", "asdf"]); + + // array slicing + const arr = e.str_split(e.str("zxcvbnm"), e.str("")); + const sliceResult = await e + .select({ + reverseIndex: arr["-2"], + slice24: arr["2:4"], + slice2: arr["2:"], + slice4: arr[":4"], + reverseSlice2: arr["-2:"], + reverseSlice4: arr[":-4"], + reverseSlice24: arr["-4:-2"], + }) + .run(client); + tc.assert< + tc.IsExact< + typeof sliceResult, + { + reverseIndex: string; + slice24: string[]; + slice2: string[]; + slice4: string[]; + reverseSlice2: string[]; + reverseSlice4: string[]; + reverseSlice24: string[]; + } + > + >(true); + assert.deepEqual( + JSON.stringify(sliceResult), + JSON.stringify({ + reverseIndex: "n", + slice24: ["c", "v"], + slice2: ["c", "v", "b", "n", "m"], + slice4: ["z", "x", "c", "v"], + reverseSlice2: ["n", "m"], + reverseSlice4: ["z", "x", "c"], + reverseSlice24: ["v", "b"], + }) + ); + + // @ts-expect-error + arr["str"]; + // @ts-expect-error + arr[":"]; }); - type named = $.setToTsType; - tc.assert>(true); - assert.deepEqual(named.__kind__, $.ExpressionKind.NamedTuple); - assert.deepEqual(named.__element__.__kind__, $.TypeKind.namedtuple); - assert.deepEqual(named.__cardinality__, $.Cardinality.One); - assert.deepEqual(named.__shape__.string.__kind__, $.ExpressionKind.Literal); - assert.equal(named.__shape__.string.__value__, "asdf"); - assert.deepEqual(named.__shape__.number.__kind__, $.ExpressionKind.Literal); - assert.equal(named.__shape__.number.__value__, 1234); - assert.deepEqual(named.__element__.__shape__.string.__kind__, $.TypeKind.scalar); - assert.equal(named.__element__.__shape__.string.__name__, "std::str"); - assert.deepEqual(named.__element__.__shape__.number.__kind__, $.TypeKind.scalar); - assert.equal(named.__element__.__shape__.number.__name__, "std::number"); - const namedResult = await client.querySingle(e.select(named).toEdgeQL()); - assert.deepEqual( - JSON.stringify(namedResult), - JSON.stringify({ string: "asdf", number: 1234 }) - ); - const namedStr = named.string; - const namedNum = named.number; - tc.assert, string>>(true); - tc.assert, number>>(true); - assert.equal(await e.select(namedStr).run(client), "asdf"); - assert.equal(await e.select(namedNum).run(client), 1234); - - const nested = e.tuple({ - a: "asdf", - named: e.tuple({ b: 123 }), - tuple: e.tuple([true, e.set(e.str("x"), e.str("y"))]), + test("tuple literal", async () => { + const tupleType = e.tuple([e.str, e.int64]); + assert.deepEqual(tupleType.__kind__, $.TypeKind.tuple); + assert.deepEqual(tupleType.__items__[0].__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__items__[0].__name__, "std::str"); + assert.deepEqual(tupleType.__items__[1].__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__items__[1].__name__, "std::int64"); + + const myTuple = e.tuple(["asdf", 45]); + type myTuple = $.setToTsType; + tc.assert>(true); + assert.deepEqual(myTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual( + myTuple.__element__.__items__[0].__kind__, + $.TypeKind.scalar + ); + assert.equal(myTuple.__element__.__items__[0].__name__, "std::str"); + assert.deepEqual( + myTuple.__element__.__items__[1].__kind__, + $.TypeKind.scalar + ); + assert.equal(myTuple.__element__.__items__[1].__name__, "std::number"); + const myTupleResult = await client.querySingle( + e.select(myTuple).toEdgeQL() + ); + assert.deepEqual(myTupleResult, ["asdf", 45]); + const myTuplePath0 = myTuple[0]; + const myTuplePath1 = myTuple[1]; + tc.assert, string>>(true); + tc.assert, number>>(true); + assert.equal(await e.select(myTuplePath0).run(client), "asdf"); + assert.equal(await e.select(myTuplePath1).run(client), 45); + + const multiTuple = e.tuple(["asdf", e.set(e.str("qwer"), e.str("erty"))]); + tc.assert< + tc.IsExact< + $infer, + [[string, string], ...[string, string][]] + > + >(true); + assert.deepEqual(multiTuple.__kind__, $.ExpressionKind.Tuple); + assert.deepEqual(multiTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual(multiTuple.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual( + multiTuple.__element__.__items__[0].__kind__, + $.TypeKind.scalar + ); + assert.equal(multiTuple.__element__.__items__[0].__name__, "std::str"); + assert.equal(multiTuple.__element__.__items__[1].__name__, "std::str"); + const multiTupleResult = await client.query( + e.select(multiTuple).toEdgeQL() + ); + assert.deepEqual(multiTupleResult, [ + ["asdf", "qwer"], + ["asdf", "erty"], + ]); + const multiTuplePath = multiTuple[0]; + tc.assert, [string, ...string[]]>>( + true + ); + tc.assert< + tc.IsExact< + (typeof multiTuplePath)["__cardinality__"], + $.Cardinality.AtLeastOne + > + >(true); + assert.deepEqual(multiTuplePath.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(await e.select(multiTuplePath).run(client), [ + "asdf", + "asdf", + ]); + + const singleTuple = e.tuple([e.str("asdf")]); + type singleTuple = $infer; + tc.assert>(true); + assert.deepEqual(singleTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual( + singleTuple.__element__.__items__[0].__kind__, + $.TypeKind.scalar + ); + assert.equal(singleTuple.__element__.__items__[0].__name__, "std::str"); + const singleTupleResult = await client.querySingle( + e.select(singleTuple).toEdgeQL() + ); + assert.deepEqual(singleTupleResult, ["asdf"]); + + const nestedTuple = e.tuple([ + "a", + e.tuple(["b", e.set(e.str("c"), e.str("d"))]), + ]); + type nestedTuple = $infer; + tc.assert< + tc.IsExact< + nestedTuple, + [[string, [string, string]], ...[string, [string, string]][]] + > + >(true); + const nestedTupleResult = await e.select(nestedTuple).run(client); + assert.deepEqual(nestedTupleResult, [ + ["a", ["b", "c"]], + ["a", ["b", "d"]], + ]); + const nestedTuplePathResult = await e + .select({ + tup0: nestedTuple[0], + tup1: nestedTuple[1], + tup10: nestedTuple[1][0], + tup11: nestedTuple[1][1], + }) + .run(client); + tc.assert< + tc.IsExact< + typeof nestedTuplePathResult, + { + tup0: [string, ...string[]]; + tup1: [[string, string], ...[string, string][]]; + tup10: [string, ...string[]]; + tup11: [string, ...string[]]; + } + > + >(true); + assert.deepEqual(JSON.parse(JSON.stringify(nestedTuplePathResult)), { + tup0: ["a", "a"], + tup1: [ + ["b", "c"], + ["b", "d"], + ], + tup10: ["b", "b"], + tup11: ["c", "d"], + }); + + const heroNamesTuple = e.tuple([e.Hero.name]); + type heroNamesTuple = $infer; + tc.assert>(true); + assert.deepEqual(heroNamesTuple.__element__.__kind__, $.TypeKind.tuple); + assert.deepEqual( + heroNamesTuple.__element__.__items__[0].__kind__, + $.TypeKind.scalar + ); + assert.equal(heroNamesTuple.__element__.__items__[0].__name__, "std::str"); + const heroNamesTupleResult = await e.select(heroNamesTuple).run(client); + assert.deepEqual( + heroNamesTupleResult.sort((a, b) => a[0].localeCompare(b[0])), + [[data.cap.name], [data.iron_man.name], [data.spidey.name]].sort((a, b) => + a[0].localeCompare(b[0]) + ) + ); }); - const nestedResult = await e - .select({ - nested: nested, - nestedA: nested.a, - nestedNamed: nested.named, - nestedTuple: nested.tuple, - nestedTuple0: nested.tuple[0], - nestedTuple1: nested.tuple[1], - }) - .run(client); - tc.assert< - tc.IsExact< - typeof nestedResult, - { - nested: { a: string; named: { b: number }; tuple: [boolean, string] }[]; - nestedA: string[]; - nestedNamed: { b: number }[]; - nestedTuple: [boolean, string][]; - nestedTuple0: boolean[]; - nestedTuple1: string[]; - } - > - >(true); - assert.deepEqual(JSON.stringify(nestedResult), JSON.stringify({ - nested: [ - { a: "asdf", named: { b: 123 }, tuple: [true, "x"] }, - { a: "asdf", named: { b: 123 }, tuple: [true, "y"] }, - ], - nestedA: ["asdf", "asdf"], - nestedNamed: [{ b: 123 }, { b: 123 }], - nestedTuple: [ - [true, "x"], - [true, "y"], - ], - nestedTuple0: [true, true], - nestedTuple1: ["x", "y"], - })); - - const emptyNamedTuple = e.tuple({ string: e.cast(e.str, e.set()) }); - type emptyNamedTuple = $.setToTsType; - tc.assert>(true); - assert.deepEqual(emptyNamedTuple.__cardinality__, $.Cardinality.Empty); - - const multiNamedTuple = e.tuple({ - hero: e.Hero, + + test("namedTuple literal", async () => { + const tupleType = e.tuple({ + string: e.str, + number: e.int64, + }); + assert.deepEqual(tupleType.__kind__, $.TypeKind.namedtuple); + assert.deepEqual(tupleType.__shape__.string.__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__shape__.string.__name__, "std::str"); + assert.deepEqual(tupleType.__shape__.number.__kind__, $.TypeKind.scalar); + assert.equal(tupleType.__shape__.number.__name__, "std::int64"); + + const named = e.tuple({ + string: "asdf", + number: 1234, + }); + + type named = $.setToTsType; + tc.assert>(true); + assert.deepEqual(named.__kind__, $.ExpressionKind.NamedTuple); + assert.deepEqual(named.__element__.__kind__, $.TypeKind.namedtuple); + assert.deepEqual(named.__cardinality__, $.Cardinality.One); + assert.deepEqual(named.__shape__.string.__kind__, $.ExpressionKind.Literal); + assert.equal(named.__shape__.string.__value__, "asdf"); + assert.deepEqual(named.__shape__.number.__kind__, $.ExpressionKind.Literal); + assert.equal(named.__shape__.number.__value__, 1234); + assert.deepEqual( + named.__element__.__shape__.string.__kind__, + $.TypeKind.scalar + ); + assert.equal(named.__element__.__shape__.string.__name__, "std::str"); + assert.deepEqual( + named.__element__.__shape__.number.__kind__, + $.TypeKind.scalar + ); + assert.equal(named.__element__.__shape__.number.__name__, "std::number"); + const namedResult = await client.querySingle(e.select(named).toEdgeQL()); + assert.deepEqual( + JSON.stringify(namedResult), + JSON.stringify({ string: "asdf", number: 1234 }) + ); + const namedStr = named.string; + const namedNum = named.number; + tc.assert, string>>(true); + tc.assert, number>>(true); + assert.equal(await e.select(namedStr).run(client), "asdf"); + assert.equal(await e.select(namedNum).run(client), 1234); + + const nested = e.tuple({ + a: "asdf", + named: e.tuple({ b: 123 }), + tuple: e.tuple([true, e.set(e.str("x"), e.str("y"))]), + }); + const nestedResult = await e + .select({ + nested: nested, + nestedA: nested.a, + nestedNamed: nested.named, + nestedTuple: nested.tuple, + nestedTuple0: nested.tuple[0], + nestedTuple1: nested.tuple[1], + }) + .run(client); + tc.assert< + tc.IsExact< + typeof nestedResult, + { + nested: { + a: string; + named: { b: number }; + tuple: [boolean, string]; + }[]; + nestedA: string[]; + nestedNamed: { b: number }[]; + nestedTuple: [boolean, string][]; + nestedTuple0: boolean[]; + nestedTuple1: string[]; + } + > + >(true); + assert.deepEqual( + JSON.stringify(nestedResult), + JSON.stringify({ + nested: [ + { a: "asdf", named: { b: 123 }, tuple: [true, "x"] }, + { a: "asdf", named: { b: 123 }, tuple: [true, "y"] }, + ], + nestedA: ["asdf", "asdf"], + nestedNamed: [{ b: 123 }, { b: 123 }], + nestedTuple: [ + [true, "x"], + [true, "y"], + ], + nestedTuple0: [true, true], + nestedTuple1: ["x", "y"], + }) + ); + + const emptyNamedTuple = e.tuple({ string: e.cast(e.str, e.set()) }); + type emptyNamedTuple = $.setToTsType; + tc.assert>(true); + assert.deepEqual(emptyNamedTuple.__cardinality__, $.Cardinality.Empty); + + const multiNamedTuple = e.tuple({ + hero: e.Hero, + }); + type multiNamedTuple = $.setToTsType; + tc.assert< + tc.IsExact< + multiNamedTuple, + { + hero: { + id: string; + }; + }[] + > + >(true); + assert.deepEqual(multiNamedTuple.__cardinality__, $.Cardinality.Many); }); - type multiNamedTuple = $.setToTsType; - tc.assert< - tc.IsExact< - multiNamedTuple, - { - hero: { - id: string; - }; - }[] - > - >(true); - assert.deepEqual(multiNamedTuple.__cardinality__, $.Cardinality.Many); -}); -test("non literal tuples", async () => { - const ver = e.sys.get_version(); - assert.equal(ver.major.__element__.__name__, "std::int64"); - assert.deepEqual(ver.major.__cardinality__, $.Cardinality.One); - assert.equal(ver.stage.__element__.__name__, "sys::VersionStage"); - assert.deepEqual(ver.stage.__cardinality__, $.Cardinality.One); - assert.equal(ver.local.__element__.__name__, "array"); - assert.deepEqual(ver.local.__cardinality__, $.Cardinality.One); - - const result = await e - .select({ - ver, - verMajor: ver.major, - verStage: ver.stage, - verLocal: ver.local, - verLocal0: ver.local[0], - }) - .run(client); - - tc.assert< - tc.IsExact< - typeof result, + test("non literal tuples", async () => { + const ver = e.sys.get_version(); + assert.equal(ver.major.__element__.__name__, "std::int64"); + assert.deepEqual(ver.major.__cardinality__, $.Cardinality.One); + assert.equal(ver.stage.__element__.__name__, "sys::VersionStage"); + assert.deepEqual(ver.stage.__cardinality__, $.Cardinality.One); + assert.equal(ver.local.__element__.__name__, "array"); + assert.deepEqual(ver.local.__cardinality__, $.Cardinality.One); + + const result = await e + .select({ + ver, + verMajor: ver.major, + verStage: ver.stage, + verLocal: ver.local, + verLocal0: ver.local[0], + }) + .run(client); + + tc.assert< + tc.IsExact< + typeof result, + { + ver: { + major: number; + minor: number; + stage: `${sys.VersionStage}`; + stage_no: number; + local: string[]; + }; + verMajor: number; + verStage: `${sys.VersionStage}`; + verLocal: string[]; + verLocal0: string; + } + > + >(true); + + assert.deepEqual( + { + major: result.verMajor, + stage: result.verStage, + local: result.verLocal, + local0: result.verLocal0, + }, { - ver: { - major: number; - minor: number; - stage: `${sys.VersionStage}`; - stage_no: number; - local: string[]; - }; - verMajor: number; - verStage: `${sys.VersionStage}`; - verLocal: string[]; - verLocal0: string; + major: result.ver.major, + stage: result.ver.stage, + local: result.ver.local, + local0: result.ver.local[0], } - > - >(true); - - assert.deepEqual({ - major: result.verMajor, - stage: result.verStage, - local: result.verLocal, - local0: result.verLocal0, - }, { - major: result.ver.major, - stage: result.ver.stage, - local: result.ver.local, - local0: result.ver.local[0], + ); }); -}); -test("objectTypeToTupleType helper", () => { - const movieTuple = objectTypeToTupleType(e.Movie); - - assert.equal(movieTuple["__kind__"], "namedtuple"); - assert.equal(movieTuple["__name__"].slice(0, 6), "tuple<"); - assert.deepEqual(movieTuple["__name__"].slice(6, -1).split(", ").sort(), [ - "genre: default::Genre", - "rating: std::float64", - "release_year: default::year", - "title: std::str", - ]); - - tc.assert< - tc.IsExact< - (typeof movieTuple)["__shape__"], - { genre: $Genre; rating: $float64; title: $str; release_year: $year } - > - >(true); - - const movieTupleWithFields = objectTypeToTupleType(e.Movie, [ - "id", - "title", - "release_year", - ]); - - assert.equal(movieTupleWithFields["__kind__"], "namedtuple"); - assert.equal(movieTupleWithFields["__name__"].slice(0, 6), "tuple<"); - assert.deepEqual(movieTupleWithFields["__name__"].slice(6, -1).split(", ").sort(), [ - "id: std::uuid", - "release_year: default::year", - "title: std::str", - ]); - - tc.assert< - tc.IsExact< - (typeof movieTupleWithFields)["__shape__"], - { id: $uuid; title: $str; release_year: $year } - > - >(true); + test("objectTypeToTupleType helper", () => { + const movieTuple = objectTypeToTupleType(e.Movie); + + assert.equal(movieTuple["__kind__"], "namedtuple"); + assert.equal(movieTuple["__name__"].slice(0, 6), "tuple<"); + assert.deepEqual(movieTuple["__name__"].slice(6, -1).split(", ").sort(), [ + "genre: default::Genre", + "rating: std::float64", + "release_year: default::year", + "title: std::str", + ]); + + tc.assert< + tc.IsExact< + (typeof movieTuple)["__shape__"], + { genre: $Genre; rating: $float64; title: $str; release_year: $year } + > + >(true); + + const movieTupleWithFields = objectTypeToTupleType(e.Movie, [ + "id", + "title", + "release_year", + ]); + + assert.equal(movieTupleWithFields["__kind__"], "namedtuple"); + assert.equal(movieTupleWithFields["__name__"].slice(0, 6), "tuple<"); + assert.deepEqual( + movieTupleWithFields["__name__"].slice(6, -1).split(", ").sort(), + ["id: std::uuid", "release_year: default::year", "title: std::str"] + ); + + tc.assert< + tc.IsExact< + (typeof movieTupleWithFields)["__shape__"], + { id: $uuid; title: $str; release_year: $year } + > + >(true); + }); }); diff --git a/packages/generate/test/delete.test.ts b/packages/generate/test/delete.test.ts index fcf2e7e90..054696c3e 100644 --- a/packages/generate/test/delete.test.ts +++ b/packages/generate/test/delete.test.ts @@ -2,59 +2,63 @@ import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; -import type { Cardinality } from "../dbschema/edgeql-js"; import { setupTests, teardownTests, tc } from "./setupTeardown"; -let client: edgedb.Client; +describe("delete", () => { + let client: edgedb.Client; -beforeAll(async () => { - const setup = await setupTests(); - ({ client } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); - -test("basic delete", async () => { - const insertBlackWidow = e.insert(e.Hero, { - name: e.str("Black Widow"), - secret_identity: e.str("Natasha Romanoff"), + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); }); - const insertedResult = await insertBlackWidow.run(client); + afterAll(async () => { + await teardownTests(client); + }); - const deleteBlackWidow = e.delete(e.Hero, (hero) => ({ - filter_single: e.op(hero.name, "=", "Black Widow"), - })); - const deletedResult = await deleteBlackWidow.run(client); + test("basic delete", async () => { + const insertBlackWidow = e.insert(e.Hero, { + name: e.str("Black Widow"), + secret_identity: e.str("Natasha Romanoff"), + }); - assert.notDeepEqual(deletedResult, null); - assert.deepEqual(deletedResult!.id, insertedResult.id); + const insertedResult = await insertBlackWidow.run(client); - const deleteWrappingSelect = e.delete( - e.select(e.Hero, (hero) => ({ - name: true, + const deleteBlackWidow = e.delete(e.Hero, (hero) => ({ filter_single: e.op(hero.name, "=", "Black Widow"), - })) - ); - const wrappingDeleteResult = await deleteWrappingSelect.run(client); - - tc.assert>( - true - ); - assert.equal(wrappingDeleteResult, null); - - const deleteAll = e.delete(e.Hero); - tc.assert< - tc.IsExact<(typeof deleteAll)["__cardinality__"], edgedb.$.Cardinality.Many> - >(true); -}); + })); + const deletedResult = await deleteBlackWidow.run(client); -test("delete with filter_single", async () => { - await e - .delete(e.Movie, () => ({ - filter_single: { id: "00000000-0000-0000-0000-000000000000" }, - })) - .run(client); + assert.ok(deletedResult); + assert.deepEqual(deletedResult.id, insertedResult.id); + + const deleteWrappingSelect = e.delete( + e.select(e.Hero, (hero) => ({ + name: true, + filter_single: e.op(hero.name, "=", "Black Widow"), + })) + ); + const wrappingDeleteResult = await deleteWrappingSelect.run(client); + + tc.assert>( + true + ); + assert.equal(wrappingDeleteResult, null); + + const deleteAll = e.delete(e.Hero); + tc.assert< + tc.IsExact< + (typeof deleteAll)["__cardinality__"], + edgedb.$.Cardinality.Many + > + >(true); + }); + + test("delete with filter_single", async () => { + await e + .delete(e.Movie, () => ({ + filter_single: { id: "00000000-0000-0000-0000-000000000000" }, + })) + .run(client); + }); }); diff --git a/packages/generate/test/detached.test.ts b/packages/generate/test/detached.test.ts index 2a6a9b631..600099dea 100644 --- a/packages/generate/test/detached.test.ts +++ b/packages/generate/test/detached.test.ts @@ -1,45 +1,47 @@ import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; -import { setupTests, tc, teardownTests, TestData } from "./setupTeardown"; +import { setupTests, tc, teardownTests, type TestData } from "./setupTeardown"; -let client: edgedb.Client; -let data: TestData; +describe("detached", () => { + let client: edgedb.Client; + let data: TestData; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client, data } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("detached", async () => { - const heroes = await e.select(e.Hero).run(client); + test("detached", async () => { + const heroes = await e.select(e.Hero).run(client); - const result = await e - .select(e.Hero, (hero) => ({ - id: true, - name: true, - friends: e.select(e.detached(e.Hero)), - filter_single: e.op(hero.name, "=", "Iron Man"), - })) - .run(client); - type result = typeof result; - tc.assert< - tc.IsExact< - result, - { - id: string; - name: string; - friends: { id: string }[]; - } | null - > - >(true); - expect(result).toMatchObject({ - id: data.iron_man.id, - name: data.iron_man.name, + const result = await e + .select(e.Hero, (hero) => ({ + id: true, + name: true, + friends: e.select(e.detached(e.Hero)), + filter_single: e.op(hero.name, "=", "Iron Man"), + })) + .run(client); + type result = typeof result; + tc.assert< + tc.IsExact< + result, + { + id: string; + name: string; + friends: { id: string }[]; + } | null + > + >(true); + expect(result).toMatchObject({ + id: data.iron_man.id, + name: data.iron_man.name, + }); + assert.deepEqual(result?.friends, heroes); }); - assert.deepEqual(result?.friends, heroes); }); diff --git a/packages/generate/test/for.test.ts b/packages/generate/test/for.test.ts index f3715d227..2c274d662 100644 --- a/packages/generate/test/for.test.ts +++ b/packages/generate/test/for.test.ts @@ -1,29 +1,30 @@ import assert from "node:assert/strict"; import e from "../dbschema/edgeql-js"; -test("simple for loop", () => { - assert.equal( - e.for(e.set(1, 2, 3), (x) => e.op(e.op(x, "*", 2), "+", x)).toEdgeQL(), - `\ +describe("for", () => { + test("simple for loop", () => { + assert.equal( + e.for(e.set(1, 2, 3), (x) => e.op(e.op(x, "*", 2), "+", x)).toEdgeQL(), + `\ FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( ((__forVar__0 * 2) + __forVar__0) )` - ); -}); + ); + }); -test("with vars in for loop", () => { - const q1 = e.for(e.set(1, 2, 3), (i) => { - const str = e.to_str(i); - return e.select({ - a: e.select(str), - b: e.select(e.tuple([str, str])), + test("with vars in for loop", () => { + const q1 = e.for(e.set(1, 2, 3), (i) => { + const str = e.to_str(i); + return e.select({ + a: e.select(str), + b: e.select(e.tuple([str, str])), + }); }); - }); - assert.equal( - q1.toEdgeQL(), - `FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal( + q1.toEdgeQL(), + `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_0 := std::to_str(__forVar__0) @@ -37,28 +38,28 @@ UNION ( ) }) )` - ); + ); - const q2 = e.for(e.set(1, 2, 3), (i) => { - const str = e.to_str(i); - return e - .insert(e.Hero, { - name: str, - secret_identity: str, - }) - .unlessConflict((person) => ({ - on: person.name, - else: e.update(person, () => ({ - set: { - name: str, - }, - })), - })); - }); + const q2 = e.for(e.set(1, 2, 3), (i) => { + const str = e.to_str(i); + return e + .insert(e.Hero, { + name: str, + secret_identity: str, + }) + .unlessConflict((person) => ({ + on: person.name, + else: e.update(person, () => ({ + set: { + name: str, + }, + })), + })); + }); - assert.equal( - q2.toEdgeQL(), - `FOR __forVar__0 IN {{ 1, 2, 3 }} + assert.equal( + q2.toEdgeQL(), + `FOR __forVar__0 IN {{ 1, 2, 3 }} UNION ( (WITH __withVar_1 := std::to_str(__forVar__0) @@ -73,5 +74,6 @@ UNION ( name := __withVar_1 }))) )` - ); + ); + }); }); diff --git a/packages/generate/test/functions.test.ts b/packages/generate/test/functions.test.ts index 92de23fbb..3d201d501 100644 --- a/packages/generate/test/functions.test.ts +++ b/packages/generate/test/functions.test.ts @@ -19,644 +19,664 @@ function checkFunctionExpr( superjson.stringify(expr.__args__), superjson.stringify(args.filter((arg) => arg !== undefined)) ); - assert.deepEqual(superjson.stringify(expr.__namedargs__), superjson.stringify(namedargs)); + assert.deepEqual( + superjson.stringify(expr.__namedargs__), + superjson.stringify(namedargs) + ); assert.deepEqual(expr.__element__.__name__, returnType.__name__); assert.deepEqual(expr.__cardinality__, cardinality); } -test("no args", () => { - checkFunctionExpr( - e.sys.get_version_as_str(), - "sys::get_version_as_str", - [], - {}, - e.str, - $.Cardinality.One - ); - - checkFunctionExpr( - e.sys.get_version(), - "sys::get_version", - [], - {}, - e.tuple({ - major: e.int64, - minor: e.int64, - stage: e.sys.VersionStage, - stage_no: e.int64, - local: e.array(e.str), - }), - $.Cardinality.One - ); +describe("functions", () => { + test("no args", () => { + checkFunctionExpr( + e.sys.get_version_as_str(), + "sys::get_version_as_str", + [], + {}, + e.str, + $.Cardinality.One + ); - try { - // @ts-expect-error - e.sys.get_version_as_str(e.str("error")); - } catch {} -}); + checkFunctionExpr( + e.sys.get_version(), + "sys::get_version", + [], + {}, + e.tuple({ + major: e.int64, + minor: e.int64, + stage: e.sys.VersionStage, + stage_no: e.int64, + local: e.array(e.str), + }), + $.Cardinality.One + ); -test("positional args", () => { - checkFunctionExpr( - e.len(e.str("test")), - "std::len", - [e.str("test")], - {}, - number, - $.Cardinality.One - ); + try { + // @ts-expect-error + e.sys.get_version_as_str(e.str("error")); + } catch {} + }); + + test("positional args", () => { + checkFunctionExpr( + e.len(e.str("test")), + "std::len", + [e.str("test")], + {}, + number, + $.Cardinality.One + ); - checkFunctionExpr( - e.len(e.bytes(Buffer.from(""))), - "std::len", - [e.bytes(Buffer.from(""))], - {}, - number, - $.Cardinality.One - ); + checkFunctionExpr( + e.len(e.bytes(Buffer.from(""))), + "std::len", + [e.bytes(Buffer.from(""))], + {}, + number, + $.Cardinality.One + ); - checkFunctionExpr( - e.len(e.literal(e.array(e.int32), [1, 2, 3])), - "std::len", - [e.literal(e.array(e.int32), [1, 2, 3])], - {}, - number, - $.Cardinality.One - ); + checkFunctionExpr( + e.len(e.literal(e.array(e.int32), [1, 2, 3])), + "std::len", + [e.literal(e.array(e.int32), [1, 2, 3])], + {}, + number, + $.Cardinality.One + ); - const setOfStr = e.set(e.str("test"), e.str("test2")); + const setOfStr = e.set(e.str("test"), e.str("test2")); - checkFunctionExpr( - e.len(setOfStr), - "std::len", - [setOfStr], - {}, - number, - $.Cardinality.AtLeastOne - ); - - const datetime_getArgs = [e.datetime(new Date()), e.str("day")] as const; - checkFunctionExpr( - e.datetime_get(...datetime_getArgs), - "std::datetime_get", - datetime_getArgs as $.typeutil.writeable, - {}, - number, - $.Cardinality.One - ); + checkFunctionExpr( + e.len(setOfStr), + "std::len", + [setOfStr], + {}, + number, + $.Cardinality.AtLeastOne + ); - const datetime_getArgs2 = [ - e.datetime(new Date()), - e.set(e.str("day"), e.str("month"), e.str("year")), - ] as const; - checkFunctionExpr( - e.datetime_get(...datetime_getArgs2), - "std::datetime_get", - datetime_getArgs2 as $.typeutil.writeable, - {}, - number, - $.Cardinality.AtLeastOne - ); + const datetime_getArgs = [e.datetime(new Date()), e.str("day")] as const; + checkFunctionExpr( + e.datetime_get(...datetime_getArgs), + "std::datetime_get", + datetime_getArgs as $.typeutil.writeable, + {}, + number, + $.Cardinality.One + ); - try { - // @ts-expect-error - e.len(e.int32("test")); + const datetime_getArgs2 = [ + e.datetime(new Date()), + e.set(e.str("day"), e.str("month"), e.str("year")), + ] as const; + checkFunctionExpr( + e.datetime_get(...datetime_getArgs2), + "std::datetime_get", + datetime_getArgs2 as $.typeutil.writeable, + {}, + number, + $.Cardinality.AtLeastOne + ); - // @ts-expect-error - e.len(e.Hero); - } catch {} -}); + try { + // @ts-expect-error + e.len(e.int32("test")); -test("named args", () => { - checkFunctionExpr( - e.std.re_replace(e.str("pattern"), e.str("sub"), e.str("str")), - "std::re_replace", - [e.str("pattern"), e.str("sub"), e.str("str")], - {}, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.std.re_replace( + // @ts-expect-error + e.len(e.Hero); + } catch {} + }); + + test("named args", () => { + checkFunctionExpr( + e.std.re_replace(e.str("pattern"), e.str("sub"), e.str("str")), + "std::re_replace", + [e.str("pattern"), e.str("sub"), e.str("str")], + {}, + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.std.re_replace( + { flags: e.str("flags") }, + e.str("pattern"), + e.str("sub"), + e.str("str") + ), + "std::re_replace", + [e.str("pattern"), e.str("sub"), e.str("str")], { flags: e.str("flags") }, - e.str("pattern"), - e.str("sub"), - e.str("str") - ), - "std::re_replace", - [e.str("pattern"), e.str("sub"), e.str("str")], - { flags: e.str("flags") }, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.std.re_replace({}, e.str("pattern"), e.str("sub"), e.str("str")), - "std::re_replace", - [e.str("pattern"), e.str("sub"), e.str("str")], - {}, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.std.re_replace( + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.std.re_replace({}, e.str("pattern"), e.str("sub"), e.str("str")), + "std::re_replace", + [e.str("pattern"), e.str("sub"), e.str("str")], + {}, + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.std.re_replace( + { flags: e.cast(e.str, e.set()) }, + e.str("pattern"), + e.str("sub"), + e.str("str") + ), + "std::re_replace", + [e.str("pattern"), e.str("sub"), e.str("str")], { flags: e.cast(e.str, e.set()) }, - e.str("pattern"), - e.str("sub"), - e.str("str") - ), - "std::re_replace", - [e.str("pattern"), e.str("sub"), e.str("str")], - { flags: e.cast(e.str, e.set()) }, - e.str, - $.Cardinality.One - ); - - checkFunctionExpr( - e.to_duration({}), - "std::to_duration", - [], - {}, - e.duration, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_duration({ hours: e.int64(5) }), - "std::to_duration", - [], - { hours: e.int64(5) }, - e.duration, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_duration({ hours: e.int64(5), seconds: e.int64(30) }), - "std::to_duration", - [], - { hours: e.int64(5), seconds: e.int64(30) }, - e.duration, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_duration({ hours: e.set(e.int64(5), e.int64(6)) }), - "std::to_duration", - [], - { hours: e.set(e.int64(5), e.int64(6)) }, - e.duration, - $.Cardinality.AtLeastOne - ); - checkFunctionExpr( - e.to_duration({ hours: e.int64(5) }), - "std::to_duration", - [], - { hours: e.int64(5) }, - e.duration, - $.Cardinality.One - ); - - checkFunctionExpr( - e["💯"]({ "🙀": e.int64(1) }), - "default::💯", - [], - { "🙀": e.int64(1) }, - number, - $.Cardinality.One - ); + e.str, + $.Cardinality.One + ); - try { - e.std.re_replace( - // @ts-expect-error - { wrongKey: e.str("") }, - e.str("pattern"), - e.str("sub"), - e.str("str") + checkFunctionExpr( + e.to_duration({}), + "std::to_duration", + [], + {}, + e.duration, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_duration({ hours: e.int64(5) }), + "std::to_duration", + [], + { hours: e.int64(5) }, + e.duration, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_duration({ hours: e.int64(5), seconds: e.int64(30) }), + "std::to_duration", + [], + { hours: e.int64(5), seconds: e.int64(30) }, + e.duration, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_duration({ hours: e.set(e.int64(5), e.int64(6)) }), + "std::to_duration", + [], + { hours: e.set(e.int64(5), e.int64(6)) }, + e.duration, + $.Cardinality.AtLeastOne + ); + checkFunctionExpr( + e.to_duration({ hours: e.int64(5) }), + "std::to_duration", + [], + { hours: e.int64(5) }, + e.duration, + $.Cardinality.One ); - e.std.re_replace( - // @ts-expect-error - { flags: e.int32(1) }, - e.str("pattern"), - e.str("sub"), - e.str("str") + checkFunctionExpr( + e["💯"]({ "🙀": e.int64(1) }), + "default::💯", + [], + { "🙀": e.int64(1) }, + number, + $.Cardinality.One ); - // @ts-expect-error - e["💯"](); - // @ts-expect-error - e["💯"]({}); - } catch {} -}); + try { + e.std.re_replace( + // @ts-expect-error + { wrongKey: e.str("") }, + e.str("pattern"), + e.str("sub"), + e.str("str") + ); + + e.std.re_replace( + // @ts-expect-error + { flags: e.int32(1) }, + e.str("pattern"), + e.str("sub"), + e.str("str") + ); -test("variadic args", () => { - checkFunctionExpr( - e.json_get(e.json("json"), e.str("path")), - "std::json_get", - [e.json("json"), e.str("path")], - {}, - e.json, - $.Cardinality.AtMostOne - ); - checkFunctionExpr( - e.json_get(e.json("json"), e.str("some"), e.str("path")), - "std::json_get", - [e.json("json"), e.str("some"), e.str("path")], - {}, - e.json, - $.Cardinality.AtMostOne - ); - checkFunctionExpr( - e.json_get( - e.json("json"), - e.str("some"), - e.set(e.str("path"), e.str("extended")) - ), - "std::json_get", - [e.json("json"), e.str("some"), e.set(e.str("path"), e.str("extended"))], - {}, - e.json, - $.Cardinality.Many - ); - checkFunctionExpr( - e.json_get( - {}, - e.json("json"), - e.str("some"), - e.set(e.str("path"), e.str("extended")) - ), - "std::json_get", - [e.json("json"), e.str("some"), e.set(e.str("path"), e.str("extended"))], - {}, - e.json, - $.Cardinality.Many - ); - checkFunctionExpr( - e.json_get( + // @ts-expect-error + e["💯"](); + // @ts-expect-error + e["💯"]({}); + } catch {} + }); + + test("variadic args", () => { + checkFunctionExpr( + e.json_get(e.json("json"), e.str("path")), + "std::json_get", + [e.json("json"), e.str("path")], + {}, + e.json, + $.Cardinality.AtMostOne + ); + checkFunctionExpr( + e.json_get(e.json("json"), e.str("some"), e.str("path")), + "std::json_get", + [e.json("json"), e.str("some"), e.str("path")], + {}, + e.json, + $.Cardinality.AtMostOne + ); + checkFunctionExpr( + e.json_get( + e.json("json"), + e.str("some"), + e.set(e.str("path"), e.str("extended")) + ), + "std::json_get", + [e.json("json"), e.str("some"), e.set(e.str("path"), e.str("extended"))], + {}, + e.json, + $.Cardinality.Many + ); + checkFunctionExpr( + e.json_get( + {}, + e.json("json"), + e.str("some"), + e.set(e.str("path"), e.str("extended")) + ), + "std::json_get", + [e.json("json"), e.str("some"), e.set(e.str("path"), e.str("extended"))], + {}, + e.json, + $.Cardinality.Many + ); + checkFunctionExpr( + e.json_get( + { default: e.json("defaultjson") }, + e.json("json"), + e.str("some"), + e.str("path") + ), + "std::json_get", + [e.json("json"), e.str("some"), e.str("path")], { default: e.json("defaultjson") }, - e.json("json"), - e.str("some"), - e.str("path") - ), - "std::json_get", - [e.json("json"), e.str("some"), e.str("path")], - { default: e.json("defaultjson") }, - e.json, - $.Cardinality.AtMostOne - ); -}); + e.json, + $.Cardinality.AtMostOne + ); + }); -test("anytype", () => { - checkFunctionExpr( - e.min(e.json("json")), - "std::min", - [e.json("json")], - {}, - e.json, - $.Cardinality.One - ); - checkFunctionExpr( - e.min(e.set(e.int64(1), e.int64(2))), - "std::min", - [e.set(e.int64(1), e.int64(2))], - {}, - number, - $.Cardinality.One - ); + test("anytype", () => { + checkFunctionExpr( + e.min(e.json("json")), + "std::min", + [e.json("json")], + {}, + e.json, + $.Cardinality.One + ); + checkFunctionExpr( + e.min(e.set(e.int64(1), e.int64(2))), + "std::min", + [e.set(e.int64(1), e.int64(2))], + {}, + number, + $.Cardinality.One + ); - checkFunctionExpr( - e.array_agg(e.str("str")), - "std::array_agg", - [e.str("str")], - {}, - e.array(e.str), - $.Cardinality.One - ); + checkFunctionExpr( + e.array_agg(e.str("str")), + "std::array_agg", + [e.str("str")], + {}, + e.array(e.str), + $.Cardinality.One + ); - checkFunctionExpr( - e.array_unpack(e.literal(e.array(e.str), ["str"])), - "std::array_unpack", - [e.literal(e.array(e.str), ["str"])], - {}, - e.str, - $.Cardinality.Many - ); + checkFunctionExpr( + e.array_unpack(e.literal(e.array(e.str), ["str"])), + "std::array_unpack", + [e.literal(e.array(e.str), ["str"])], + {}, + e.str, + $.Cardinality.Many + ); - checkFunctionExpr( - e.contains( - e.literal(e.array(e.str), ["test", "haystack"]), - e.set(e.str("needle"), e.str("haystack")) - ), - "std::contains", - [ - e.literal(e.array(e.str), ["test", "haystack"]), - e.set(e.str("needle"), e.str("haystack")), - ], - {}, - e.bool, - $.Cardinality.AtLeastOne - ); + checkFunctionExpr( + e.contains( + e.literal(e.array(e.str), ["test", "haystack"]), + e.set(e.str("needle"), e.str("haystack")) + ), + "std::contains", + [ + e.literal(e.array(e.str), ["test", "haystack"]), + e.set(e.str("needle"), e.str("haystack")), + ], + {}, + e.bool, + $.Cardinality.AtLeastOne + ); - checkFunctionExpr( - e.contains( - e.literal(e.array(e.int16), [1, 2, 3]), - e.cast(e.int64, e.bigint(BigInt(2))) - ), - "std::contains", - [ - e.literal(e.array(e.int16), [1, 2, 3]), - e.cast(e.int64, e.bigint(BigInt(2))), - ], - {}, - e.bool, - $.Cardinality.One - ); + checkFunctionExpr( + e.contains( + e.literal(e.array(e.int16), [1, 2, 3]), + e.cast(e.int64, e.bigint(BigInt(2))) + ), + "std::contains", + [ + e.literal(e.array(e.int16), [1, 2, 3]), + e.cast(e.int64, e.bigint(BigInt(2))), + ], + {}, + e.bool, + $.Cardinality.One + ); - checkFunctionExpr( - e.contains(e.literal(e.array(e.float32), [1, 2, 3]), e.int64(2)), - "std::contains", - [e.literal(e.array(e.float32), [1, 2, 3]), e.int64(2)], - {}, - e.bool, - $.Cardinality.One - ); + checkFunctionExpr( + e.contains(e.literal(e.array(e.float32), [1, 2, 3]), e.int64(2)), + "std::contains", + [e.literal(e.array(e.float32), [1, 2, 3]), e.int64(2)], + {}, + e.bool, + $.Cardinality.One + ); - checkFunctionExpr( - e.array_get( + checkFunctionExpr( + e.array_get( + { default: e.bigint(BigInt(0)) }, + e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), + e.int64(4) + ), + "std::array_get", + [ + e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), + e.int64(4), + ], { default: e.bigint(BigInt(0)) }, - e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), - e.int64(4) - ), - "std::array_get", - [ - e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), - e.int64(4), - ], - { default: e.bigint(BigInt(0)) }, - e.bigint, - $.Cardinality.AtMostOne - ); - - try { - // @ts-expect-error - e.contains(e.literal(e.array(e.str), ["test", "haystack"]), e.int64(1)); - - e.array_get( - // @ts-expect-error - { default: e.str("0") }, - e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), - e.int64(4) + e.bigint, + $.Cardinality.AtMostOne ); - // @ts-expect-error - e.min(e.set(e.int64(1), e.str("str"))); + try { + // @ts-expect-error + e.contains(e.literal(e.array(e.str), ["test", "haystack"]), e.int64(1)); - // @ts-expect-error - e.contains(e.literal(e.array(e.float32), [1, 2, 3]), e.bigint(BigInt(2))); - } catch {} -}); + e.array_get( + // @ts-expect-error + { default: e.str("0") }, + e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), + e.int64(4) + ); -test("cardinality inference", () => { - // optional param - checkFunctionExpr( - e.to_str(e.int64(123), e.str("")), - "std::to_str", - [e.int64(123), e.str("")], - {}, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_str(e.int64(123), e.cast(e.str, e.set())), - "std::to_str", - [e.int64(123), e.cast(e.str, e.set())], - {}, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_str(e.int64(123), undefined), - "std::to_str", - [e.int64(123), e.cast(e.str, e.set()) as any], - {}, - e.str, - $.Cardinality.One - ); - checkFunctionExpr( - e.to_str(e.set(e.int64(123), e.int64(456)), undefined), - "std::to_str", - [e.set(e.int64(123), e.int64(456)), e.cast(e.str, e.set()) as any], - {}, - e.str, - $.Cardinality.AtLeastOne - ); - checkFunctionExpr( - e.to_str(e.int64(123)), - "std::to_str", - [e.int64(123), undefined as any], - {}, - e.str, - $.Cardinality.One - ); + // @ts-expect-error + e.min(e.set(e.int64(1), e.str("str"))); - // setoftype param - checkFunctionExpr( - e.sum(e.int64(1)), - "std::sum", - [e.int64(1)], - {}, - number, - $.Cardinality.One - ); - checkFunctionExpr( - e.sum(e.set(e.int64(1), e.int64(2))), - "std::sum", - [e.set(e.int64(1), e.int64(2))], - {}, - number, - $.Cardinality.One - ); - checkFunctionExpr( - e.sum(e.cast(e.int64, e.set())), - "std::sum", - [e.cast(e.int64, e.set())], - {}, - number, - $.Cardinality.One - ); + // @ts-expect-error + e.contains(e.literal(e.array(e.float32), [1, 2, 3]), e.bigint(BigInt(2))); + } catch {} + }); + + test("cardinality inference", () => { + // optional param + checkFunctionExpr( + e.to_str(e.int64(123), e.str("")), + "std::to_str", + [e.int64(123), e.str("")], + {}, + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_str(e.int64(123), e.cast(e.str, e.set())), + "std::to_str", + [e.int64(123), e.cast(e.str, e.set())], + {}, + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_str(e.int64(123), undefined), + "std::to_str", + [e.int64(123), e.cast(e.str, e.set()) as any], + {}, + e.str, + $.Cardinality.One + ); + checkFunctionExpr( + e.to_str(e.set(e.int64(123), e.int64(456)), undefined), + "std::to_str", + [e.set(e.int64(123), e.int64(456)), e.cast(e.str, e.set()) as any], + {}, + e.str, + $.Cardinality.AtLeastOne + ); + checkFunctionExpr( + e.to_str(e.int64(123)), + "std::to_str", + [e.int64(123), undefined as any], + {}, + e.str, + $.Cardinality.One + ); - // optional return - checkFunctionExpr( - e.array_get( - e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), - e.int64(1) - ), - "std::array_get", - [ - e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), - e.int64(1), - ], - {}, - e.bigint, - $.Cardinality.AtMostOne - ); - checkFunctionExpr( - e.array_get(e.cast(e.array(e.bigint), e.set()), e.int64(1)), - "std::array_get", - [e.cast(e.array(e.bigint), e.set()), e.int64(1)], - {}, - e.bigint, - $.Cardinality.Empty - ); - // BROKEN - // checkFunctionExpr( - // e.array_get( - // e.set( - // e.literal(e.array(e.$bigint), [BigInt(1), BigInt(2), BigInt(3)]), - // e.literal(e.array(e.$bigint), [BigInt(4)]) - // ), - // e.int64(1) - // ), - // "std::array_get", - // [ - // e.set( - // e.literal(e.array(e.$bigint), [BigInt(1), BigInt(2), BigInt(3)]), - // e.literal(e.array(e.$bigint), [BigInt(4)]) - // ), - // e.int64(1), - // ], - // {}, - // e.$bigint, - // $.Cardinality.Many - // ); - - // setoftype return - checkFunctionExpr( - e.array_unpack(e.literal(e.array(e.str), ["str"])), - "std::array_unpack", - [e.literal(e.array(e.str), ["str"])], - {}, - e.str, - $.Cardinality.Many - ); - checkFunctionExpr( - e.array_unpack(e.cast(e.array(e.str), e.set())), - "std::array_unpack", - [e.cast(e.array(e.str), e.set())], - {}, - e.str, - $.Cardinality.Many - ); - checkFunctionExpr( - e.array_unpack(e.literal(e.array(e.str), ["str"])), - "std::array_unpack", - [e.literal(e.array(e.str), ["str"])], - {}, - e.str, - $.Cardinality.Many - ); -}); + // setoftype param + checkFunctionExpr( + e.sum(e.int64(1)), + "std::sum", + [e.int64(1)], + {}, + number, + $.Cardinality.One + ); + checkFunctionExpr( + e.sum(e.set(e.int64(1), e.int64(2))), + "std::sum", + [e.set(e.int64(1), e.int64(2))], + {}, + number, + $.Cardinality.One + ); + checkFunctionExpr( + e.sum(e.cast(e.int64, e.set())), + "std::sum", + [e.cast(e.int64, e.set())], + {}, + number, + $.Cardinality.One + ); -test("assert_*", () => { - const emptySet = e.cast(e.str, e.set()); - const oneSet = e.set("str"); - const atLeastOneSet = e.set("str", "str2"); - const atMostOneSet = { - ...oneSet, - __cardinality__: $.Cardinality.AtMostOne, - } as unknown as $.TypeSet; - const manySet = { - ...atLeastOneSet, - __cardinality__: $.Cardinality.Many, - } as unknown as $.TypeSet; - - assert.deepEqual(emptySet.__cardinality__, $.Cardinality.Empty); - assert.deepEqual(oneSet.__cardinality__, $.Cardinality.One); - assert.deepEqual(atLeastOneSet.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(atMostOneSet.__cardinality__, $.Cardinality.AtMostOne); - assert.deepEqual(manySet.__cardinality__, $.Cardinality.Many); - tc.assert< - tc.IsExact<(typeof emptySet)["__cardinality__"], $.Cardinality.Empty> - >(true); - tc.assert>( - true - ); - tc.assert< - tc.IsExact< - (typeof atLeastOneSet)["__cardinality__"], - $.Cardinality.AtLeastOne - > - >(true); - tc.assert< - tc.IsExact< - (typeof atMostOneSet)["__cardinality__"], - $.Cardinality.AtMostOne - > - >(true); - tc.assert< - tc.IsExact<(typeof manySet)["__cardinality__"], $.Cardinality.Many> - >(true); - - // assert_single - const emptySingle = e.assert_single(emptySet); - assert.deepEqual(emptySingle.__cardinality__, $.Cardinality.AtMostOne); - tc.assert< - tc.IsExact<(typeof emptySingle)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - const oneSingle = e.assert_single(oneSet); - assert.deepEqual(oneSingle.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact<(typeof oneSingle)["__cardinality__"], $.Cardinality.One> - >(true); - const atLeastOneSingle = e.assert_single(atLeastOneSet); - assert.deepEqual(atLeastOneSingle.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact<(typeof atLeastOneSingle)["__cardinality__"], $.Cardinality.One> - >(true); - const atMostOneSingle = e.assert_single(atMostOneSet); - assert.deepEqual(atMostOneSingle.__cardinality__, $.Cardinality.AtMostOne); - tc.assert< - tc.IsExact< - (typeof atMostOneSingle)["__cardinality__"], + // optional return + checkFunctionExpr( + e.array_get( + e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), + e.int64(1) + ), + "std::array_get", + [ + e.literal(e.array(e.bigint), [BigInt(1), BigInt(2), BigInt(3)]), + e.int64(1), + ], + {}, + e.bigint, $.Cardinality.AtMostOne - > - >(true); - const manySingle = e.assert_single(manySet); - assert.deepEqual(manySingle.__cardinality__, $.Cardinality.AtMostOne); - tc.assert< - tc.IsExact<(typeof manySingle)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - - // assert_exists - const emptyExists = e.assert_exists(emptySet); - assert.deepEqual(emptyExists.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact<(typeof emptyExists)["__cardinality__"], $.Cardinality.One> - >(true); - const oneExists = e.assert_exists(oneSet); - assert.deepEqual(oneExists.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact<(typeof oneExists)["__cardinality__"], $.Cardinality.One> - >(true); - const atLeastOneExists = e.assert_exists(atLeastOneSet); - assert.deepEqual(atLeastOneExists.__cardinality__, $.Cardinality.AtLeastOne); - tc.assert< - tc.IsExact< - (typeof atLeastOneExists)["__cardinality__"], + ); + checkFunctionExpr( + e.array_get(e.cast(e.array(e.bigint), e.set()), e.int64(1)), + "std::array_get", + [e.cast(e.array(e.bigint), e.set()), e.int64(1)], + {}, + e.bigint, + $.Cardinality.Empty + ); + // BROKEN + // checkFunctionExpr( + // e.array_get( + // e.set( + // e.literal(e.array(e.$bigint), [BigInt(1), BigInt(2), BigInt(3)]), + // e.literal(e.array(e.$bigint), [BigInt(4)]) + // ), + // e.int64(1) + // ), + // "std::array_get", + // [ + // e.set( + // e.literal(e.array(e.$bigint), [BigInt(1), BigInt(2), BigInt(3)]), + // e.literal(e.array(e.$bigint), [BigInt(4)]) + // ), + // e.int64(1), + // ], + // {}, + // e.$bigint, + // $.Cardinality.Many + // ); + + // setoftype return + checkFunctionExpr( + e.array_unpack(e.literal(e.array(e.str), ["str"])), + "std::array_unpack", + [e.literal(e.array(e.str), ["str"])], + {}, + e.str, + $.Cardinality.Many + ); + checkFunctionExpr( + e.array_unpack(e.cast(e.array(e.str), e.set())), + "std::array_unpack", + [e.cast(e.array(e.str), e.set())], + {}, + e.str, + $.Cardinality.Many + ); + checkFunctionExpr( + e.array_unpack(e.literal(e.array(e.str), ["str"])), + "std::array_unpack", + [e.literal(e.array(e.str), ["str"])], + {}, + e.str, + $.Cardinality.Many + ); + }); + + test("assert_*", () => { + const emptySet = e.cast(e.str, e.set()); + const oneSet = e.set("str"); + const atLeastOneSet = e.set("str", "str2"); + const atMostOneSet = { + ...oneSet, + __cardinality__: $.Cardinality.AtMostOne, + } as unknown as $.TypeSet; + const manySet = { + ...atLeastOneSet, + __cardinality__: $.Cardinality.Many, + } as unknown as $.TypeSet; + + assert.deepEqual(emptySet.__cardinality__, $.Cardinality.Empty); + assert.deepEqual(oneSet.__cardinality__, $.Cardinality.One); + assert.deepEqual(atLeastOneSet.__cardinality__, $.Cardinality.AtLeastOne); + assert.deepEqual(atMostOneSet.__cardinality__, $.Cardinality.AtMostOne); + assert.deepEqual(manySet.__cardinality__, $.Cardinality.Many); + tc.assert< + tc.IsExact<(typeof emptySet)["__cardinality__"], $.Cardinality.Empty> + >(true); + tc.assert< + tc.IsExact<(typeof oneSet)["__cardinality__"], $.Cardinality.One> + >(true); + tc.assert< + tc.IsExact< + (typeof atLeastOneSet)["__cardinality__"], + $.Cardinality.AtLeastOne + > + >(true); + tc.assert< + tc.IsExact< + (typeof atMostOneSet)["__cardinality__"], + $.Cardinality.AtMostOne + > + >(true); + tc.assert< + tc.IsExact<(typeof manySet)["__cardinality__"], $.Cardinality.Many> + >(true); + + // assert_single + const emptySingle = e.assert_single(emptySet); + assert.deepEqual(emptySingle.__cardinality__, $.Cardinality.AtMostOne); + tc.assert< + tc.IsExact< + (typeof emptySingle)["__cardinality__"], + $.Cardinality.AtMostOne + > + >(true); + const oneSingle = e.assert_single(oneSet); + assert.deepEqual(oneSingle.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact<(typeof oneSingle)["__cardinality__"], $.Cardinality.One> + >(true); + const atLeastOneSingle = e.assert_single(atLeastOneSet); + assert.deepEqual(atLeastOneSingle.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact< + (typeof atLeastOneSingle)["__cardinality__"], + $.Cardinality.One + > + >(true); + const atMostOneSingle = e.assert_single(atMostOneSet); + assert.deepEqual(atMostOneSingle.__cardinality__, $.Cardinality.AtMostOne); + tc.assert< + tc.IsExact< + (typeof atMostOneSingle)["__cardinality__"], + $.Cardinality.AtMostOne + > + >(true); + const manySingle = e.assert_single(manySet); + assert.deepEqual(manySingle.__cardinality__, $.Cardinality.AtMostOne); + tc.assert< + tc.IsExact< + (typeof manySingle)["__cardinality__"], + $.Cardinality.AtMostOne + > + >(true); + + // assert_exists + const emptyExists = e.assert_exists(emptySet); + assert.deepEqual(emptyExists.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact<(typeof emptyExists)["__cardinality__"], $.Cardinality.One> + >(true); + const oneExists = e.assert_exists(oneSet); + assert.deepEqual(oneExists.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact<(typeof oneExists)["__cardinality__"], $.Cardinality.One> + >(true); + const atLeastOneExists = e.assert_exists(atLeastOneSet); + assert.deepEqual( + atLeastOneExists.__cardinality__, $.Cardinality.AtLeastOne - > - >(true); - const atMostOneExists = e.assert_exists(atMostOneSet); - assert.deepEqual(atMostOneExists.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact<(typeof atMostOneExists)["__cardinality__"], $.Cardinality.One> - >(true); - const manyExists = e.assert_exists(manySet); - assert.deepEqual(manyExists.__cardinality__, $.Cardinality.AtLeastOne); - tc.assert< - tc.IsExact<(typeof manyExists)["__cardinality__"], $.Cardinality.AtLeastOne> - >(true); -}); - -test("persist Cardinality.One", async () => { - const query = e.str_trim(e.str("test string")); - assert.deepEqual(query.__cardinality__, $.Cardinality.One); - tc.assert>( - true - ); + ); + tc.assert< + tc.IsExact< + (typeof atLeastOneExists)["__cardinality__"], + $.Cardinality.AtLeastOne + > + >(true); + const atMostOneExists = e.assert_exists(atMostOneSet); + assert.deepEqual(atMostOneExists.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact<(typeof atMostOneExists)["__cardinality__"], $.Cardinality.One> + >(true); + const manyExists = e.assert_exists(manySet); + assert.deepEqual(manyExists.__cardinality__, $.Cardinality.AtLeastOne); + tc.assert< + tc.IsExact< + (typeof manyExists)["__cardinality__"], + $.Cardinality.AtLeastOne + > + >(true); + }); + + test("persist Cardinality.One", async () => { + const query = e.str_trim(e.str("test string")); + assert.deepEqual(query.__cardinality__, $.Cardinality.One); + tc.assert>( + true + ); + }); }); diff --git a/packages/generate/test/globals.test.ts b/packages/generate/test/globals.test.ts index 2844ba849..ce2700f29 100644 --- a/packages/generate/test/globals.test.ts +++ b/packages/generate/test/globals.test.ts @@ -1,71 +1,107 @@ import assert from "node:assert/strict"; import type * as edgedb from "edgedb"; import { $ } from "edgedb"; -import * as tc from "conditional-type-checks"; -import e, { $infer } from "../dbschema/edgeql-js"; +import e from "../dbschema/edgeql-js"; -import { - setupTests, - teardownTests, - TestData, - testIfVersionGTE, -} from "./setupTeardown"; +import { setupTests, teardownTests, testIfVersionGTE } from "./setupTeardown"; -let client: edgedb.Client; -let data: TestData; +describe("globals", () => { + let client: edgedb.Client; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -testIfVersionGTE(2)("globals", async () => { - assert.equal( - e.select(e.global.uuid_global).toEdgeQL(), - `SELECT (GLOBAL default::uuid_global)` - ); + testIfVersionGTE(2)("globals", async () => { + assert.equal( + e.select(e.global.uuid_global).toEdgeQL(), + `SELECT (GLOBAL default::uuid_global)` + ); - // TODO: add additional tests using .withGlobals once it lands - const str_required = await e.select(e.global.str_required).run(client); - assert.equal(str_required, `hi mom`); - const str_required_multi = await e - .select(e.global.str_required_multi) - .run(client); - assert.deepEqual(str_required_multi, ["hi", "mom"]); + const str_required = await e.select(e.global.str_required).run(client); + assert.equal(str_required, `hi mom`); + const str_required_multi = await e + .select(e.global.str_required_multi) + .run(client); + assert.deepEqual(str_required_multi, ["hi", "mom"]); - assert.equal(e.global.arr_global.__element__.__name__, `array`); - assert.deepEqual(e.global.arr_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal( - e.global.named_tuple_global.__element__.__name__, - `tuple` - ); - assert.deepEqual(e.global.named_tuple_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.global.num_global.__element__.__name__, `std::int64`); - assert.deepEqual(e.global.num_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.global.seq_global.__element__.__name__, `default::global_seq`); - assert.deepEqual(e.global.seq_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.global.str_global.__element__.__name__, `std::str`); - assert.deepEqual(e.global.str_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.global.str_global_with_default.__element__.__name__, `std::str`); - assert.deepEqual(e.global.str_global_with_default.__cardinality__, $.Cardinality.One); - assert.equal(e.global.str_multi.__element__.__name__, `default::str_multi`); - assert.deepEqual(e.global.str_multi.__cardinality__, $.Cardinality.AtLeastOne); - assert.equal(e.global.str_required.__element__.__name__, `std::str`); - assert.deepEqual(e.global.str_required.__cardinality__, $.Cardinality.One); - assert.equal( - e.global.str_required_multi.__element__.__name__, - `default::str_required_multi` - ); - assert.deepEqual(e.global.str_required_multi.__cardinality__, $.Cardinality.AtLeastOne); - assert.equal(e.global.tuple_global.__element__.__name__, `tuple`); - assert.deepEqual(e.global.tuple_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.global.uuid_global.__element__.__name__, `std::uuid`); - assert.deepEqual(e.global.uuid_global.__cardinality__, $.Cardinality.AtMostOne); - assert.equal(e.extra.global.user_id.__element__.__name__, `std::uuid`); - assert.deepEqual(e.extra.global.user_id.__cardinality__, $.Cardinality.AtMostOne); + assert.equal(e.global.arr_global.__element__.__name__, `array`); + assert.deepEqual( + e.global.arr_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal( + e.global.named_tuple_global.__element__.__name__, + `tuple` + ); + assert.deepEqual( + e.global.named_tuple_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal(e.global.num_global.__element__.__name__, `std::int64`); + assert.deepEqual( + e.global.num_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal( + e.global.seq_global.__element__.__name__, + `default::global_seq` + ); + assert.deepEqual( + e.global.seq_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal(e.global.str_global.__element__.__name__, `std::str`); + assert.deepEqual( + e.global.str_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal( + e.global.str_global_with_default.__element__.__name__, + `std::str` + ); + assert.deepEqual( + e.global.str_global_with_default.__cardinality__, + $.Cardinality.One + ); + assert.equal(e.global.str_multi.__element__.__name__, `default::str_multi`); + assert.deepEqual( + e.global.str_multi.__cardinality__, + $.Cardinality.AtLeastOne + ); + assert.equal(e.global.str_required.__element__.__name__, `std::str`); + assert.deepEqual(e.global.str_required.__cardinality__, $.Cardinality.One); + assert.equal( + e.global.str_required_multi.__element__.__name__, + `default::str_required_multi` + ); + assert.deepEqual( + e.global.str_required_multi.__cardinality__, + $.Cardinality.AtLeastOne + ); + assert.equal( + e.global.tuple_global.__element__.__name__, + `tuple` + ); + assert.deepEqual( + e.global.tuple_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal(e.global.uuid_global.__element__.__name__, `std::uuid`); + assert.deepEqual( + e.global.uuid_global.__cardinality__, + $.Cardinality.AtMostOne + ); + assert.equal(e.extra.global.user_id.__element__.__name__, `std::uuid`); + assert.deepEqual( + e.extra.global.user_id.__cardinality__, + $.Cardinality.AtMostOne + ); + }); }); diff --git a/packages/generate/test/interfaces.test.ts b/packages/generate/test/interfaces.test.ts index df1caa351..fee4b5884 100644 --- a/packages/generate/test/interfaces.test.ts +++ b/packages/generate/test/interfaces.test.ts @@ -35,8 +35,9 @@ interface test_Z extends BaseObject { xy?: X | Y | null; } -test("check generated interfaces", () => { - // TODO: re-enable test when 2.0 is stable - tc.assert>(true); - tc.assert>(true); +describe("interfaces", () => { + test("check generated interfaces", () => { + tc.assert>(true); + tc.assert>(true); + }); }); diff --git a/packages/generate/test/literals.test.ts b/packages/generate/test/literals.test.ts index 40de04da6..2dccbfdfb 100644 --- a/packages/generate/test/literals.test.ts +++ b/packages/generate/test/literals.test.ts @@ -4,126 +4,131 @@ import { TypeKind } from "edgedb/dist/reflection"; import e from "../dbschema/edgeql-js"; import { setupTests, testIfVersionGTE } from "./setupTeardown"; -test("literals", () => { - const duration = new edgedb.Duration(0, 0, 0, 0, 5, 6, 7, 8, 9, 10); - const localdate = new edgedb.LocalDate(2021, 10, 31); - const localdatetime = new edgedb.LocalDateTime(2021, 10, 31, 21, 45, 30); - const localtime = new edgedb.LocalTime(15, 15, 0); - const relduration = new edgedb.RelativeDuration(1, 2, 3); - const dateduration = new edgedb.DateDuration(1, 2, 3, 4); - const uuid = "317fee4c-0da5-45aa-9980-fedac211bfb6"; +describe("literals", () => { + test("literals", () => { + const duration = new edgedb.Duration(0, 0, 0, 0, 5, 6, 7, 8, 9, 10); + const localdate = new edgedb.LocalDate(2021, 10, 31); + const localdatetime = new edgedb.LocalDateTime(2021, 10, 31, 21, 45, 30); + const localtime = new edgedb.LocalTime(15, 15, 0); + const relduration = new edgedb.RelativeDuration(1, 2, 3); + const dateduration = new edgedb.DateDuration(1, 2, 3, 4); + const uuid = "317fee4c-0da5-45aa-9980-fedac211bfb6"; - assert.equal( - e.std.bigint(BigInt("9007199254740991")).toEdgeQL(), - `9007199254740991n` - ); - assert.equal(e.std.bool(true).toEdgeQL(), `true`); - assert.deepEqual( - e.std.bytes(Buffer.from(`whatever\nðñòóôõö÷øùúûüýþÿ`)).toEdgeQL(), - `b'whatever\\n\\xc3\\xb0\\xc3\\xb1\\xc3\\xb2\\xc3\\xb3\\xc3\\xb4\\xc3` + - `\\xb5\\xc3\\xb6\\xc3\\xb7\\xc3\\xb8\\xc3\\xb9\\xc3\\xba\\xc3\\xbb` + - `\\xc3\\xbc\\xc3\\xbd\\xc3\\xbe\\xc3\\xbf'` - ); - assert.equal( - e.std.datetime(new Date("2021-06-25T02:01:13.681Z")).toEdgeQL(), - `'2021-06-25T02:01:13.681Z'` - ); - assert.equal( - e.std.decimal("1234.1234n").toEdgeQL(), - `"1234.1234n"` - ); - assert.equal( - e.std.duration(duration).toEdgeQL(), - `'PT5H6M7.00800901S'` - ); - assert.equal(e.std.int16(144.1235).toEdgeQL(), `144.1235`); - assert.equal(e.std.int64(1234.15).toEdgeQL(), `1234.15`); - assert.equal(e.std.float64(1234.1234).toEdgeQL(), `1234.1234`); - assert.equal(e.std.float64(124).toEdgeQL(), `124`); - assert.equal( - e.std.int16("9223372036854775807").toEdgeQL(), - `9223372036854775807` - ); - assert.equal(e.year("1234").toEdgeQL(), `1234`); + assert.equal( + e.std.bigint(BigInt("9007199254740991")).toEdgeQL(), + `9007199254740991n` + ); + assert.equal(e.std.bool(true).toEdgeQL(), `true`); + assert.deepEqual( + e.std.bytes(Buffer.from(`whatever\nðñòóôõö÷øùúûüýþÿ`)).toEdgeQL(), + `b'whatever\\n\\xc3\\xb0\\xc3\\xb1\\xc3\\xb2\\xc3\\xb3\\xc3\\xb4\\xc3` + + `\\xb5\\xc3\\xb6\\xc3\\xb7\\xc3\\xb8\\xc3\\xb9\\xc3\\xba\\xc3\\xbb` + + `\\xc3\\xbc\\xc3\\xbd\\xc3\\xbe\\xc3\\xbf'` + ); + assert.equal( + e.std.datetime(new Date("2021-06-25T02:01:13.681Z")).toEdgeQL(), + `'2021-06-25T02:01:13.681Z'` + ); + assert.equal( + e.std.decimal("1234.1234n").toEdgeQL(), + `"1234.1234n"` + ); + assert.equal( + e.std.duration(duration).toEdgeQL(), + `'PT5H6M7.00800901S'` + ); + assert.equal(e.std.int16(144.1235).toEdgeQL(), `144.1235`); + assert.equal(e.std.int64(1234.15).toEdgeQL(), `1234.15`); + assert.equal( + e.std.float64(1234.1234).toEdgeQL(), + `1234.1234` + ); + assert.equal(e.std.float64(124).toEdgeQL(), `124`); + assert.equal( + e.std.int16("9223372036854775807").toEdgeQL(), + `9223372036854775807` + ); + assert.equal(e.year("1234").toEdgeQL(), `1234`); - assert.equal(e.std.json("asdf").toEdgeQL(), `to_json($$"asdf"$$)`); - assert.equal( - e.std.json({ a: 123, b: "some string", c: [true, false] }).toEdgeQL(), - 'to_json($${"a":123,"b":"some string","c":[true,false]}$$)' - ); + assert.equal(e.std.json("asdf").toEdgeQL(), `to_json($$"asdf"$$)`); + assert.equal( + e.std.json({ a: 123, b: "some string", c: [true, false] }).toEdgeQL(), + 'to_json($${"a":123,"b":"some string","c":[true,false]}$$)' + ); - assert.equal(e.std.str(`asdfaf`).toEdgeQL(), `"asdfaf"`); - assert.equal( - e.std.str(`string " with ' all \` quotes`).toEdgeQL(), - `"string \\" with ' all \` quotes"` - ); - assert.equal( - e.std.uuid(uuid).toEdgeQL(), - `"317fee4c-0da5-45aa-9980-fedac211bfb6"` - ); - assert.equal( - e.cal.local_date(localdate).toEdgeQL(), - `'2021-10-31'` - ); - assert.equal( - e.cal.local_datetime(localdatetime).toEdgeQL(), - `'2021-10-31T21:45:30'` - ); - assert.equal( - e.cal.local_time(localtime).toEdgeQL(), - `'15:15:00'` - ); - assert.equal( - e.cal.relative_duration(relduration).toEdgeQL(), - `'P1Y2M21D'` - ); - assert.equal( - e.cal.date_duration(dateduration).toEdgeQL(), - `'P1Y2M25D'` - ); -}); + assert.equal(e.std.str(`asdfaf`).toEdgeQL(), `"asdfaf"`); + assert.equal( + e.std.str(`string " with ' all \` quotes`).toEdgeQL(), + `"string \\" with ' all \` quotes"` + ); + assert.equal( + e.std.uuid(uuid).toEdgeQL(), + `"317fee4c-0da5-45aa-9980-fedac211bfb6"` + ); + assert.equal( + e.cal.local_date(localdate).toEdgeQL(), + `'2021-10-31'` + ); + assert.equal( + e.cal.local_datetime(localdatetime).toEdgeQL(), + `'2021-10-31T21:45:30'` + ); + assert.equal( + e.cal.local_time(localtime).toEdgeQL(), + `'15:15:00'` + ); + assert.equal( + e.cal.relative_duration(relduration).toEdgeQL(), + `'P1Y2M21D'` + ); + assert.equal( + e.cal.date_duration(dateduration).toEdgeQL(), + `'P1Y2M25D'` + ); + }); -test("collection type literals", () => { - const literalArray = e.literal(e.array(e.str), ["adsf"]); - assert.equal(literalArray.toEdgeQL(), `["adsf"]`); - const literalNamedTuple = e.literal(e.tuple({ str: e.str }), { - str: "asdf", + test("collection type literals", () => { + const literalArray = e.literal(e.array(e.str), ["adsf"]); + assert.equal(literalArray.toEdgeQL(), `["adsf"]`); + const literalNamedTuple = e.literal(e.tuple({ str: e.str }), { + str: "asdf", + }); + assert.equal(literalNamedTuple.toEdgeQL(), `( str := "asdf" )`); + const literalTuple = e.literal(e.tuple([e.str, e.int64]), ["asdf", 1234]); + assert.equal(literalTuple.toEdgeQL(), `( "asdf", 1234 )`); }); - assert.equal(literalNamedTuple.toEdgeQL(), `( str := "asdf" )`); - const literalTuple = e.literal(e.tuple([e.str, e.int64]), ["asdf", 1234]); - assert.equal(literalTuple.toEdgeQL(), `( "asdf", 1234 )`); -}); -test("enum literals", () => { - const horror = e.Genre.Horror; - assert.deepEqual(e.Genre.Horror.__element__.__kind__, TypeKind.enum); - assert.deepEqual(horror.__element__, e.Genre); - assert.deepEqual(horror.__cardinality__, edgedb.$.Cardinality.One); - assert.equal( - e.literal(e.Genre, "Horror").toEdgeQL(), - `default::Genre.Horror` - ); + test("enum literals", () => { + const horror = e.Genre.Horror; + assert.deepEqual(e.Genre.Horror.__element__.__kind__, TypeKind.enum); + assert.deepEqual(horror.__element__, e.Genre); + assert.deepEqual(horror.__cardinality__, edgedb.$.Cardinality.One); + assert.equal( + e.literal(e.Genre, "Horror").toEdgeQL(), + `default::Genre.Horror` + ); - assert.ok(e.Genre.__values__.includes("Horror")); + assert.ok(e.Genre.__values__.includes("Horror")); - assert.throws(() => (e.Genre as any).NotAGenre.toEdgeQL()); - assert.throws(() => e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL()); -}); + assert.throws(() => (e.Genre as any).NotAGenre.toEdgeQL()); + assert.throws(() => e.literal(e.Genre, "NotAGenre" as "Horror").toEdgeQL()); + }); -testIfVersionGTE(2)("constructing with strings", async () => { - const { client } = await setupTests(); + testIfVersionGTE(2)("constructing with strings", async () => { + const { client } = await setupTests(); - const dateString = new Date().toISOString(); - assert.deepEqual( - (await e.datetime(dateString).run(client)).toISOString(), - dateString - ); + const dateString = new Date().toISOString(); + assert.deepEqual( + (await e.datetime(dateString).run(client)).toISOString(), + dateString + ); - await e.int64("12341234").run(client); - await e.cal.local_datetime("1999-03-31T15:17:00").run(client); - await e.cal.local_date("1999-03-31").run(client); - await e.cal.local_time("15:17:00").run(client); - await e.duration("5 hours").run(client); - await e.cal.relative_duration("4 weeks 5 hours").run(client); - await e.cal.date_duration("4 months 5 days").run(client); + await e.int64("12341234").run(client); + await e.cal.local_datetime("1999-03-31T15:17:00").run(client); + await e.cal.local_date("1999-03-31").run(client); + await e.cal.local_time("15:17:00").run(client); + await e.duration("5 hours").run(client); + await e.cal.relative_duration("4 weeks 5 hours").run(client); + await e.cal.date_duration("4 months 5 days").run(client); + }); }); diff --git a/packages/generate/test/objectTypes.test.ts b/packages/generate/test/objectTypes.test.ts index 3435c7fa3..42049e7a0 100644 --- a/packages/generate/test/objectTypes.test.ts +++ b/packages/generate/test/objectTypes.test.ts @@ -11,197 +11,210 @@ const $Bag = e.default.Bag.__element__; const $Simple = e.default.Simple.__element__; const $Z = e.default.Z.__element__; -test("property hydration", () => { - assert.equal(typeof $Hero, "object"); - assert.equal($Hero.__name__, "default::Hero"); - assert.equal($Hero.__pointers__.name.__kind__, "property"); - assert.equal($Hero.__pointers__.name.cardinality, $.Cardinality.One); - assert.deepEqual($Hero.__pointers__.name.target, e.std.str); - assert.deepEqual($Hero.__pointers__.name.target.__kind__, $.TypeKind.scalar); - assert.equal($Hero.__pointers__.name.exclusive, true); - assert.equal($Hero.__pointers__.secret_identity.exclusive, false); - - assert.equal( - e.default.Movie.__element__.__pointers__.profile.exclusive, - true - ); - assert.equal( - e.default.Movie.__element__.__pointers__.characters.exclusive, - false - ); -}); - -test("link hydration", () => { - assert.equal($Hero.__pointers__.villains.__kind__, "link"); - assert.equal($Hero.__pointers__.villains.target.__kind__, $.TypeKind.object); - assert.equal($Hero.__pointers__.villains.cardinality, $.Cardinality.Many); - assert.equal($Hero.__pointers__.villains.target.__name__, "default::Villain"); - assert.deepEqual($Hero.__pointers__.villains.properties, {}); - - // type union link - assert.equal($Z.__pointers__.xy.__kind__, "link"); - assert.deepEqual(Object.keys($Z.__pointers__.xy.target.__pointers__).sort(), [ - "__type__", - "a", - "id", - ]); - assert.equal( - $Z.__pointers__.xy.target.__pointers__.a.target.__name__, - "std::str" - ); - assert.equal($Z.__pointers__.xy.target.__name__, "default::X | default::Y"); -}); - -const link = $AnnotationSubject.__pointers__.annotations; -test("link properties", () => { - assert.equal(link.properties["@value"].target.__name__, "std::str"); - assert.deepEqual( - link.properties["@value"].cardinality, - $.Cardinality.AtMostOne - ); - assert.equal(link.properties["@value"].__kind__, "property"); -}); - -test("overloaded properties", () => { - tc.assert< - tc.IsExact< - (typeof e.AdminUser)["__element__"]["__pointers__"]["username"], - PropertyDesc<$str, $.Cardinality.One, true, false, false, false> - > - >(true); -}); +describe("object types", () => { + test("property hydration", () => { + assert.equal(typeof $Hero, "object"); + assert.equal($Hero.__name__, "default::Hero"); + assert.equal($Hero.__pointers__.name.__kind__, "property"); + assert.equal($Hero.__pointers__.name.cardinality, $.Cardinality.One); + assert.deepEqual($Hero.__pointers__.name.target, e.std.str); + assert.deepEqual( + $Hero.__pointers__.name.target.__kind__, + $.TypeKind.scalar + ); + assert.equal($Hero.__pointers__.name.exclusive, true); + assert.equal($Hero.__pointers__.secret_identity.exclusive, false); + + assert.equal( + e.default.Movie.__element__.__pointers__.profile.exclusive, + true + ); + assert.equal( + e.default.Movie.__element__.__pointers__.characters.exclusive, + false + ); + }); -test("named tuple tests", () => { - // named tuple tests - const BagShape = $Bag.__pointers__; - assert.deepEqual(BagShape.namedTuple.cardinality, $.Cardinality.AtMostOne); + test("link hydration", () => { + assert.equal($Hero.__pointers__.villains.__kind__, "link"); + assert.equal( + $Hero.__pointers__.villains.target.__kind__, + $.TypeKind.object + ); + assert.equal($Hero.__pointers__.villains.cardinality, $.Cardinality.Many); + assert.equal( + $Hero.__pointers__.villains.target.__name__, + "default::Villain" + ); + assert.deepEqual($Hero.__pointers__.villains.properties, {}); + + // type union link + assert.equal($Z.__pointers__.xy.__kind__, "link"); + assert.deepEqual( + Object.keys($Z.__pointers__.xy.target.__pointers__).sort(), + ["__type__", "a", "id"] + ); + assert.equal( + $Z.__pointers__.xy.target.__pointers__.a.target.__name__, + "std::str" + ); + assert.equal($Z.__pointers__.xy.target.__name__, "default::X | default::Y"); + }); - const namedTuple = BagShape.namedTuple.target; - assert.deepEqual(namedTuple.__kind__, $.TypeKind.namedtuple); - assert.equal(namedTuple.__shape__.x.__name__, "std::str"); - assert.deepEqual(namedTuple.__shape__.x.__kind__, $.TypeKind.scalar); - assert.equal(namedTuple.__shape__.y.__name__, "std::int64"); -}); + const link = $AnnotationSubject.__pointers__.annotations; + test("link properties", () => { + assert.equal(link.properties["@value"].target.__name__, "std::str"); + assert.deepEqual( + link.properties["@value"].cardinality, + $.Cardinality.AtMostOne + ); + assert.equal(link.properties["@value"].__kind__, "property"); + }); -test("unnamed tuple tests", () => { - // named tuple tests - const BagShape = $Bag.__pointers__; - const unnamedTuple = BagShape.unnamedTuple.target; - assert.deepEqual(unnamedTuple.__kind__, $.TypeKind.tuple); - assert.equal(unnamedTuple.__items__[0].__name__, "std::str"); - assert.equal(unnamedTuple.__items__[1].__name__, "std::int64"); -}); + test("overloaded properties", () => { + tc.assert< + tc.IsExact< + (typeof e.AdminUser)["__element__"]["__pointers__"]["username"], + PropertyDesc<$str, $.Cardinality.One, true, false, false, false> + > + >(true); + }); -test("array tests", () => { - // named tuple tests - const BagShape = $Bag.__pointers__; - const arrayProp = BagShape.stringsArr.target; - assert.deepEqual(arrayProp.__kind__, $.TypeKind.array); - assert.equal(arrayProp.__element__.__name__, "std::str"); -}); + test("named tuple tests", () => { + // named tuple tests + const BagShape = $Bag.__pointers__; + assert.deepEqual(BagShape.namedTuple.cardinality, $.Cardinality.AtMostOne); -test("merging tests", () => { - const merged = $.$mergeObjectTypes($Bag, $Simple); - assert.equal(Object.keys(merged.__pointers__).length, 4); - assert.equal(Object.keys(merged.__pointers__).includes("id"), true); - assert.equal(Object.keys(merged.__pointers__).includes("__type__"), true); - assert.equal(Object.keys(merged.__pointers__).includes("name"), true); - assert.equal(Object.keys(merged.__pointers__).includes("age"), true); - type merged = keyof (typeof merged)["__pointers__"]; - // shared keys - tc.assert>(true); -}); + const namedTuple = BagShape.namedTuple.target; + assert.deepEqual(namedTuple.__kind__, $.TypeKind.namedtuple); + assert.equal(namedTuple.__shape__.x.__name__, "std::str"); + assert.deepEqual(namedTuple.__shape__.x.__kind__, $.TypeKind.scalar); + assert.equal(namedTuple.__shape__.y.__name__, "std::int64"); + }); -test("backlinks", () => { - const heroMovie = e.Hero[" ({ limit: 1 })).assert_single().nemesis - .__cardinality__, - $.Cardinality.AtMostOne - ); - - assert.equal(e.Profile[" { + // named tuple tests + const BagShape = $Bag.__pointers__; + const unnamedTuple = BagShape.unnamedTuple.target; + assert.deepEqual(unnamedTuple.__kind__, $.TypeKind.tuple); + assert.equal(unnamedTuple.__items__[0].__name__, "std::str"); + assert.equal(unnamedTuple.__items__[1].__name__, "std::int64"); + }); -test("select *", () => { - const movieStarShape = { - id: true, - title: true, - genre: true, - rating: true, - release_year: true, - }; - - // on root object - const movieStar = e.Movie["*"]; - - assert.deepEqual(movieStar, movieStarShape); - tc.assert< - tc.IsExact< - typeof movieStar, - { - id: true; - title: true; - genre: true; - rating: true; - release_year: true; - } - > - >(true); + test("array tests", () => { + // named tuple tests + const BagShape = $Bag.__pointers__; + const arrayProp = BagShape.stringsArr.target; + assert.deepEqual(arrayProp.__kind__, $.TypeKind.array); + assert.equal(arrayProp.__element__.__name__, "std::str"); + }); - // on select scope - e.select(e.Movie, (movie) => { - assert.deepEqual(movie["*"], movieStarShape); + test("merging tests", () => { + const merged = $.$mergeObjectTypes($Bag, $Simple); + assert.equal(Object.keys(merged.__pointers__).length, 4); + assert.equal(Object.keys(merged.__pointers__).includes("id"), true); + assert.equal(Object.keys(merged.__pointers__).includes("__type__"), true); + assert.equal(Object.keys(merged.__pointers__).includes("name"), true); + assert.equal(Object.keys(merged.__pointers__).includes("age"), true); + type merged = keyof (typeof merged)["__pointers__"]; + // shared keys + tc.assert>(true); + }); - return {}; + test("backlinks", () => { + const heroMovie = e.Hero[" ({ limit: 1 })).assert_single().nemesis + .__cardinality__, + $.Cardinality.AtMostOne + ); + + assert.equal(e.Profile[" ({})), - (movie) => { + test("select *", () => { + const movieStarShape = { + id: true, + title: true, + genre: true, + rating: true, + release_year: true, + }; + + // on root object + const movieStar = e.Movie["*"]; + + assert.deepEqual(movieStar, movieStarShape); + tc.assert< + tc.IsExact< + typeof movieStar, + { + id: true; + title: true; + genre: true; + rating: true; + release_year: true; + } + > + >(true); + + // on select scope + e.select(e.Movie, (movie) => { assert.deepEqual(movie["*"], movieStarShape); return {}; - } - ); - - // on polymorphic select scope - e.select(e.Person.is(e.Hero), (hero) => { - assert.deepEqual(hero["*"], { - id: true, - name: true, - height: true, - secret_identity: true, - number_of_movies: true, }); - return {}; - }); + // on wrapped select scope + e.select( + e.select(e.Movie, () => ({})), + (movie) => { + assert.deepEqual(movie["*"], movieStarShape); + + return {}; + } + ); + + // on polymorphic select scope + e.select(e.Person.is(e.Hero), (hero) => { + assert.deepEqual(hero["*"], { + id: true, + name: true, + height: true, + secret_identity: true, + number_of_movies: true, + }); + + return {}; + }); - // on insert select - e.select(e.insert(e.Movie, { title: "test" }), (movie) => { - assert.deepEqual(movie["*"], movieStarShape); + // on insert select + e.select(e.insert(e.Movie, { title: "test" }), (movie) => { + assert.deepEqual(movie["*"], movieStarShape); - return movie["*"]; - }).toEdgeQL(); + return movie["*"]; + }).toEdgeQL(); + }); }); diff --git a/packages/generate/test/paths.test.ts b/packages/generate/test/paths.test.ts index b72e6eb74..b80286d16 100644 --- a/packages/generate/test/paths.test.ts +++ b/packages/generate/test/paths.test.ts @@ -4,126 +4,143 @@ import e from "../dbschema/edgeql-js/index"; import { $PathNode } from "../dbschema/edgeql-js/syntax"; import { tc } from "./setupTeardown"; -test("path structure", () => { - const Hero = e.default.Hero; - type Hero = typeof Hero; - const $Hero = e.Hero.__element__; - const $Villain = e.Villain.__element__; - const HeroSetSingleton = $.$toSet($Hero, $.Cardinality.One); - const HeroSingleton = $PathNode(HeroSetSingleton, null); - type HeroSingleton = typeof HeroSingleton; - const VillainRoot = $.$toSet($Villain, $.Cardinality.One); - const Villain = $PathNode(VillainRoot, null); +describe("paths", () => { + test("path structure", () => { + const Hero = e.default.Hero; + type Hero = typeof Hero; + const $Hero = e.Hero.__element__; + const $Villain = e.Villain.__element__; + const HeroSetSingleton = $.$toSet($Hero, $.Cardinality.One); + const HeroSingleton = $PathNode(HeroSetSingleton, null); + type HeroSingleton = typeof HeroSingleton; + const VillainRoot = $.$toSet($Villain, $.Cardinality.One); + const Villain = $PathNode(VillainRoot, null); - assert.deepEqual(Hero.name.__element__.__kind__, $.TypeKind.scalar); - assert.equal(Hero.name.__element__.__name__, "std::str"); - assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); - assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); + assert.deepEqual(Hero.name.__element__.__kind__, $.TypeKind.scalar); + assert.equal(Hero.name.__element__.__name__, "std::str"); + assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); + assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); - assert.equal(Villain[">(true); - tc.assert>( - true - ); + // check path root cardinalities + tc.assert>(true); + tc.assert>( + true + ); - // Hero.name - assert.equal(Hero.name.__element__.__name__, "std::str"); - assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); - tc.assert>( - true - ); + // Hero.name + assert.equal(Hero.name.__element__.__name__, "std::str"); + assert.deepEqual(Hero.name.__cardinality__, $.Cardinality.Many); + tc.assert>( + true + ); - // HeroSingleton.name - assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); - tc.assert< - tc.IsExact - >(true); + // HeroSingleton.name + assert.deepEqual(HeroSingleton.name.__cardinality__, $.Cardinality.One); + tc.assert< + tc.IsExact + >(true); - // AtMostOneHero.name - // test cardinality merging - const HeroSetAtLeastOne = $.$toSet($Hero, $.Cardinality.AtLeastOne); - const AtLeastOneHero = $PathNode(HeroSetAtLeastOne, null); - type AtLeastOneHero = typeof AtLeastOneHero; - assert.deepEqual(AtLeastOneHero.id.__cardinality__, $.Cardinality.AtLeastOne); - assert.deepEqual(AtLeastOneHero.number_of_movies.__cardinality__, $.Cardinality.Many); - tc.assert< - tc.IsExact< - AtLeastOneHero["number_of_movies"]["__cardinality__"], + // AtMostOneHero.name + // test cardinality merging + const HeroSetAtLeastOne = $.$toSet($Hero, $.Cardinality.AtLeastOne); + const AtLeastOneHero = $PathNode(HeroSetAtLeastOne, null); + type AtLeastOneHero = typeof AtLeastOneHero; + assert.deepEqual( + AtLeastOneHero.id.__cardinality__, + $.Cardinality.AtLeastOne + ); + assert.deepEqual( + AtLeastOneHero.number_of_movies.__cardinality__, $.Cardinality.Many - > - >(true); + ); + tc.assert< + tc.IsExact< + AtLeastOneHero["number_of_movies"]["__cardinality__"], + $.Cardinality.Many + > + >(true); - // Hero.villains.id - assert.deepEqual(Hero.villains.id.__cardinality__, $.Cardinality.Many); - tc.assert< - tc.IsExact< - HeroSingleton["villains"]["id"]["__cardinality__"], - $.Cardinality.Many - > - >(true); + // Hero.villains.id + assert.deepEqual(Hero.villains.id.__cardinality__, $.Cardinality.Many); + tc.assert< + tc.IsExact< + HeroSingleton["villains"]["id"]["__cardinality__"], + $.Cardinality.Many + > + >(true); - assert.equal( - Hero.villains.nemesis.villains.name.toEdgeQL(), - "DETACHED default::Hero.villains.nemesis.villains.name" - ); - const Herotype = Hero.__type__.__type__.__type__; - assert.equal( - Herotype.annotations.__type__.computed_fields.toEdgeQL(), - "DETACHED default::Hero.__type__.__type__.__type__.annotations.__type__.computed_fields" - ); - assert.ok(Hero.villains.__parent__); - assert.equal(Hero.villains.__parent__?.linkName, "villains"); - assert.equal(Hero.villains.__parent__?.type.__element__.__name__, "default::Hero"); -}); + assert.equal( + Hero.villains.nemesis.villains.name.toEdgeQL(), + "DETACHED default::Hero.villains.nemesis.villains.name" + ); + const Herotype = Hero.__type__.__type__.__type__; + assert.equal( + Herotype.annotations.__type__.computed_fields.toEdgeQL(), + "DETACHED default::Hero.__type__.__type__.__type__.annotations.__type__.computed_fields" + ); + assert.ok(Hero.villains.__parent__); + assert.equal(Hero.villains.__parent__?.linkName, "villains"); + assert.equal( + Hero.villains.__parent__?.type.__element__.__name__, + "default::Hero" + ); + }); -test("type intersection on path node", () => { - const $Hero = e.Hero.__element__; - const person = e.Person; - const hero = person.is(e.Hero); - tc.assert< - tc.IsExact< - (typeof hero)["__element__"]["__pointers__"], - (typeof $Hero)["__pointers__"] - > - >(true); - tc.assert< - tc.IsExact< - (typeof hero)["__element__"]["__name__"], - (typeof $Hero)["__name__"] - > - >(true); - tc.assert< - tc.IsExact<(typeof hero)["__element__"]["__shape__"], { id: true }> - >(true); - assert.deepEqual(hero.__element__.__shape__, { id: true }); - assert.equal(hero.__element__.__name__, "default::Hero"); - assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); - assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); - // referential equality - assert.equal(hero.__expr__, person); - // check that pathify works - assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); - assert.equal(hero.toEdgeQL(), `DETACHED default::Person[IS default::Hero]`); -}); + test("type intersection on path node", () => { + const $Hero = e.Hero.__element__; + const person = e.Person; + const hero = person.is(e.Hero); + tc.assert< + tc.IsExact< + (typeof hero)["__element__"]["__pointers__"], + (typeof $Hero)["__pointers__"] + > + >(true); + tc.assert< + tc.IsExact< + (typeof hero)["__element__"]["__name__"], + (typeof $Hero)["__name__"] + > + >(true); + tc.assert< + tc.IsExact<(typeof hero)["__element__"]["__shape__"], { id: true }> + >(true); + assert.deepEqual(hero.__element__.__shape__, { id: true }); + assert.equal(hero.__element__.__name__, "default::Hero"); + assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); + assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); + // referential equality + assert.equal(hero.__expr__, person); + // check that pathify works + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); + assert.equal(hero.toEdgeQL(), `DETACHED default::Person[IS default::Hero]`); + }); -test("type intersection on select", () => { - const q2 = e.select(e.Person, () => ({ id: true, name: true, limit: 5 })); - const hero = q2.is(e.Hero); - assert.equal(hero.__element__.__name__, "default::Hero"); - assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); - assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); - // referential equality - assert.equal(hero.__expr__, q2); - // check that pathify works - assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); -}); + test("type intersection on select", () => { + const q2 = e.select(e.Person, () => ({ id: true, name: true, limit: 5 })); + const hero = q2.is(e.Hero); + assert.equal(hero.__element__.__name__, "default::Hero"); + assert.deepEqual(hero.__element__.__kind__, $.TypeKind.object); + assert.deepEqual(hero.__kind__, $.ExpressionKind.TypeIntersection); + // referential equality + assert.equal(hero.__expr__, q2); + // check that pathify works + assert.equal(hero.number_of_movies.__element__.__name__, "std::int64"); + }); -test("assert_single", () => { - const singleHero = e.Hero.assert_single(); - tc.assert< - tc.IsExact<(typeof singleHero)["__cardinality__"], $.Cardinality.AtMostOne> - >(true); - assert.deepEqual(singleHero.__cardinality__, $.Cardinality.AtMostOne); + test("assert_single", () => { + const singleHero = e.Hero.assert_single(); + tc.assert< + tc.IsExact< + (typeof singleHero)["__cardinality__"], + $.Cardinality.AtMostOne + > + >(true); + assert.deepEqual(singleHero.__cardinality__, $.Cardinality.AtMostOne); + }); }); diff --git a/packages/generate/test/primitives.test.ts b/packages/generate/test/primitives.test.ts index fd79ba599..577e0bf12 100644 --- a/packages/generate/test/primitives.test.ts +++ b/packages/generate/test/primitives.test.ts @@ -4,165 +4,169 @@ import e from "../dbschema/edgeql-js"; import type { getSharedParentPrimitiveVariadic } from "../dbschema/edgeql-js/syntax"; import { setupTests, tc, teardownTests } from "./setupTeardown"; -let client: edgedb.Client; - -beforeAll(async () => { - const setup = await setupTests(); - ({ client } = setup); -}); - -afterAll(async () => { - await teardownTests(client); -}); +describe("primitives", () => { + let client: edgedb.Client; + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); -test("primitive types", () => { - assert.equal(e.int16.__name__, "std::int16"); - assert.equal(e.int32.__name__, "std::int32"); - assert.equal(e.int64.__name__, "std::int64"); - assert.equal(e.float32.__name__, "std::float32"); - assert.equal(e.float64.__name__, "std::float64"); - assert.equal(e.str.__name__, "std::str"); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("collection types", () => { - const arrayType = e.array(e.str); - assert.equal(arrayType.__name__, "array"); - const named = e.tuple({ str: e.str }); - assert.equal(named.__name__, "tuple"); - assert.equal(named.__shape__.str.__name__, "std::str"); - const unnamed = e.tuple([e.str, e.int64]); - assert.equal(unnamed.__name__, "tuple"); - assert.equal(unnamed.__items__[0].__name__, "std::str"); - assert.equal(unnamed.__items__[1].__name__, "std::int64"); -}); + test("primitive types", () => { + assert.equal(e.int16.__name__, "std::int16"); + assert.equal(e.int32.__name__, "std::int32"); + assert.equal(e.int64.__name__, "std::int64"); + assert.equal(e.float32.__name__, "std::float32"); + assert.equal(e.float64.__name__, "std::float64"); + assert.equal(e.str.__name__, "std::str"); + }); -test("scalar type merging", () => { - type _t1 = getSharedParentPrimitiveVariadic< - [typeof e.std.str, typeof e.std.str] - >; - tc.assert>(true); - type _t2 = getSharedParentPrimitiveVariadic< - [typeof e.std.str, typeof e.std.int32] - >; - tc.assert>(true); -}); + test("collection types", () => { + const arrayType = e.array(e.str); + assert.equal(arrayType.__name__, "array"); + const named = e.tuple({ str: e.str }); + assert.equal(named.__name__, "tuple"); + assert.equal(named.__shape__.str.__name__, "std::str"); + const unnamed = e.tuple([e.str, e.int64]); + assert.equal(unnamed.__name__, "tuple"); + assert.equal(unnamed.__items__[0].__name__, "std::str"); + assert.equal(unnamed.__items__[1].__name__, "std::int64"); + }); -test("range primitives", async () => { - const range = new edgedb.Range(3, 8); - const lowerRange = new edgedb.Range(3, null); - const upperRange = new edgedb.Range(null, 8); - const dateRange = new edgedb.Range( - new Date("2022-07-05T14:00:00Z"), - new Date("2022-07-05T16:00:00Z") - ); - - assert.equal( - e.std.range(range).toEdgeQL(), - `std::range(3, 8, inc_lower := true, inc_upper := false)` - ); - assert.equal( - e.std.range(lowerRange).toEdgeQL(), - `std::range(3, {}, inc_lower := true, inc_upper := false)` - ); - assert.equal( - e.std.range(upperRange).toEdgeQL(), - `std::range({}, 8, inc_lower := true, inc_upper := false)` - ); - assert.equal( - e.std.range(dateRange).toEdgeQL(), - `std::range('2022-07-05T14:00:00.000Z', '2022-07-05T16:00:00.000Z', inc_lower := true, inc_upper := false)` - ); - - assert.equal(e.range(3, 8).toEdgeQL(), `std::range(3, 8)`); - assert.equal(e.range(3).toEdgeQL(), `std::range(3)`); - assert.equal(e.range(undefined, 8).toEdgeQL(), `std::range({}, 8)`); - - assert.throws(() => e.range(new edgedb.Range(null, null))); - assert.throws(() => e.range(edgedb.Range.empty())); - - const res = await e - .select({ - range: e.range(range), - lowerRange: e.range(lowerRange), - upperRange: e.range(upperRange), - dateRange: e.range(dateRange), - }) - .run(client); - - tc.assert< - tc.IsExact< - typeof res, - { - range: edgedb.Range; - lowerRange: edgedb.Range; - upperRange: edgedb.Range; - dateRange: edgedb.Range; - } - > - >(true); - - assert.deepEqual(res, { - range: range, - lowerRange: lowerRange, - upperRange: new edgedb.Range(null, 8, false), - dateRange: dateRange, + test("scalar type merging", () => { + type _t1 = getSharedParentPrimitiveVariadic< + [typeof e.std.str, typeof e.std.str] + >; + tc.assert>(true); + type _t2 = getSharedParentPrimitiveVariadic< + [typeof e.std.str, typeof e.std.int32] + >; + tc.assert>(true); }); - const getLower = e.range_get_lower(e.Bag.rangeField); - - tc.assert< - tc.IsExact<(typeof getLower)["__element__"]["__name__"], "std::number"> - >(true); - assert.equal(getLower.__element__.__name__, "std::number"); - - const q2 = e.params( - { - range: e.range(e.int32), - rangeArray: e.array(e.range(e.datetime)), - }, - ($) => - e.select({ - range: $.range, - rangeArray: $.rangeArray, + test("range primitives", async () => { + const range = new edgedb.Range(3, 8); + const lowerRange = new edgedb.Range(3, null); + const upperRange = new edgedb.Range(null, 8); + const dateRange = new edgedb.Range( + new Date("2022-07-05T14:00:00Z"), + new Date("2022-07-05T16:00:00Z") + ); + + assert.equal( + e.std.range(range).toEdgeQL(), + `std::range(3, 8, inc_lower := true, inc_upper := false)` + ); + assert.equal( + e.std.range(lowerRange).toEdgeQL(), + `std::range(3, {}, inc_lower := true, inc_upper := false)` + ); + assert.equal( + e.std.range(upperRange).toEdgeQL(), + `std::range({}, 8, inc_lower := true, inc_upper := false)` + ); + assert.equal( + e.std.range(dateRange).toEdgeQL(), + `std::range('2022-07-05T14:00:00.000Z', '2022-07-05T16:00:00.000Z', inc_lower := true, inc_upper := false)` + ); + + assert.equal(e.range(3, 8).toEdgeQL(), `std::range(3, 8)`); + assert.equal(e.range(3).toEdgeQL(), `std::range(3)`); + assert.equal( + e.range(undefined, 8).toEdgeQL(), + `std::range({}, 8)` + ); + + assert.throws(() => e.range(new edgedb.Range(null, null))); + assert.throws(() => e.range(edgedb.Range.empty())); + + const res = await e + .select({ + range: e.range(range), + lowerRange: e.range(lowerRange), + upperRange: e.range(upperRange), + dateRange: e.range(dateRange), }) - ); - - const res2 = await q2.run(client, { range, rangeArray: [dateRange] }); - - tc.assert< - tc.IsExact< - typeof res2, - { range: edgedb.Range; rangeArray: edgedb.Range[] } - > - >(true); - - assert.deepEqual(res2, { range: range, rangeArray: [dateRange] }); - - await e - .insert(e.Bag, { - stringsMulti: "test", - rangeField: range, - }) - .run(client); - - await e - .update(e.Bag, () => ({ - set: { - rangeField: e.range(lowerRange), + .run(client); + + tc.assert< + tc.IsExact< + typeof res, + { + range: edgedb.Range; + lowerRange: edgedb.Range; + upperRange: edgedb.Range; + dateRange: edgedb.Range; + } + > + >(true); + + assert.deepEqual(res, { + range: range, + lowerRange: lowerRange, + upperRange: new edgedb.Range(null, 8, false), + dateRange: dateRange, + }); + + const getLower = e.range_get_lower(e.Bag.rangeField); + + tc.assert< + tc.IsExact<(typeof getLower)["__element__"]["__name__"], "std::number"> + >(true); + assert.equal(getLower.__element__.__name__, "std::number"); + + const q2 = e.params( + { + range: e.range(e.int32), + rangeArray: e.array(e.range(e.datetime)), }, - })) - .run(client); + ($) => + e.select({ + range: $.range, + rangeArray: $.rangeArray, + }) + ); + + const res2 = await q2.run(client, { range, rangeArray: [dateRange] }); + + tc.assert< + tc.IsExact< + typeof res2, + { range: edgedb.Range; rangeArray: edgedb.Range[] } + > + >(true); + + assert.deepEqual(res2, { range: range, rangeArray: [dateRange] }); + + await e + .insert(e.Bag, { + stringsMulti: "test", + rangeField: range, + }) + .run(client); - const res3 = await e.select(e.Bag.rangeField).run(client); + await e + .update(e.Bag, () => ({ + set: { + rangeField: e.range(lowerRange), + }, + })) + .run(client); - tc.assert[]>>(true); + const res3 = await e.select(e.Bag.rangeField).run(client); - assert.deepEqual(res3, [lowerRange]); + tc.assert[]>>(true); - await e.delete(e.Bag).run(client); -}); + assert.deepEqual(res3, [lowerRange]); + + await e.delete(e.Bag).run(client); + }); -test("enum value with space", async () => { - const result = await e.Genre["Science Fiction"].run(client); - assert.equal(result, "Science Fiction"); + test("enum value with space", async () => { + const result = await e.Genre["Science Fiction"].run(client); + assert.equal(result, "Science Fiction"); + }); }); diff --git a/packages/generate/test/queries.test.ts b/packages/generate/test/queries.test.ts index b23259736..7746b2ff1 100644 --- a/packages/generate/test/queries.test.ts +++ b/packages/generate/test/queries.test.ts @@ -3,47 +3,50 @@ import type * as edgedb from "edgedb"; import * as tc from "conditional-type-checks"; import { getMoviesStarring } from "../dbschema/queries"; -import { setupTests, teardownTests, TestData } from "./setupTeardown"; -let client: edgedb.Client; +import { setupTests, teardownTests } from "./setupTeardown"; -beforeAll(async () => { - const setup = await setupTests(); - ({ client } = setup); -}); +describe("queries", () => { + let client: edgedb.Client; -afterAll(async () => { - await teardownTests(client); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client } = setup); + }); + + afterAll(async () => { + await teardownTests(client); + }); -test("basic select", async () => { - const result = await getMoviesStarring(client, { name: "Iron Man" }); + test("basic select", async () => { + const result = await getMoviesStarring(client, { name: "Iron Man" }); - type result = typeof result; - tc.assert< - tc.IsExact< - result, - { - id: string; - title: string; - release_year: number; - characters: { - name: string; - height: string | null; - "@character_name": string | null; - }[]; - tuple: [number, string, bigint[]]; - version: { - major: number; - minor: number; - stage: "dev" | "rc" | "beta" | "alpha" | "final"; - stage_no: number; - local: string[]; - }; - range: edgedb.Range; - local_date: edgedb.LocalDate; - }[] - > - >(true); + type result = typeof result; + tc.assert< + tc.IsExact< + result, + { + id: string; + title: string; + release_year: number; + characters: { + name: string; + height: string | null; + "@character_name": string | null; + }[]; + tuple: [number, string, bigint[]]; + version: { + major: number; + minor: number; + stage: "dev" | "rc" | "beta" | "alpha" | "final"; + stage_no: number; + local: string[]; + }; + range: edgedb.Range; + local_date: edgedb.LocalDate; + }[] + > + >(true); - assert.equal(result.length, 2); + assert.equal(result.length, 2); + }); }); diff --git a/packages/generate/test/update.test.ts b/packages/generate/test/update.test.ts index db7d965f0..eca1a5988 100644 --- a/packages/generate/test/update.test.ts +++ b/packages/generate/test/update.test.ts @@ -3,232 +3,234 @@ import type * as edgedb from "edgedb"; import e from "../dbschema/edgeql-js"; import type { UpdateShape } from "../dbschema/edgeql-js/syntax"; -import { setupTests, tc, teardownTests, TestData } from "./setupTeardown"; +import { setupTests, tc, teardownTests, type TestData } from "./setupTeardown"; -let client: edgedb.Client; -let data: TestData; +describe("update", () => { + let client: edgedb.Client; + let data: TestData; -const $Hero = e.Hero.__element__; -const $Villain = e.Villain.__element__; + const $Hero = e.Hero.__element__; + const $Villain = e.Villain.__element__; -beforeAll(async () => { - const setup = await setupTests(); - ({ client, data } = setup); -}); + beforeAll(async () => { + const setup = await setupTests(); + ({ client, data } = setup); + }); -afterAll(async () => { - await teardownTests(client); -}); + afterAll(async () => { + await teardownTests(client); + }); -test("update", async () => { - e.update(e.Hero, () => ({ - set: { - name: "asdf", - }, - })).toEdgeQL(); - - e.update(e.Villain, () => ({ - set: { - name: e.str("asdf"), - nemesis: e.cast($Hero, e.set()), - }, - })).toEdgeQL(); - - e.update(e.Bag, () => ({ - set: { - stringsMulti: { - "+=": ["new string"], + test("update", async () => { + e.update(e.Hero, () => ({ + set: { + name: "asdf", }, - }, - })).toEdgeQL(); + })).toEdgeQL(); - e.update(e.Bag, () => ({ - set: { - stringsMulti: { - "+=": "new string", + e.update(e.Villain, () => ({ + set: { + name: e.str("asdf"), + nemesis: e.cast($Hero, e.set()), }, - }, - })).toEdgeQL(); -}); + })).toEdgeQL(); -test("update assignable", () => { - e.update(e.Bag, () => ({ - set: { - int32Field: e.float32(23), - int64Field: e.float64(12), - // @ts-expect-error - bigintField: e.float32(324), - // @ts-expect-error - float32Field: e.bigint(BigInt(1234)), - }, - })).toEdgeQL(); - - e.update(e.Bag, () => ({ - set: { - int32Field: 23, - bigintField: BigInt(324), - // @ts-expect-error - float32Field: BigInt(1234), - }, - })).toEdgeQL(); - - e.update(e.Movie, () => ({ - set: { - rating: null, - profile: null, - // @ts-expect-error release_year is required prop - release_year: null, - }, - })).toEdgeQL(); -}); + e.update(e.Bag, () => ({ + set: { + stringsMulti: { + "+=": ["new string"], + }, + }, + })).toEdgeQL(); -test("scoped update", async () => { - const query = e.update(e.Hero, (hero) => ({ - filter_single: e.op(hero.name, "=", data.spidey.name), - set: { - name: e.op("The Amazing ", "++", hero.name), - }, - })); + e.update(e.Bag, () => ({ + set: { + stringsMulti: { + "+=": "new string", + }, + }, + })).toEdgeQL(); + }); - const result = await query.run(client); - tc.assert>(true); + test("update assignable", () => { + e.update(e.Bag, () => ({ + set: { + int32Field: e.float32(23), + int64Field: e.float64(12), + // @ts-expect-error + bigintField: e.float32(324), + // @ts-expect-error + float32Field: e.bigint(BigInt(1234)), + }, + })).toEdgeQL(); - assert.deepEqual(result, { id: data.spidey.id }); + e.update(e.Bag, () => ({ + set: { + int32Field: 23, + bigintField: BigInt(324), + // @ts-expect-error + float32Field: BigInt(1234), + }, + })).toEdgeQL(); - assert.deepEqual( - await e - .select(e.Hero, (hero) => ({ - name: true, - filter_single: e.op(hero.id, "=", e.uuid(result!.id)), - })) - .run(client), - { name: `The Amazing ${data.spidey.name}` } - ); -}); + e.update(e.Movie, () => ({ + set: { + rating: null, + profile: null, + // @ts-expect-error release_year is required prop + release_year: null, + }, + })).toEdgeQL(); + }); -test("update link property", async () => { - const theAvengers = e - .select(e.Movie, (movie) => ({ - filter: e.op(movie.title, "=", "The Avengers"), - limit: 1, - })) - .assert_single(); - - const qq1 = await e - .select(theAvengers, () => ({ id: true, characters: true })) - .run(client); - - assert.equal(qq1?.characters.length, 2); - - const q2 = e.update(theAvengers, () => ({ - set: { - characters: { - "+=": e.select(e.Villain, (villain) => ({ - filter: e.op(villain.name, "=", data.thanos.name), - })), + test("scoped update", async () => { + const query = e.update(e.Hero, (hero) => ({ + filter_single: e.op(hero.name, "=", data.spidey.name), + set: { + name: e.op("The Amazing ", "++", hero.name), }, - }, - })); - await q2.run(client); + })); - const t2 = await e - .select(theAvengers, () => ({ id: true, characters: true })) - .run(client); - assert.equal(t2?.characters.length, 3); + const result = await query.run(client); + tc.assert>(true); - await e - .update(theAvengers, () => ({ + assert.deepEqual(result, { id: data.spidey.id }); + + assert.deepEqual( + await e + .select(e.Hero, (hero) => ({ + name: true, + filter_single: e.op(hero.id, "=", e.uuid(result!.id)), + })) + .run(client), + { name: `The Amazing ${data.spidey.name}` } + ); + }); + + test("update link property", async () => { + const theAvengers = e + .select(e.Movie, (movie) => ({ + filter: e.op(movie.title, "=", "The Avengers"), + limit: 1, + })) + .assert_single(); + + const qq1 = await e + .select(theAvengers, () => ({ id: true, characters: true })) + .run(client); + + assert.equal(qq1?.characters.length, 2); + + const q2 = e.update(theAvengers, () => ({ set: { characters: { - "-=": e.select(e.Villain, (villain) => ({ + "+=": e.select(e.Villain, (villain) => ({ filter: e.op(villain.name, "=", data.thanos.name), })), }, }, - })) - .run(client); + })); + await q2.run(client); - const t3 = await e - .select(theAvengers, () => ({ id: true, characters: true })) - .run(client); - assert.equal(t3?.characters.length, 2); + const t2 = await e + .select(theAvengers, () => ({ id: true, characters: true })) + .run(client); + assert.equal(t2?.characters.length, 3); - await e - .update(theAvengers, () => ({ - set: { - characters: e.cast($Villain, e.set()), - }, - })) - .run(client); + await e + .update(theAvengers, () => ({ + set: { + characters: { + "-=": e.select(e.Villain, (villain) => ({ + filter: e.op(villain.name, "=", data.thanos.name), + })), + }, + }, + })) + .run(client); - const t4 = await e - .select(theAvengers, () => ({ id: true, characters: true })) - .run(client); - assert.equal(t4?.characters.length, 0); + const t3 = await e + .select(theAvengers, () => ({ id: true, characters: true })) + .run(client); + assert.equal(t3?.characters.length, 2); - await e - .update(theAvengers, () => ({ - set: { - characters: e.select(e.Hero, (hero) => ({ - filter: e.op( - hero.id, - "in", - e.set(e.uuid(data.cap.id), e.uuid(data.iron_man.id)) - ), - })), - }, - })) - .run(client); + await e + .update(theAvengers, () => ({ + set: { + characters: e.cast($Villain, e.set()), + }, + })) + .run(client); - const t5 = await e - .select(theAvengers, () => ({ id: true, characters: true })) - .run(client); - assert.equal(t5?.characters.length, 2); -}); + const t4 = await e + .select(theAvengers, () => ({ id: true, characters: true })) + .run(client); + assert.equal(t4?.characters.length, 0); -test("optional prop update", async () => { - const query = e.params({ title: e.optional(e.str) }, (params) => { - return e.update(e.Movie, (m) => ({ - filter_single: { title: "not a real title" }, - set: { - // Error here - title: params.title, - }, - })); + await e + .update(theAvengers, () => ({ + set: { + characters: e.select(e.Hero, (hero) => ({ + filter: e.op( + hero.id, + "in", + e.set(e.uuid(data.cap.id), e.uuid(data.iron_man.id)) + ), + })), + }, + })) + .run(client); + + const t5 = await e + .select(theAvengers, () => ({ id: true, characters: true })) + .run(client); + assert.equal(t5?.characters.length, 2); }); - await query.run(client, { title: "still not real" }); -}); -test("exclude readonly props", () => { - type updateProfileShape = UpdateShape<(typeof e)["Profile"]>; - tc.assert< - tc.IsExact - >(true); -}); + test("optional prop update", async () => { + const query = e.params({ title: e.optional(e.str) }, (params) => { + return e.update(e.Movie, (m) => ({ + filter_single: { title: "not a real title" }, + set: { + // Error here + title: params.title, + }, + })); + }); + await query.run(client, { title: "still not real" }); + }); -test("empty update", async () => { - const result = await e.update(e.Movie, () => ({ set: {} })).run(client); - assert.ok(result); -}); + test("exclude readonly props", () => { + type updateProfileShape = UpdateShape<(typeof e)["Profile"]>; + tc.assert< + tc.IsExact + >(true); + }); -test("update with filter_single", async () => { - await e - .update(e.Movie, () => ({ - filter_single: { id: data.the_avengers.id }, - set: {}, - })) - .run(client); -}); + test("empty update", async () => { + const result = await e.update(e.Movie, () => ({ set: {} })).run(client); + assert.ok(result); + }); + + test("update with filter_single", async () => { + await e + .update(e.Movie, () => ({ + filter_single: { id: data.the_avengers.id }, + set: {}, + })) + .run(client); + }); -test("update with filter_single + op", async () => { - await e - .update(e.Profile, (profile) => ({ - filter_single: e.op( - profile[" { + await e + .update(e.Profile, (profile) => ({ + filter_single: e.op( + profile[" { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); +describe("with", () => { + test("simple repeated expression", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal( - e.select(e.op(numbers, "+", numbers)).toEdgeQL(), - `WITH + assert.equal( + e.select(e.op(numbers, "+", numbers)).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 } SELECT (__withVar_0 + __withVar_0)` - ); -}); + ); + }); -test("simple expression with alias", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("simple expression with alias", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal( - e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL(), - `WITH + assert.equal( + e.select(e.op(numbers, "+", e.alias(numbers))).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 }, __withVar_1 := __withVar_0 SELECT (__withVar_0 + __withVar_1)` - ); -}); - -test("implicit WITH vars referencing each other", () => { - const skip = e.int64(10); - const remainingHeros = e.select(e.Hero, (hero) => ({ - order_by: hero.id, - offset: skip, - })); - const pageResults = e.select(remainingHeros, () => ({ - id: true, - name: true, - limit: 10, - })); - - const query = e.select({ - pageResults, - nextOffset: e.op(skip, "+", e.count(pageResults)), - hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), + ); }); - assert.equal( - query.toEdgeQL(), - `WITH + test("implicit WITH vars referencing each other", () => { + const skip = e.int64(10); + const remainingHeros = e.select(e.Hero, (hero) => ({ + order_by: hero.id, + offset: skip, + })); + const pageResults = e.select(remainingHeros, () => ({ + id: true, + name: true, + limit: 10, + })); + + const query = e.select({ + pageResults, + nextOffset: e.op(skip, "+", e.count(pageResults)), + hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), + }); + + assert.equal( + query.toEdgeQL(), + `WITH __withVar_4 := 10, __withVar_3 := ( WITH @@ -71,85 +72,86 @@ SELECT { single nextOffset := (__withVar_4 + std::count(__withVar_1)), single hasMore := (SELECT (std::count(__withVar_3) > 10)) }` - ); + ); - type queryType = $.BaseTypeToTsType<(typeof query)["__element__"]>; - tc.assert< - tc.IsExact< - queryType, - { - pageResults: { - id: string; - name: string; - }[]; - nextOffset: number; - hasMore: boolean; - } - > - >(true); -}); + type queryType = $.BaseTypeToTsType<(typeof query)["__element__"]>; + tc.assert< + tc.IsExact< + queryType, + { + pageResults: { + id: string; + name: string; + }[]; + nextOffset: number; + hasMore: boolean; + } + > + >(true); + }); -test("simple repeated expression not in select expr", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("simple repeated expression not in select expr", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.throws(() => e.op(numbers, "+", numbers).toEdgeQL()); -}); + assert.throws(() => e.op(numbers, "+", numbers).toEdgeQL()); + }); -test("explicit WITH block", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH block", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal( - e.with([numbers], e.select(numbers)).toEdgeQL(), - `WITH + assert.equal( + e.with([numbers], e.select(numbers)).toEdgeQL(), + `WITH __withVar_0 := { 1, 2, 3 } SELECT __withVar_0` - ); -}); + ); + }); -test("explicit WITH block in nested query", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH block in nested query", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.equal( - e - .select({ - nested: e.with([numbers], e.select(numbers)), - }) - .toEdgeQL(), - `SELECT { + assert.equal( + e + .select({ + nested: e.with([numbers], e.select(numbers)), + }) + .toEdgeQL(), + `SELECT { multi nested := assert_exists(( WITH __withVar_0 := { 1, 2, 3 } SELECT __withVar_0 )) }` - ); -}); + ); + }); -test("explicit WITH in nested query, var used outside WITH block", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH in nested query, var used outside WITH block", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - assert.throws(() => - e - .select({ - numbers, - nested: e.with([numbers], e.select(numbers)), - }) - .toEdgeQL()); -}); + assert.throws(() => + e + .select({ + numbers, + nested: e.with([numbers], e.select(numbers)), + }) + .toEdgeQL() + ); + }); -test("explicit WITH block nested in implicit WITH block", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH block nested in implicit WITH block", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - const explicitWith = e.with([numbers], e.select(numbers)); + const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), - `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -159,24 +161,24 @@ SELECT { multi numbers := assert_exists(__withVar_0), multi numbers2 := assert_exists(__withVar_0) }` - ); -}); + ); + }); -test("explicit WITH block nested in explicit WITH block", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH block nested in explicit WITH block", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - const explicitWith = e.with([numbers], e.select(numbers)); + const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal( - e - .with( - [explicitWith], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), - `WITH + assert.equal( + e + .with( + [explicitWith], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 } @@ -185,25 +187,25 @@ test("explicit WITH block nested in explicit WITH block", () => { SELECT { multi numbers := assert_exists(__withVar_0) }` - ); -}); + ); + }); -test("explicit WITH block nested in explicit WITH block, sub expr explicitly extracted", () => { - const number = e.int64(2); - const numbers = e.set(e.int64(1), number, e.int64(3)); + test("explicit WITH block nested in explicit WITH block, sub expr explicitly extracted", () => { + const number = e.int64(2); + const numbers = e.set(e.int64(1), number, e.int64(3)); - const explicitWith = e.with([numbers], e.select(numbers)); + const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal( - e - .with( - [explicitWith, number], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), - `WITH + assert.equal( + e + .with( + [explicitWith, number], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -213,43 +215,44 @@ test("explicit WITH block nested in explicit WITH block, sub expr explicitly ext SELECT { multi numbers := assert_exists(__withVar_0) }` - ); -}); + ); + }); -test("explicit WITH nested in explicit WITH, expr declared in both", () => { - const number = e.int64(2); - const numbers = e.set(e.int64(1), number, e.int64(3)); + test("explicit WITH nested in explicit WITH, expr declared in both", () => { + const number = e.int64(2); + const numbers = e.set(e.int64(1), number, e.int64(3)); - const explicitWith = e.with([numbers], e.select(numbers)); + const explicitWith = e.with([numbers], e.select(numbers)); - assert.throws(() => - e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL()); -}); + assert.throws(() => + e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL() + ); + }); -test("explicit WITH block nested in explicit WITH block, sub expr implicitly extracted", () => { - const number = e.int64(2); - const numbers = e.set(e.int64(1), number, e.int64(3)); + test("explicit WITH block nested in explicit WITH block, sub expr implicitly extracted", () => { + const number = e.int64(2); + const numbers = e.set(e.int64(1), number, e.int64(3)); - const explicitWith = e.with([numbers], e.select(numbers)); + const explicitWith = e.with([numbers], e.select(numbers)); - assert.equal( - e - .with( - [explicitWith], - e.select({ - number, - numbers: explicitWith, - }) - ) - .toEdgeQL(), - `WITH + assert.equal( + e + .with( + [explicitWith], + e.select({ + number, + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_2 := 2, __withVar_0 := ( WITH @@ -260,32 +263,32 @@ SELECT { single number := __withVar_2, multi numbers := assert_exists(__withVar_0) }` - ); -}); - -test("implicit WITH and explicit WITH in sub expr", () => { - const skip = e.int64(10); - const remainingHeros = e.select(e.Hero, (hero) => ({ - order_by: hero.id, - offset: skip, - })); - const pageResults = e.select(remainingHeros, () => ({ - id: true, - name: true, - limit: 10, - })); - - const nextOffset = e.op(skip, "+", e.count(pageResults)); - - const query = e.select({ - pageResults, - nextOffset: e.with([nextOffset], e.select(nextOffset)), - hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), + ); }); - assert.equal( - query.toEdgeQL(), - `WITH + test("implicit WITH and explicit WITH in sub expr", () => { + const skip = e.int64(10); + const remainingHeros = e.select(e.Hero, (hero) => ({ + order_by: hero.id, + offset: skip, + })); + const pageResults = e.select(remainingHeros, () => ({ + id: true, + name: true, + limit: 10, + })); + + const nextOffset = e.op(skip, "+", e.count(pageResults)); + + const query = e.select({ + pageResults, + nextOffset: e.with([nextOffset], e.select(nextOffset)), + hasMore: e.select(e.op(e.count(remainingHeros), ">", 10)), + }); + + assert.equal( + query.toEdgeQL(), + `WITH __withVar_5 := 10, __withVar_4 := ( WITH @@ -314,24 +317,24 @@ SELECT { ), single hasMore := (SELECT (std::count(__withVar_4) > 10)) }` - ); -}); + ); + }); -test("explicit WITH nested in implicit WITH + alias implicit", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH nested in implicit WITH + alias implicit", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - const numbersAlias = e.alias(numbers); + const numbersAlias = e.alias(numbers); - const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); + const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - assert.equal( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), - `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -345,27 +348,27 @@ SELECT { single numbers := __withVar_0, single numbers2 := __withVar_0 }` - ); -}); + ); + }); -test("explicit WITH nested in implicit WITH + alias explicit", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); + test("explicit WITH nested in implicit WITH + alias explicit", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - const numbersAlias = e.alias(numbers); + const numbersAlias = e.alias(numbers); - const explicitWith = e.with( - [numbers, numbersAlias], - e.select({ numbers, numbersAlias }) - ); + const explicitWith = e.with( + [numbers, numbersAlias], + e.select({ numbers, numbersAlias }) + ); - assert.equal( - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - }) - .toEdgeQL(), - `WITH + assert.equal( + e + .select({ + numbers: explicitWith, + numbers2: explicitWith, + }) + .toEdgeQL(), + `WITH __withVar_0 := ( WITH __withVar_1 := { 1, 2, 3 }, @@ -379,51 +382,52 @@ SELECT { single numbers := __withVar_0, single numbers2 := __withVar_0 }` - ); -}); - -test("explicit WITH nested in implicit WITH + alias outside WITH", () => { - const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); - - const numbersAlias = e.alias(numbers); - - const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - - assert.throws(() => - e - .select({ - numbers: explicitWith, - numbers2: explicitWith, - numbersAlias, - }) - .toEdgeQL()); -}); + ); + }); -test( - "explicit WITH block nested in explicit WITH block, " + - "alias declared in inner WITH", - () => { - const number = e.int64(2); - const numbers = e.set(e.int64(1), number, e.int64(3)); + test("explicit WITH nested in implicit WITH + alias outside WITH", () => { + const numbers = e.set(e.int64(1), e.int64(2), e.int64(3)); const numbersAlias = e.alias(numbers); - const arg = e.op(numbers, "+", numbersAlias); - const explicitWith = e.with( - [numbersAlias], - e.select(e.op(numbers, "+", numbersAlias)) - ); + const explicitWith = e.with([numbers], e.select({ numbers, numbersAlias })); - assert.equal( + assert.throws(() => e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), - `WITH + .select({ + numbers: explicitWith, + numbers2: explicitWith, + numbersAlias, + }) + .toEdgeQL() + ); + }); + + test( + "explicit WITH block nested in explicit WITH block, " + + "alias declared in inner WITH", + () => { + const number = e.int64(2); + const numbers = e.set(e.int64(1), number, e.int64(3)); + + const numbersAlias = e.alias(numbers); + + const arg = e.op(numbers, "+", numbersAlias); + const explicitWith = e.with( + [numbersAlias], + e.select(e.op(numbers, "+", numbersAlias)) + ); + + assert.equal( + e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `WITH __withVar_1 := { 1, 2, 3 }, __withVar_0 := ( WITH @@ -433,35 +437,35 @@ test( SELECT { multi numbers := assert_exists(__withVar_0) }` - ); - } -); - -test( - "explicit WITH block nested in explicit WITH block, " + - "alias of alias declared in inner WITH", - () => { - const number = e.int64(2); - const numbers = e.set(e.int64(1), number, e.int64(3)); - - const numbersAlias = e.alias(numbers); - const numbersAlias2 = e.alias(numbersAlias); - - const explicitWith = e.with( - [numbersAlias2], - e.select(e.op(numbers, "+", numbersAlias2)) - ); + ); + } + ); - assert.equal( - e - .with( - [explicitWith, numbers], - e.select({ - numbers: explicitWith, - }) - ) - .toEdgeQL(), - `\ + test( + "explicit WITH block nested in explicit WITH block, " + + "alias of alias declared in inner WITH", + () => { + const number = e.int64(2); + const numbers = e.set(e.int64(1), number, e.int64(3)); + + const numbersAlias = e.alias(numbers); + const numbersAlias2 = e.alias(numbersAlias); + + const explicitWith = e.with( + [numbersAlias2], + e.select(e.op(numbers, "+", numbersAlias2)) + ); + + assert.equal( + e + .with( + [explicitWith, numbers], + e.select({ + numbers: explicitWith, + }) + ) + .toEdgeQL(), + `\ WITH __withVar_1 := { 1, 2, 3 }, __withVar_2 := __withVar_1, @@ -473,22 +477,22 @@ WITH SELECT { multi numbers := assert_exists(__withVar_0) }` - ); - } -); - -test("query with no WITH block", () => { - const query = e.select(e.Person.is(e.Hero), (person) => ({ - id: true, - computable: e.int64(35), - all_heroes: e.select(e.Hero, () => ({ __type__: { name: true } })), - order_by: person.name, - limit: 1, - })); - - assert.equal( - query.toEdgeQL(), - `\ + ); + } + ); + + test("query with no WITH block", () => { + const query = e.select(e.Person.is(e.Hero), (person) => ({ + id: true, + computable: e.int64(35), + all_heroes: e.select(e.Hero, () => ({ __type__: { name: true } })), + order_by: person.name, + limit: 1, + })); + + assert.equal( + query.toEdgeQL(), + `\ WITH __scope_0_defaultHero := DETACHED default::Person[IS default::Hero] SELECT __scope_0_defaultHero { @@ -510,26 +514,26 @@ SELECT __scope_0_defaultHero { } ORDER BY __scope_0_defaultHero.name LIMIT 1` - ); -}); - -test("repeated expression referencing scoped select object", () => { - const query = e.select(e.Hero, (hero) => { - const secret = e.op( - e.op(hero.name, "++", " is "), - "++", - hero.secret_identity ); - return { - name: true, - secret, - secret2: secret, - }; }); - assert.equal( - query.toEdgeQL(), - `\ + test("repeated expression referencing scoped select object", () => { + const query = e.select(e.Hero, (hero) => { + const secret = e.op( + e.op(hero.name, "++", " is "), + "++", + hero.secret_identity + ); + return { + name: true, + secret, + secret2: secret, + }; + }); + + assert.equal( + query.toEdgeQL(), + `\ WITH __scope_0_defaultHero_expr := DETACHED default::Hero, __scope_0_defaultHero := (FOR __scope_0_defaultHero_inner IN {__scope_0_defaultHero_expr} UNION ( @@ -544,12 +548,13 @@ SELECT __scope_0_defaultHero { single secret := __scope_0_defaultHero.__withVar_1, single secret2 := __scope_0_defaultHero.__withVar_1 }` - ); -}); + ); + }); -test("repeated expr used outside scope", () => { - const expr = e.to_str(e.int64(123)); - const query = e.tuple([expr, e.select(expr)]); + test("repeated expr used outside scope", () => { + const expr = e.to_str(e.int64(123)); + const query = e.tuple([expr, e.select(expr)]); - assert.throws(() => query.toEdgeQL()); + assert.throws(() => query.toEdgeQL()); + }); }); From 5ae5707fbd185ceb5169d878a727ed438fd4900c Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Tue, 30 May 2023 16:58:12 -0400 Subject: [PATCH 10/20] FORMAT --- packages/generate/test/insert.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/generate/test/insert.test.ts b/packages/generate/test/insert.test.ts index dc2c0985a..ffa0b0535 100644 --- a/packages/generate/test/insert.test.ts +++ b/packages/generate/test/insert.test.ts @@ -338,7 +338,8 @@ describe("insert", () => { name: "Star-Lord", "@character_name": "Peter Quill", }), - })); + }) + ); }); test("undefined in insert", async () => { From 5d2a6a977d1078d61b23eb1c2cb775a73681e6dc Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 11 May 2023 16:38:17 -0400 Subject: [PATCH 11/20] Set up trouble scenario in schema --- packages/generate/dbschema/default.esdl | 15 +++++++++++++-- packages/generate/test/interfaces.test.ts | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/generate/dbschema/default.esdl b/packages/generate/dbschema/default.esdl index f7e0889bb..81a1b97ea 100644 --- a/packages/generate/dbschema/default.esdl +++ b/packages/generate/dbschema/default.esdl @@ -20,7 +20,13 @@ module default { scalar type global_seq extending sequence; global seq_global -> global_seq; + abstract type Power { + property name -> str; + } + type GoodPower extending Power {} + + type EvilPower extending Power {} abstract link movie_character { property character_name -> str; @@ -31,16 +37,21 @@ module default { constraint exclusive; }; property height -> decimal; + multi link powers -> Power; } - type Villain extending Person { + abstract type MainCharacter extending Person {} + + type Villain extending MainCharacter { link nemesis -> Hero; + overloaded multi link powers -> EvilPower; } - type Hero extending Person { + type Hero extending MainCharacter { property secret_identity -> str; property number_of_movies -> int64; multi link villains := . GoodPower; } scalar type year extending int16 { diff --git a/packages/generate/test/interfaces.test.ts b/packages/generate/test/interfaces.test.ts index fee4b5884..d3f058374 100644 --- a/packages/generate/test/interfaces.test.ts +++ b/packages/generate/test/interfaces.test.ts @@ -1,6 +1,6 @@ import * as tc from "conditional-type-checks"; -import type { Movie, X, Y, Z } from "../dbschema/interfaces"; +import type { Power, Movie, X, Y, Z } from "../dbschema/interfaces"; export type Genre = | "Horror" @@ -15,6 +15,7 @@ export interface BaseObject { export interface test_Person extends BaseObject { name: string; height?: string | null; + powers: Power[]; } export interface test_Movie extends BaseObject { characters: test_Person[]; From 017143d3d5d9045834ca62b105fb73d6a7893b7b Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Fri, 12 May 2023 11:44:17 -0400 Subject: [PATCH 12/20] Fix warning in jest config --- packages/generate/jest.config.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/generate/jest.config.js b/packages/generate/jest.config.js index 14bb9c484..0d1006dcf 100644 --- a/packages/generate/jest.config.js +++ b/packages/generate/jest.config.js @@ -3,10 +3,8 @@ module.exports = { testEnvironment: "node", testPathIgnorePatterns: ["./dist", "./esm", "./mts", "./cjs", "./deno"], globalSetup: "./test/globalSetup.ts", - transform: {}, - globals: { - "ts-jest": { - tsconfig: "tsconfig.json" - } - } + transform: { + "^.+\\.tsx?$": "ts-jest", + }, + globals: {}, }; From 50202a1ba082194d462d4c12da958f3852dfe783 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Fri, 12 May 2023 11:44:32 -0400 Subject: [PATCH 13/20] Test case to demonstrate type-level issue --- packages/generate/test/insert.test.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/generate/test/insert.test.ts b/packages/generate/test/insert.test.ts index ffa0b0535..eae8644f7 100644 --- a/packages/generate/test/insert.test.ts +++ b/packages/generate/test/insert.test.ts @@ -149,14 +149,22 @@ describe("insert", () => { test("nested insert", async () => { const q1 = e.insert(e.Villain, { name: e.str("villain"), + powers: e.insert(e.EvilPower, { name: "genius" }), + nemesis: e.insert(e.Hero, { name: "hero", + powers: e.for(e.set(e.str("flight"), e.str("super strength")), (name) => + e.insert(e.GoodPower, { name }) + ), }), }); const q2 = e.select(q1, () => ({ name: true, - nemesis: { name: true }, + powers: { + name: true, + }, + nemesis: { name: true, powers: { name: true } }, })); const result = await q2.run(client); @@ -164,9 +172,11 @@ describe("insert", () => { assert.deepEqual(result, { ...result, name: "villain", + powers: [{ name: "genius" }], nemesis: { ...result.nemesis, name: "hero", + powers: [{ name: "flight" }, { name: "super strength" }], }, }); From c49d32380d9ee014e64f43af6137c5675d175fe2 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Mon, 15 May 2023 16:12:06 -0400 Subject: [PATCH 14/20] Add migration --- .../generate/dbschema/migrations/00021.edgeql | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 packages/generate/dbschema/migrations/00021.edgeql diff --git a/packages/generate/dbschema/migrations/00021.edgeql b/packages/generate/dbschema/migrations/00021.edgeql new file mode 100644 index 000000000..32aca7f9d --- /dev/null +++ b/packages/generate/dbschema/migrations/00021.edgeql @@ -0,0 +1,35 @@ +CREATE MIGRATION m1u4jn5jcn65vrccu2a2ynlio44tm67exuplgdmmu4m2q2ej5u2fxa + ONTO m1sxhoqfjqn7vtpmatzanmwydtxndf3jlf33npkblmya42fx3bcdoa +{ + CREATE ABSTRACT TYPE default::Power { + CREATE PROPERTY name -> std::str; + }; + CREATE TYPE default::EvilPower EXTENDING default::Power; + ALTER TYPE default::Person { + CREATE MULTI LINK powers -> default::Power; + }; + CREATE ABSTRACT TYPE default::MainCharacter EXTENDING default::Person; + ALTER TYPE default::Villain { + DROP EXTENDING default::Person; + EXTENDING default::MainCharacter LAST; + }; + ALTER TYPE default::Villain { + ALTER LINK powers { + SET MULTI; + SET OWNED; + SET TYPE default::EvilPower USING ({}); + }; + }; + CREATE TYPE default::GoodPower EXTENDING default::Power; + ALTER TYPE default::Hero { + DROP EXTENDING default::Person; + EXTENDING default::MainCharacter LAST; + }; + ALTER TYPE default::Hero { + ALTER LINK powers { + SET MULTI; + SET OWNED; + SET TYPE default::GoodPower USING ({}); + }; + }; +}; From 22e2da8b96447a94735af1bf936830d23f1581ed Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Tue, 16 May 2023 04:59:44 -0400 Subject: [PATCH 15/20] Recurse bases to get overloaded field candidates --- .../src/edgeql-js/generateObjectTypes.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/generate/src/edgeql-js/generateObjectTypes.ts b/packages/generate/src/edgeql-js/generateObjectTypes.ts index 5ec96b0ec..5154ff7d4 100644 --- a/packages/generate/src/edgeql-js/generateObjectTypes.ts +++ b/packages/generate/src/edgeql-js/generateObjectTypes.ts @@ -381,12 +381,21 @@ export const generateObjectTypes = (params: GeneratorParams) => { const baseTypesUnion = type.bases.length ? frag`${joinFrags( type.bases.map((base) => { + function getRecursiveLinks(base: { + id: string; + }): ($.introspect.Pointer | $.introspect.Backlink)[] { + const baseType = types.get(base.id) as $.introspect.ObjectType; + return [ + ...baseType.pointers, + ...baseType.backlinks, + ...baseType.backlink_stubs, + ...(baseType.bases.length + ? baseType.bases.flatMap(getRecursiveLinks) + : []), + ]; + } const baseType = types.get(base.id) as $.introspect.ObjectType; - const overloadedFields = [ - ...baseType.pointers, - ...baseType.backlinks, - ...baseType.backlink_stubs, - ] + const overloadedFields = getRecursiveLinks(base) .filter((field) => fieldNames.has(field.name)) .map((field) => quote(field.name)); const baseRef = getRef(baseType.name); From 68ded9e58ec70a5753bf058afab7aeecb2fd51f2 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Tue, 16 May 2023 16:08:13 -0400 Subject: [PATCH 16/20] Use subtype names to allow nominal Select The code before assumed that subtypes were structurally assignable to their supertype, but via overloads the subtypes might have incompatible shapes. Now we specifically list the subtypes of an abstract type as assignable to the supertype. --- .../src/edgeql-js/generateObjectTypes.ts | 107 ++++++++++++++---- packages/generate/src/syntax/casting.ts | 13 ++- packages/generate/src/syntax/typesystem.ts | 5 +- 3 files changed, 95 insertions(+), 30 deletions(-) diff --git a/packages/generate/src/edgeql-js/generateObjectTypes.ts b/packages/generate/src/edgeql-js/generateObjectTypes.ts index 5154ff7d4..d01f22b72 100644 --- a/packages/generate/src/edgeql-js/generateObjectTypes.ts +++ b/packages/generate/src/edgeql-js/generateObjectTypes.ts @@ -1,4 +1,4 @@ -import { CodeFragment, dts, r, t, ts } from "../builders"; +import { CodeFragment, IdentRef, dts, r, t, ts } from "../builders"; import type { GeneratorParams } from "../genutil"; import type { $ } from "../genutil"; import { @@ -453,34 +453,93 @@ export const generateObjectTypes = (params: GeneratorParams) => { // instantiate ObjectType subtype from shape body.writeln([ dts`declare `, - t`type ${ref} = $.ObjectType<${quote(type.name)}, ${ref}λShape, null, [`, + // type Foo = $.ObjectType< + t`type ${ref} = $.ObjectType<`, ]); - - const bases = type.bases - .map((b) => types.get(b.id)) - .map((b) => getRef(b.name)); body.indented(() => { - for (const b of bases) { - body.writeln([t`...${b}['__exclusives__'],`]); + // Name + body.writeln([t`${quote(type.name)},`]); + // Pointers + body.writeln([t`${ref}λShape, `]); + // Shape + body.writeln([t`null, `]); + // Exclusives + body.writeln([t`[`]); + + // Base types exclusives + const bases = (function findRecursiveBases( + bases: readonly { id: string }[] + ): IdentRef[] { + return [ + ...bases + .map((b) => types.get(b.id) as $.introspect.ObjectType) + // TODO: make this better at rejecting system types + .filter((b) => splitName(b.name).mod !== "std") + .flatMap((b) => { + if (b.bases.length) { + return [...findRecursiveBases(b.bases), b]; + } + return [b]; + }) + .map((b) => getRef(b.name)), + ]; + })(type.bases); + + body.indented(() => { + for (const b of bases) { + body.writeln([t`...${b}['__exclusives__'],`]); + } + }); + + // This type exclusives + body.indented(() => { + for (const ex of type.exclusives) { + body.writeln([ + t`{`, + ...Object.keys(ex).map((key) => { + const target = types.get(ex[key].target_id); + const { staticType } = getStringRepresentation(target, { types }); + const card = `$.Cardinality.One | $.Cardinality.AtMostOne `; + return t`${key}: {__element__: ${staticType}, __cardinality__: ${card}},`; + }), + t`},`, + ]); + } + }); + + // Exclusives, End + body.writeln([t`],`]); + + // Subtypes + body.writeln([t`| ${quote(ref.name)}`]); + if ( + type.is_abstract && + !["std", "sys", "schema"].includes(splitName(type.name).mod) + ) { + function findRecursiveSubtypes(type: { + id: string; + }): $.introspect.ObjectType[] { + const subtypes: $.introspect.ObjectType[] = []; + for (const candidate of types.values()) { + if ( + candidate.kind === "object" && + candidate.bases.find((b) => b.id === type.id) + ) { + subtypes.push(candidate); + subtypes.push(...findRecursiveSubtypes(candidate)); + } + } + return subtypes; + } + const subtypes = findRecursiveSubtypes(type).map((t) => getRef(t.name)); + + for (const sub of subtypes) { + body.writeln([t`| ${quote(sub.name)}`]); + } } }); - // const ref = getRef(type.name); - for (const ex of type.exclusives) { - body.writeln([ - t` {`, - ...Object.keys(ex).map((key) => { - const target = types.get(ex[key].target_id); - const { staticType } = getStringRepresentation(target, { types }); - const card = `$.Cardinality.One | $.Cardinality.AtMostOne `; - return t`${key}: {__element__: ${staticType}, __cardinality__: ${card}},`; - }), - t`},`, - ]); - // body.writeln([t`\n {${lines.join(", ")}}`]); - } - - body.writeln([t`]>;`]); + body.writeln([t`>;`]); if (type.name === "std::Object") { body.writeln([t`export `, dts`declare `, t`type $Object = ${ref}`]); diff --git a/packages/generate/src/syntax/casting.ts b/packages/generate/src/syntax/casting.ts index a6b9c6ad6..914926a94 100644 --- a/packages/generate/src/syntax/casting.ts +++ b/packages/generate/src/syntax/casting.ts @@ -15,6 +15,8 @@ import type { TupleType, TypeSet, RangeType, + ExclusiveTuple, + ObjectTypePointers, } from "./typesystem"; import type { cardutil } from "./cardinality"; @@ -73,22 +75,25 @@ export type pointerToAssignmentExpression< export type setToAssignmentExpression< Set extends TypeSet, IsSetModifier extends boolean -> = [Set] extends [PrimitiveTypeSet] +> = Set extends PrimitiveTypeSet ? | TypeSet< assignableBy, cardutil.assignable< - // Set["__cardinality__"] cardutil.overrideLowerBound > > | getAssignmentLiteral - : [Set] extends [ObjectTypeSet] + : Set extends ObjectTypeSet ? TypeSet< ObjectType< // anonymize the object type string, - Set["__element__"]["__pointers__"] + ObjectTypePointers, + any, + ExclusiveTuple, + // Allow expressions that are assignable to a supertype + Set["__element__"]["__subNames__"] >, cardutil.assignable< // Allow expressions with AtMostOne or Many cardinality in diff --git a/packages/generate/src/syntax/typesystem.ts b/packages/generate/src/syntax/typesystem.ts index 7f2f0d318..f9b4a752e 100644 --- a/packages/generate/src/syntax/typesystem.ts +++ b/packages/generate/src/syntax/typesystem.ts @@ -217,14 +217,15 @@ export interface ObjectType< Name extends string = string, Pointers extends ObjectTypePointers = ObjectTypePointers, Shape extends object | null = any, - Exclusives extends ExclusiveTuple = ExclusiveTuple - // Polys extends Poly[] = any[] + Exclusives extends ExclusiveTuple = ExclusiveTuple, + SubtypeNames extends string = Name > extends BaseType { __kind__: TypeKind.object; __name__: Name; __pointers__: Pointers; __shape__: Shape; __exclusives__: Exclusives; + __subNames__: SubtypeNames; } export type PropertyTypes = From 9c02ec8399829f89f1c5596fe1bd38b873e6a8a6 Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Wed, 17 May 2023 09:56:31 -0400 Subject: [PATCH 17/20] Pass the subnames in the select expression type --- packages/generate/src/syntax/select.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/generate/src/syntax/select.ts b/packages/generate/src/syntax/select.ts index c813db4f0..9ef940d15 100644 --- a/packages/generate/src/syntax/select.ts +++ b/packages/generate/src/syntax/select.ts @@ -872,7 +872,9 @@ export function select( __element__: ObjectType< `${Expr["__element__"]["__name__"]}`, // _shape Expr["__element__"]["__pointers__"], - Expr["__element__"]["__shape__"] // {id: true} + Expr["__element__"]["__shape__"], // {id: true} + Expr["__element__"]["__exclusives__"], + Expr["__element__"]["__subNames__"] >; __cardinality__: Expr["__cardinality__"]; }>; From 25745765afeaca09a70fab2ff2063e335173898d Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Wed, 17 May 2023 10:06:44 -0400 Subject: [PATCH 18/20] Include system types when finding base types --- packages/generate/src/edgeql-js/generateObjectTypes.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/generate/src/edgeql-js/generateObjectTypes.ts b/packages/generate/src/edgeql-js/generateObjectTypes.ts index d01f22b72..809fd67cd 100644 --- a/packages/generate/src/edgeql-js/generateObjectTypes.ts +++ b/packages/generate/src/edgeql-js/generateObjectTypes.ts @@ -473,8 +473,6 @@ export const generateObjectTypes = (params: GeneratorParams) => { return [ ...bases .map((b) => types.get(b.id) as $.introspect.ObjectType) - // TODO: make this better at rejecting system types - .filter((b) => splitName(b.name).mod !== "std") .flatMap((b) => { if (b.bases.length) { return [...findRecursiveBases(b.bases), b]; From 84f5c1dd904c8ab9cb59b3b67e9e50720d3b238b Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Wed, 17 May 2023 10:07:03 -0400 Subject: [PATCH 19/20] Remove commented out code --- packages/generate/src/syntax/select.ts | 53 ++------------------------ 1 file changed, 4 insertions(+), 49 deletions(-) diff --git a/packages/generate/src/syntax/select.ts b/packages/generate/src/syntax/select.ts index 9ef940d15..d3db90099 100644 --- a/packages/generate/src/syntax/select.ts +++ b/packages/generate/src/syntax/select.ts @@ -111,57 +111,12 @@ export type exclusivesToFilterSingle = : orLiteralValue; }; }[number]; + export type SelectModifiers = { - // export type SelectModifiers = { filter?: SelectFilterExpression; - filter_single?: // | Partial< - // typeutil.stripNever<{ - // [k in keyof T["__pointers__"]]: T["__pointers__"][k] - // extends PropertyDesc - // ? orScalarLiteral<{ - // __element__: T["__pointers__"][k]["target"]; - // __cardinality__: T["__pointers__"][k]["cardinality"]; - // }> - // : never; - // }> - // > - - // | (ObjectType extends T - // ? unknown - // : typeutil.stripNever<{ - // [k in keyof T["__pointers__"]]: T["__pointers__"][k] - // extends PropertyDesc< - // infer T, - // infer C, - // infer E - // > - // ? E extends true - // ? orScalarLiteral<{ - // __element__: T; - // __cardinality__: C; - // }> - // : never - // : never; - // }>) - exclusivesToFilterSingle | SelectFilterExpression; - - // | (ObjectType extends T - // ? unknown - // : typeutil.stripNever<{ - // [k in keyof T["__pointers__"]]: T["__pointers__"][k] - // extends PropertyDesc< - // infer T, - // infer C, - // infer E - // > - // ? E extends true - // ? orScalarLiteral<{ - // __element__: T; - // __cardinality__: C; - // }> - // : never - // : never; - // }>); + filter_single?: + | exclusivesToFilterSingle + | SelectFilterExpression; order_by?: OrderByExpression; offset?: OffsetExpression | number; limit?: LimitExpression | number; From f4274277e1ec642894858dc95ff3c0d1dd04281b Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Wed, 17 May 2023 10:59:18 -0400 Subject: [PATCH 20/20] LINT: no-shadow --- .../src/edgeql-js/generateObjectTypes.ts | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/generate/src/edgeql-js/generateObjectTypes.ts b/packages/generate/src/edgeql-js/generateObjectTypes.ts index 809fd67cd..303505dc0 100644 --- a/packages/generate/src/edgeql-js/generateObjectTypes.ts +++ b/packages/generate/src/edgeql-js/generateObjectTypes.ts @@ -381,17 +381,17 @@ export const generateObjectTypes = (params: GeneratorParams) => { const baseTypesUnion = type.bases.length ? frag`${joinFrags( type.bases.map((base) => { - function getRecursiveLinks(base: { + function getRecursiveLinks(b: { id: string; }): ($.introspect.Pointer | $.introspect.Backlink)[] { - const baseType = types.get(base.id) as $.introspect.ObjectType; + const { pointers, backlinks, backlink_stubs, bases } = types.get( + b.id + ) as $.introspect.ObjectType; return [ - ...baseType.pointers, - ...baseType.backlinks, - ...baseType.backlink_stubs, - ...(baseType.bases.length - ? baseType.bases.flatMap(getRecursiveLinks) - : []), + ...pointers, + ...backlinks, + ...backlink_stubs, + ...(bases.length ? bases.flatMap(getRecursiveLinks) : []), ]; } const baseType = types.get(base.id) as $.introspect.ObjectType; @@ -468,10 +468,10 @@ export const generateObjectTypes = (params: GeneratorParams) => { // Base types exclusives const bases = (function findRecursiveBases( - bases: readonly { id: string }[] + bs: readonly { id: string }[] ): IdentRef[] { return [ - ...bases + ...bs .map((b) => types.get(b.id) as $.introspect.ObjectType) .flatMap((b) => { if (b.bases.length) { @@ -514,25 +514,24 @@ export const generateObjectTypes = (params: GeneratorParams) => { type.is_abstract && !["std", "sys", "schema"].includes(splitName(type.name).mod) ) { - function findRecursiveSubtypes(type: { + const subtypes = (function findRecursiveSubtypes(sub: { id: string; }): $.introspect.ObjectType[] { - const subtypes: $.introspect.ObjectType[] = []; + const subs: $.introspect.ObjectType[] = []; for (const candidate of types.values()) { if ( candidate.kind === "object" && - candidate.bases.find((b) => b.id === type.id) + candidate.bases.find((b) => b.id === sub.id) ) { - subtypes.push(candidate); - subtypes.push(...findRecursiveSubtypes(candidate)); + subs.push(candidate); + subs.push(...findRecursiveSubtypes(candidate)); } } - return subtypes; - } - const subtypes = findRecursiveSubtypes(type).map((t) => getRef(t.name)); + return subs; + })(type); for (const sub of subtypes) { - body.writeln([t`| ${quote(sub.name)}`]); + body.writeln([t`| ${quote(getRef(sub.name).name)}`]); } } });