diff --git a/package.json b/package.json index 89f7b7e..9bb4a85 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "scripts": { "build": "tsup ./src/index.ts", "tsc": "tsc", - "test": "vitest" + "test": "vitest --typecheck --watch false && pnpm test:integration", + "test:watch": "vitest --typecheck", + "test:integration": "vitest --config vitest.integration.config.mts" }, "license": "MIT", "devDependencies": { diff --git a/src/queryBuilders/getItemQueryBuilder.integration.test.ts b/src/queryBuilders/getItemQueryBuilder.integration.test.ts index 59db2e0..48223e9 100644 --- a/src/queryBuilders/getItemQueryBuilder.integration.test.ts +++ b/src/queryBuilders/getItemQueryBuilder.integration.test.ts @@ -1,4 +1,3 @@ -import { beforeAll, describe, expect, it } from "vitest"; import { DDB, TEST_DATA } from "../../test/testFixture"; import { getDDBClientFor, startDDBTestContainer } from "../../test/testUtil"; import { Tsynamo } from "./../index"; diff --git a/src/queryBuilders/queryQueryBuilder.integration.test.ts b/src/queryBuilders/queryQueryBuilder.integration.test.ts index a34dde1..c460647 100644 --- a/src/queryBuilders/queryQueryBuilder.integration.test.ts +++ b/src/queryBuilders/queryQueryBuilder.integration.test.ts @@ -1,4 +1,3 @@ -import { beforeAll, describe, expect, it } from "vitest"; import { DDB, TEST_DATA } from "../../test/testFixture"; import { getDDBClientFor, startDDBTestContainer } from "../../test/testUtil"; import { Tsynamo } from "./../index"; diff --git a/src/typeHelpers.test-d.ts b/src/typeHelpers.test-d.ts new file mode 100644 index 0000000..9c87799 --- /dev/null +++ b/src/typeHelpers.test-d.ts @@ -0,0 +1,133 @@ +import { SelectAttributes, type ObjectFullPaths } from "./typeHelpers"; + +describe("typeHelpers typecheck", () => { + it("ObjectFullPaths typecheck", () => { + type empty = ObjectFullPaths<{}>; + expectTypeOf().toEqualTypeOf(); + + type simpleObject = ObjectFullPaths<{ key: string; anotherKey: number }>; + expectTypeOf().toEqualTypeOf<"key" | "anotherKey">(); + + type nestedObject = ObjectFullPaths<{ key: { nested: string } }>; + expectTypeOf().toEqualTypeOf<"key" | "key.nested">(); + + type deepNested = ObjectFullPaths<{ + key: { n: { nn: { nnn: { nnnn: string } } } }; + }>; + expectTypeOf().toEqualTypeOf< + "key" | "key.n" | "key.n.nn" | "key.n.nn.nnn" | "key.n.nn.nnn.nnnn" + >(); + + type array = ObjectFullPaths<{ array: string[] }>; + expectTypeOf().toEqualTypeOf<"array" | `array[${number}]`>(); + + type arrayWObject = ObjectFullPaths<{ + cats: { name: string; age: number }[]; + }>; + expectTypeOf().toEqualTypeOf< + | "cats" + | `cats[${number}]` + | `cats[${number}].name` + | `cats[${number}].age` + >(); + + type arrayWArray = ObjectFullPaths<{ + house: { cats: { name: string; age: number }[] }[]; + }>; + expectTypeOf().toEqualTypeOf< + | "house" + | `house[${number}]` + | `house[${number}].cats` + | `house[${number}].cats[${number}]` + | `house[${number}].cats[${number}].name` + | `house[${number}].cats[${number}].age` + >(); + + type tuple = ObjectFullPaths<{ + tuple: [string, number]; + }>; + expectTypeOf().toEqualTypeOf<"tuple" | "tuple[0]" | "tuple[1]">(); + + type tupleWObject = ObjectFullPaths<{ + tuple: [{ left: boolean }, { right: boolean }]; + }>; + expectTypeOf().toEqualTypeOf< + "tuple" | "tuple[0]" | "tuple[1]" | "tuple[0].left" | "tuple[1].right" + >(); + + type tupleWArrayOrTuple = ObjectFullPaths<{ + tuple: [{ left: boolean[] }, { right: [boolean] }]; + }>; + expectTypeOf().toEqualTypeOf< + | "tuple" + | "tuple[0]" + | "tuple[1]" + | "tuple[0].left" + | "tuple[1].right" + | `tuple[0].left[${number}]` + | "tuple[1].right[0]" + >(); + + // TODO ObjectFullPaths doesnt work with multi-dimensional arrays yet + }); + + it("SelectAttributes typecheck", () => { + interface Table { + key: number; + otherKey: string; + obj: { + nestedKey: boolean; + anotherNestedKey: true; + }; + tuple: [{ kissa: "koira" }, number]; + cats: { + name: string; + age: number; + }[]; + } + + type selectKey = SelectAttributes; + expectTypeOf().toEqualTypeOf<{ + key: number; + }>(); + type selectObjectKey = SelectAttributes; + expectTypeOf().toEqualTypeOf<{ + key: number; + obj: { + nestedKey: boolean; + anotherNestedKey: true; + }; + }>(); + + type selectAll = SelectAttributes< + Table, + ["key", "otherKey", "cats", "obj", "tuple"] + >; + expectTypeOf().toEqualTypeOf(); + + type selectNested = SelectAttributes; + expectTypeOf().toEqualTypeOf<{ + key: number; + obj: { + nestedKey: boolean; + }; + }>(); + + type selectTuple1 = SelectAttributes; + expectTypeOf().toEqualTypeOf<{ + key: number; + tuple: { + 0: { + kissa: "koira"; + }; + }; + }>(); + + type selectTuple2 = SelectAttributes; + // TODO Fix this =( + // expectTypeOf().toEqualTypeOf<{ + // key: number; + // tuple: { 0: number }; + // }>(); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index d3981be..12074fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { "extends": "@tsconfig/node20/tsconfig.json", - "exclude": ["node_modules"] + "exclude": ["node_modules"], + "compilerOptions": { "types": ["vitest/globals"] } } \ No newline at end of file diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 0000000..7fc9d62 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,19 @@ +import { defineConfig } from "vitest/config"; +import path from "path"; + +export default defineConfig({ + test: { + globals: true, + exclude: [ + "**/node_modules/**", + "**/build/**", + "**/*.integration.test.ts/**", + ], + hookTimeout: 30000, + }, + resolve: { + alias: { + "@shared": path.resolve(__dirname, "../../shared"), + }, + }, +}); diff --git a/vitest.config.ts b/vitest.integration.config.mts similarity index 100% rename from vitest.config.ts rename to vitest.integration.config.mts