From ca99dc663872d8a2052691354f1db4a7f2d16e49 Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 08:58:53 +0700 Subject: [PATCH 1/6] fix: with validator problem --- packages/core/src/utils.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index af5d9cdf..08ab576b 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,7 +1,7 @@ import type { Column, TableRelationalConfig } from 'drizzle-orm' import { is, Table } from 'drizzle-orm' import type { IsNever, Simplify, ValueOf } from 'type-fest' -import type { ZodError, ZodObject, ZodOptional, ZodType } from 'zod' +import type { ZodIssue, ZodObject, ZodOptional, ZodType } from 'zod' import type { ApiHttpStatus, @@ -125,14 +125,16 @@ export async function validateRequestBody< TApiRouteSchema extends ApiRouteSchema = any, TContext extends Record = Record, >(schema: TApiRouteSchema, payload: ApiRouteHandlerPayloadWithContext) { - let zodErrors: Partial> | undefined + let zodErrors: + | Partial> + | undefined if (schema.query) { const err = await schema.query.safeParseAsync((payload as any).query) if (!err.success) { zodErrors = { ...zodErrors, - query: err.error, + query: err.error.issues, } } } @@ -142,7 +144,7 @@ export async function validateRequestBody< if (!err.success) { zodErrors = { ...zodErrors, - pathParams: err.error, + pathParams: err.error.issues, } } } @@ -152,7 +154,7 @@ export async function validateRequestBody< if (!err.success) { zodErrors = { ...zodErrors, - headers: err.error, + headers: err.error.issues, } } } @@ -162,7 +164,7 @@ export async function validateRequestBody< if (!err.success) { zodErrors = { ...zodErrors, - body: err.error, + body: err.error.issues, } } } From 8435674d41a12461e57ffc7e407476cecb511408 Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 10:39:46 +0700 Subject: [PATCH 2/6] fix: extra query not working --- packages/core/src/builder.handler.ts | 26 ++++---------- packages/core/src/builder.ts | 2 +- packages/core/src/utils.ts | 52 +++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/packages/core/src/builder.handler.ts b/packages/core/src/builder.handler.ts index 3ba0bb8a..6081bad6 100644 --- a/packages/core/src/builder.handler.ts +++ b/packages/core/src/builder.handler.ts @@ -7,7 +7,6 @@ import { Many, One, or, - sql, type TableRelationalConfig, } from 'drizzle-orm' import type { NodePgQueryResultHKT } from 'drizzle-orm/node-postgres' @@ -42,25 +41,18 @@ export function createDefaultApiHandlers< schema: Record fields: TFields tableTsKey: string - identiferColumn: string + identifierColumn: string tableNamesMap: Record tables: Record }): CollectionAdminApi { - const { fields, tableTsKey, tableNamesMap, tables, schema, identiferColumn } = args + const { fields, tableTsKey, tableNamesMap, tables, schema, identifierColumn } = args const tableRelationalConfig = tables[tableTsKey] const primaryKeyColumn = getPrimaryColumn(tableRelationalConfig) - const identifierKeyColumn = tableRelationalConfig.columns[identiferColumn] + const identifierKeyColumn = tableRelationalConfig.columns[identifierColumn] const tableName = tableRelationalConfig.tsName const tableSchema = getTableFromSchema(schema, tableTsKey) - const queryPayload = createDrizzleQuery(fields) - - const extrasQuery = { - extras: { - __pk: sql`${primaryKeyColumn}`.as('__pk'), - __id: sql`${identifierKeyColumn}`.as('__id'), - }, - } + const queryPayload = createDrizzleQuery(fields, identifierColumn) const findOne: ApiFindOneHandler = async (args) => { const db = args.context.db @@ -68,7 +60,6 @@ export function createDefaultApiHandlers< const result = await query.findFirst({ ...queryPayload, - ...extrasQuery, where: eq(primaryKeyColumn, args.id), }) if (!result) { @@ -94,7 +85,6 @@ export function createDefaultApiHandlers< const result = await query.findMany({ ...queryPayload, - ...extrasQuery, limit: args.limit, offset: args.offset, orderBy: orderBy @@ -136,7 +126,6 @@ export function createDefaultApiHandlers< const result = await query.findFirst({ ...queryPayload, - ...extrasQuery, where: eq(primaryKeyColumn, pk), }) @@ -165,7 +154,6 @@ export function createDefaultApiHandlers< const pk = await apiHandler.update(args.id, tx, args.data) const result = await query.findFirst({ ...queryPayload, - ...extrasQuery, where: eq(primaryKeyColumn, pk), }) @@ -574,11 +562,11 @@ function mapResultToFields(fields: Fields, result: Record): Re const value = result[field._.relationTsName] if (!value) return [] - const primaryColumnTsName = field._.primaryColumnTsName if (Array.isArray(value)) { const values = value.map((v) => ({ ...mapResultToFields(field.fields, v), - __pk: v[primaryColumnTsName], + __pk: v['__pk'], + __id: v['__id'], })) return [[field.fieldName, values]] } @@ -586,7 +574,7 @@ function mapResultToFields(fields: Fields, result: Record): Re return [ [ field.fieldName, - { ...mapResultToFields(field.fields, value), __pk: value[primaryColumnTsName] }, + { ...mapResultToFields(field.fields, value), __pk: value['__pk'], __id: value['__id'] }, ], ] } diff --git a/packages/core/src/builder.ts b/packages/core/src/builder.ts index 92b7d6da..ca7c9a75 100644 --- a/packages/core/src/builder.ts +++ b/packages/core/src/builder.ts @@ -82,7 +82,7 @@ export class Builder< const defaultHandlers = createDefaultApiHandlers({ schema: this.config.schema, fields: config.fields, - identiferColumn: config.identifierColumn as string, + identifierColumn: config.identifierColumn as string, tableTsKey: tableTsName, tables: this.tableRelationalConfigByTableTsName, tableNamesMap: this.tableTsNameByTableDbName, diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 08ab576b..6b397dae 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,5 +1,5 @@ -import type { Column, TableRelationalConfig } from 'drizzle-orm' -import { is, Table } from 'drizzle-orm' +import type { Column, SQL, TableRelationalConfig } from 'drizzle-orm' +import { is, sql, Table } from 'drizzle-orm' import type { IsNever, Simplify, ValueOf } from 'type-fest' import type { ZodIssue, ZodObject, ZodOptional, ZodType } from 'zod' @@ -9,7 +9,14 @@ import type { ApiRouteHandlerPayloadWithContext, ApiRouteSchema, } from './endpoint' -import type { Field, FieldRelation, Fields, FieldsInitial, FieldsWithFieldName } from './field' +import type { + Field, + FieldMetadataColumns, + FieldRelation, + Fields, + FieldsInitial, + FieldsWithFieldName, +} from './field' export function isRelationField(field: Field): field is FieldRelation { return field._.source === 'relation' @@ -74,7 +81,43 @@ export function getTableFromSchema(schema: Record, tableTsName: return schema[tableTsName] } -export function createDrizzleQuery(fields: Fields): Record { +const getExtraField = (fields: Fields, identifierColumn?: string) => { + const firstColumn = Object.values(fields).find((field) => field._.source === 'column') + ?._ as FieldMetadataColumns + + if (!firstColumn) { + throw new Error('No column fields found in the provided fields') + } + + const extraWith: [string, SQL.Aliased][] = [] + + const table = firstColumn.column.table + const tableColumns = Object.values(table) + const primaryKeyColumn = tableColumns.find((col) => col.primary) + + extraWith.push(['__pk', sql`${primaryKeyColumn}`.as('__pk') as SQL.Aliased]) + + if (identifierColumn) { + const identifierKeyColumn = tableColumns.find((col) => col.name === identifierColumn) + + if (!identifierKeyColumn) { + throw new Error(`Identifier column ${identifierColumn} not found in table ${table._.name}`) + } + + if (!primaryKeyColumn) { + throw new Error(`Primary key column not found in table ${table._.name}`) + } + + extraWith.push(['__id', sql`${identifierKeyColumn}`.as('__id') as SQL.Aliased]) + } + + return Object.fromEntries(extraWith) +} + +export function createDrizzleQuery( + fields: Fields, + identifierColumn?: string +): Record { const queryColumns = Object.fromEntries( Object.values(fields).flatMap((field) => { if (field._.source !== 'column') return [] @@ -94,6 +137,7 @@ export function createDrizzleQuery(fields: Fields): Record { return { columns: queryColumns, with: queryWith, + extras: getExtraField(fields, identifierColumn), } } From 5a5c79fd8eb2eafabed03af21bc7f12582e766eb Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 10:45:26 +0700 Subject: [PATCH 3/6] chore: add changeset --- .changeset/blue-ghosts-rush.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/blue-ghosts-rush.md diff --git a/.changeset/blue-ghosts-rush.md b/.changeset/blue-ghosts-rush.md new file mode 100644 index 00000000..4d4eb65d --- /dev/null +++ b/.changeset/blue-ghosts-rush.md @@ -0,0 +1,6 @@ +--- +'@kivotos/core': patch +--- + +[[DRIZZ-86] Embed __pk to relation field](https://app.plane.so/softnetics/browse/DRIZZ-86/) +[[DRIZZ-85] withValidator not working properly due to wrong response](https://app.plane.so/softnetics/browse/DRIZZ-85/) From c50b1c1cfed5cd82911de8c8537304b7f49b0210 Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 11:50:59 +0700 Subject: [PATCH 4/6] fix: missing issues usage in response --- packages/core/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 6b397dae..48c742e0 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -263,7 +263,7 @@ export function withValidator< status: 500, body: { error: 'Response validation failed', - details: validationError, + details: validationError.issues, }, } } From 107afd64d605b87ee329feba63af0329b1863f22 Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 13:18:50 +0700 Subject: [PATCH 5/6] perf: optimize get identifier column --- packages/core/src/builder.handler.ts | 2 +- packages/core/src/utils.ts | 42 ++++++++-------------------- 2 files changed, 13 insertions(+), 31 deletions(-) diff --git a/packages/core/src/builder.handler.ts b/packages/core/src/builder.handler.ts index 6081bad6..6a8d83d5 100644 --- a/packages/core/src/builder.handler.ts +++ b/packages/core/src/builder.handler.ts @@ -52,7 +52,7 @@ export function createDefaultApiHandlers< const identifierKeyColumn = tableRelationalConfig.columns[identifierColumn] const tableName = tableRelationalConfig.tsName const tableSchema = getTableFromSchema(schema, tableTsKey) - const queryPayload = createDrizzleQuery(fields, identifierColumn) + const queryPayload = createDrizzleQuery(fields, tables, tableRelationalConfig, identifierColumn) const findOne: ApiFindOneHandler = async (args) => { const db = args.context.db diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 48c742e0..f7316ce6 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -9,14 +9,7 @@ import type { ApiRouteHandlerPayloadWithContext, ApiRouteSchema, } from './endpoint' -import type { - Field, - FieldMetadataColumns, - FieldRelation, - Fields, - FieldsInitial, - FieldsWithFieldName, -} from './field' +import type { Field, FieldRelation, Fields, FieldsInitial, FieldsWithFieldName } from './field' export function isRelationField(field: Field): field is FieldRelation { return field._.source === 'relation' @@ -81,32 +74,15 @@ export function getTableFromSchema(schema: Record, tableTsName: return schema[tableTsName] } -const getExtraField = (fields: Fields, identifierColumn?: string) => { - const firstColumn = Object.values(fields).find((field) => field._.source === 'column') - ?._ as FieldMetadataColumns - - if (!firstColumn) { - throw new Error('No column fields found in the provided fields') - } - +const getExtraField = (tableRelational: TableRelationalConfig, identifierColumn?: string) => { const extraWith: [string, SQL.Aliased][] = [] - const table = firstColumn.column.table - const tableColumns = Object.values(table) - const primaryKeyColumn = tableColumns.find((col) => col.primary) + const primaryKeyColumn = tableRelational.primaryKey[0] extraWith.push(['__pk', sql`${primaryKeyColumn}`.as('__pk') as SQL.Aliased]) if (identifierColumn) { - const identifierKeyColumn = tableColumns.find((col) => col.name === identifierColumn) - - if (!identifierKeyColumn) { - throw new Error(`Identifier column ${identifierColumn} not found in table ${table._.name}`) - } - - if (!primaryKeyColumn) { - throw new Error(`Primary key column not found in table ${table._.name}`) - } + const identifierKeyColumn = tableRelational.columns[identifierColumn] extraWith.push(['__id', sql`${identifierKeyColumn}`.as('__id') as SQL.Aliased]) } @@ -116,6 +92,8 @@ const getExtraField = (fields: Fields, identifierColumn?: string) => { export function createDrizzleQuery( fields: Fields, + table: Record, + tableRelationalConfig: TableRelationalConfig, identifierColumn?: string ): Record { const queryColumns = Object.fromEntries( @@ -129,15 +107,19 @@ export function createDrizzleQuery( Object.values(fields).flatMap((field) => { if (!isRelationField(field)) return [] const relationName = field._.relation.fieldName + const referencedTableName = field._.relation.referencedTableName + console.log('Referenced table name: ', referencedTableName, table[referencedTableName]) - return [[relationName, createDrizzleQuery(field.fields) as any]] + return [ + [relationName, createDrizzleQuery(field.fields, table, table[referencedTableName]) as any], + ] }) ) return { columns: queryColumns, with: queryWith, - extras: getExtraField(fields, identifierColumn), + extras: getExtraField(tableRelationalConfig, identifierColumn), } } From f949ca3268bf7d00c33bf637780af0b14bf0851c Mon Sep 17 00:00:00 2001 From: miello Date: Fri, 30 May 2025 13:20:09 +0700 Subject: [PATCH 6/6] refactor: remove console log --- packages/core/src/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index f7316ce6..cebde50a 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -108,7 +108,6 @@ export function createDrizzleQuery( if (!isRelationField(field)) return [] const relationName = field._.relation.fieldName const referencedTableName = field._.relation.referencedTableName - console.log('Referenced table name: ', referencedTableName, table[referencedTableName]) return [ [relationName, createDrizzleQuery(field.fields, table, table[referencedTableName]) as any],