From 6026613d299889dc2b0d6483af82a45f5ad2ae43 Mon Sep 17 00:00:00 2001 From: dswbx Date: Tue, 7 Jan 2025 18:08:50 +0100 Subject: [PATCH 1/2] feat: allow data query to have single string as sort --- app/__test__/data/data-query-impl.spec.ts | 26 ++++++++++++++++++----- app/src/data/server/data-query-impl.ts | 13 +++++++++--- 2 files changed, 31 insertions(+), 8 deletions(-) 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; }) From aa86d545532f91a233c2b5a1531eb0157a7f0819 Mon Sep 17 00:00:00 2001 From: dswbx Date: Wed, 8 Jan 2025 10:16:41 +0100 Subject: [PATCH 2/2] clean up data controller --- app/src/data/api/DataController.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/app/src/data/api/DataController.ts b/app/src/data/api/DataController.ts index 68a5417..adf10a4 100644 --- a/app/src/data/api/DataController.ts +++ b/app/src/data/api/DataController.ts @@ -1,33 +1,25 @@ import { type ClassController, isDebug, tbValidator as tb } from "core"; -import { StringEnum, Type, objectCleanEmpty, objectTransform } from "core/utils"; +import { StringEnum, Type } from "core/utils"; import { DataPermissions, type EntityData, type EntityManager, - FieldClassMap, type MutatorResponse, - PrimaryField, type RepoQuery, type RepositoryResponse, - TextField, querySchema } from "data"; import { Hono } from "hono"; import type { Handler } from "hono/types"; import type { ModuleBuildContext } from "modules"; import * as SystemPermissions from "modules/permissions"; -import { type AppDataConfig, FIELDS } from "../data-schema"; +import type { AppDataConfig } from "../data-schema"; export class DataController implements ClassController { constructor( private readonly ctx: ModuleBuildContext, private readonly config: AppDataConfig - ) { - /*console.log( - "data controller", - this.em.entities.map((e) => e.name) - );*/ - } + ) {} get em(): EntityManager { return this.ctx.em;