diff --git a/app/__test__/data/data-query-impl.spec.ts b/app/__test__/data/data-query-impl.spec.ts index d5217df..a2fcdff 100644 --- a/app/__test__/data/data-query-impl.spec.ts +++ b/app/__test__/data/data-query-impl.spec.ts @@ -1,16 +1,15 @@ import { describe, expect, test } from "bun:test"; -import type { QueryObject } from "ufo"; -import { WhereBuilder, type WhereQuery } from "../../src/data/entities/query/WhereBuilder"; +import { Value } from "../../src/core/utils"; +import { WhereBuilder, type WhereQuery, querySchema } from "../../src/data"; import { getDummyConnection } from "./helper"; -const t = "t"; describe("data-query-impl", () => { function qb() { const c = getDummyConnection(); const kysely = c.dummyConnection.kysely; - return kysely.selectFrom(t).selectAll(); + return kysely.selectFrom("t").selectAll(); } - function compile(q: QueryObject) { + function compile(q: WhereQuery) { const { sql, parameters } = WhereBuilder.addClause(qb(), q).compile(); return { sql, parameters }; } @@ -90,3 +89,20 @@ describe("data-query-impl", () => { } }); }); + +describe("data-query-impl: Typebox", () => { + test("sort", async () => { + const decode = (input: any, expected: any) => { + const result = Value.Decode(querySchema, input); + expect(result.sort).toEqual(expected); + }; + const _dflt = { by: "id", dir: "asc" }; + + decode({ sort: "" }, _dflt); + decode({ sort: "name" }, { by: "name", dir: "asc" }); + decode({ sort: "-name" }, { by: "name", dir: "desc" }); + decode({ sort: "-posts.name" }, { by: "posts.name", dir: "desc" }); + decode({ sort: "-1name" }, _dflt); + decode({ sort: { by: "name", dir: "desc" } }, { by: "name", dir: "desc" }); + }); +}); diff --git a/app/src/data/server/data-query-impl.ts b/app/src/data/server/data-query-impl.ts index a85ac77..5bf18d9 100644 --- a/app/src/data/server/data-query-impl.ts +++ b/app/src/data/server/data-query-impl.ts @@ -6,7 +6,6 @@ import { Type, Value } from "core/utils"; -import type { Simplify } from "type-fest"; import { WhereBuilder } from "../entities"; const NumberOrString = (options: SchemaOptions = {}) => @@ -19,17 +18,25 @@ const limit = NumberOrString({ default: 10 }); const offset = NumberOrString({ default: 0 }); // @todo: allow "id" and "-id" +const sort_default = { by: "id", dir: "asc" }; const sort = Type.Transform( Type.Union( [Type.String(), Type.Object({ by: Type.String(), dir: StringEnum(["asc", "desc"]) })], { - default: { by: "id", dir: "asc" } + default: sort_default } ) ) .Decode((value) => { if (typeof value === "string") { - return JSON.parse(value); + if (/^-?[a-zA-Z_][a-zA-Z0-9_.]*$/.test(value)) { + const dir = value[0] === "-" ? "desc" : "asc"; + return { by: dir === "desc" ? value.slice(1) : value, dir }; + } else if (/^{.*}$/.test(value)) { + return JSON.parse(value); + } + + return sort_default; } return value; })