Skip to content

Commit 42cae58

Browse files
authored
eng-1754-Clean up the typing of validators/processors for better type inference (#1033)
* Clean up the typing of validators/processors for better type inference * lint * crud * Correction for processSupabaseError
1 parent c9aff7a commit 42cae58

9 files changed

Lines changed: 165 additions & 138 deletions

File tree

apps/website/app/api/supabase/agent-identifier/route.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NextResponse, NextRequest } from "next/server";
22

33
import { createClient } from "~/utils/supabase/server";
4-
import { getOrCreateEntity, ItemValidator } from "~/utils/supabase/dbUtils";
4+
import { getOrCreateEntity } from "~/utils/supabase/dbUtils";
55
import { asPostgrestFailure } from "@repo/database/lib/contextFunctions";
66
import {
77
createApiResponse,
@@ -11,25 +11,26 @@ import {
1111
import { type TablesInsert, Constants } from "@repo/database/dbTypes";
1212

1313
type AgentIdentifierDataInput = TablesInsert<"AgentIdentifier">;
14+
// eslint-disable-next-line @typescript-eslint/naming-convention
1415
const { AgentIdentifierType } = Constants.public.Enums;
1516

16-
const agentIdentifierValidator: ItemValidator<AgentIdentifierDataInput> = (
17-
agent_identifier: any,
18-
) => {
17+
// ItemValidator<"AgentIdentifier">
18+
const agentIdentifierValidator = (
19+
// eslint-disable-next-line @typescript-eslint/naming-convention
20+
agent_identifier: AgentIdentifierDataInput,
21+
): string | null => {
1922
if (!agent_identifier || typeof agent_identifier !== "object")
2023
return "Invalid request body: expected a JSON object.";
24+
// eslint-disable-next-line @typescript-eslint/naming-convention
2125
const { identifier_type, account_id, value, trusted } = agent_identifier;
2226

2327
if (!AgentIdentifierType.includes(identifier_type))
2428
return "Invalid identifier_type";
2529
if (!value || typeof value !== "string" || value.trim() === "")
2630
return "Missing or invalid value";
27-
if (!account_id || Number.isNaN(Number.parseInt(account_id, 10)))
31+
if (!account_id || typeof account_id !== "number" || Number.isNaN(account_id))
2832
return "Missing or invalid account_id";
29-
if (
30-
trusted !== undefined &&
31-
!["true", "false", true, false].includes(trusted)
32-
)
33+
if (trusted !== undefined && typeof trusted !== "boolean")
3334
return "if included, trusted should be a boolean";
3435

3536
const keys = ["identifier_type", "account_id", "value", "trusted"];
@@ -42,18 +43,16 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
4243
const supabasePromise = createClient();
4344

4445
try {
45-
const body = await request.json();
46+
const body = (await request.json()) as AgentIdentifierDataInput;
4647
const error = agentIdentifierValidator(body);
4748
if (error !== null)
4849
return createApiResponse(request, asPostgrestFailure(error, "invalid"));
4950

50-
body.account_id = Number.parseInt(body.account_id, 10);
51-
body.trusted = body.trusted === true || body.trusted === "true" || false;
5251
const supabase = await supabasePromise;
53-
const result = await getOrCreateEntity<"AgentIdentifier">({
52+
const result = await getOrCreateEntity({
5453
supabase,
5554
tableName: "AgentIdentifier",
56-
insertData: body as AgentIdentifierDataInput,
55+
insertData: body,
5756
uniqueOn: ["value", "identifier_type", "account_id"],
5857
});
5958

apps/website/app/api/supabase/content-embedding/batch/route.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {
88
handleRouteError,
99
defaultOptionsHandler,
1010
} from "~/utils/supabase/apiUtils";
11+
import { processAndInsertBatch } from "~/utils/supabase/dbUtils";
1112
import {
12-
processAndInsertBatch,
13+
type ContentEmbeddingVecTables,
14+
type ContentEmbeddingVecTablesInsert,
1315
KNOWN_EMBEDDING_TABLES,
14-
} from "~/utils/supabase/dbUtils";
15-
import {
16-
type ApiInputEmbeddingItem,
17-
type ApiOutputEmbeddingRecord,
1816
embeddingInputProcessing,
1917
embeddingOutputProcessing,
2018
} from "~/utils/supabase/validators";
@@ -23,12 +21,12 @@ const DEFAULT_MODEL = "openai_text_embedding_3_small_1536";
2321

2422
const batchInsertEmbeddingsProcess = async (
2523
supabase: Awaited<ReturnType<typeof createClient>>,
26-
embeddingItems: ApiInputEmbeddingItem[],
27-
): Promise<PostgrestResponse<ApiOutputEmbeddingRecord>> => {
24+
embeddingItems: ContentEmbeddingVecTablesInsert[],
25+
): Promise<PostgrestResponse<ContentEmbeddingVecTables>> => {
2826
// groupBy is node21 only, we are using 20. Group by model, by hand.
2927
// Note: This means that later index values may be totally wrong.
3028
// Note2: The key is a ModelName, but I cannot use an enum as a key.
31-
const byModel: { [key: string]: ApiInputEmbeddingItem[] } = {};
29+
const byModel: { [key: string]: ContentEmbeddingVecTablesInsert[] } = {};
3230
try {
3331
embeddingItems.reduce((acc, item) => {
3432
const model = item?.model || DEFAULT_MODEL;
@@ -45,7 +43,7 @@ const batchInsertEmbeddingsProcess = async (
4543
throw error;
4644
}
4745

48-
const globalResults: ApiOutputEmbeddingRecord[] = [];
46+
const globalResults: ContentEmbeddingVecTables[] = [];
4947
const partialErrors: string[] = [];
5048
let created = false,
5149
count = 0,
@@ -55,15 +53,11 @@ const batchInsertEmbeddingsProcess = async (
5553
if (embeddingItemsSet === undefined) continue;
5654
const tableData = KNOWN_EMBEDDING_TABLES[modelName];
5755
if (tableData === undefined) continue;
58-
const results = await processAndInsertBatch<
59-
// any ContentEmbedding table for type checking purposes only
60-
"ContentEmbedding_openai_text_embedding_3_small_1536",
61-
ApiInputEmbeddingItem,
62-
ApiOutputEmbeddingRecord
63-
>({
56+
const { tableName } = tableData;
57+
const results = await processAndInsertBatch({
6458
supabase,
6559
items: embeddingItemsSet,
66-
tableName: tableData.tableName,
60+
tableName,
6761
inputProcessor: embeddingInputProcessing,
6862
outputProcessor: embeddingOutputProcessing,
6963
});
@@ -108,7 +102,7 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
108102
const supabase = await createClient();
109103

110104
try {
111-
const body: ApiInputEmbeddingItem[] = await request.json();
105+
const body = (await request.json()) as ContentEmbeddingVecTablesInsert[];
112106
if (!Array.isArray(body)) {
113107
return createApiResponse(
114108
request,

apps/website/app/api/supabase/content-embedding/route.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import {
88
handleRouteError,
99
defaultOptionsHandler,
1010
} from "~/utils/supabase/apiUtils";
11+
import { getOrCreateEntity } from "~/utils/supabase/dbUtils";
1112
import {
12-
getOrCreateEntity,
1313
KNOWN_EMBEDDING_TABLES,
14-
} from "~/utils/supabase/dbUtils";
15-
import {
16-
ApiInputEmbeddingItem,
17-
ApiOutputEmbeddingRecord,
14+
ContentEmbeddingVecTablesInsert,
15+
ContentEmbeddingVecTables,
1816
embeddingInputProcessing,
1917
embeddingOutputProcessing,
2018
} from "~/utils/supabase/validators";
@@ -23,9 +21,11 @@ const DEFAULT_MODEL = "openai_text_embedding_3_small_1536";
2321

2422
const processAndCreateEmbedding = async (
2523
supabasePromise: ReturnType<typeof createClient>,
26-
data: ApiInputEmbeddingItem,
27-
): Promise<PostgrestSingleResponse<ApiOutputEmbeddingRecord>> => {
28-
const { valid, error, processedItem } = embeddingInputProcessing(data);
24+
data: ContentEmbeddingVecTablesInsert,
25+
): Promise<PostgrestSingleResponse<ContentEmbeddingVecTables>> => {
26+
const processed = embeddingInputProcessing(data);
27+
if (!processed) return asPostgrestFailure("Could not process input", "valid");
28+
const { valid, error, processedItem } = processed;
2929
if (
3030
!valid ||
3131
processedItem === undefined ||
@@ -78,7 +78,7 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
7878
const supabasePromise = createClient();
7979

8080
try {
81-
const body: ApiInputEmbeddingItem = await request.json();
81+
const body = (await request.json()) as ContentEmbeddingVecTablesInsert;
8282
const result = await processAndCreateEmbedding(supabasePromise, body);
8383
return createApiResponse(request, result);
8484
} catch (e: unknown) {

apps/website/app/api/supabase/content/batch/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const batchInsertContentProcess = async (
1818
supabase: Awaited<ReturnType<typeof createClient>>,
1919
contentItems: ContentDataInput[],
2020
): Promise<PostgrestResponse<ContentRecord>> => {
21-
return validateAndInsertBatch<"Content">({
21+
return validateAndInsertBatch({
2222
supabase,
2323
tableName: "Content",
2424
items: contentItems,

apps/website/app/api/supabase/content/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const processAndUpsertContentEntry = async (
2727
// If no solid matchCriteria for a "get", getOrCreateEntity will likely proceed to "create".
2828
// If there are unique constraints other than (space_id, source_local_id), it will handle race conditions.
2929

30-
const result = await getOrCreateEntity<"Content">({
30+
const result = await getOrCreateEntity({
3131
supabase,
3232
tableName: "Content",
3333
insertData: data,

apps/website/app/api/supabase/document/route.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { NextResponse, NextRequest } from "next/server";
22
import type { PostgrestSingleResponse } from "@supabase/supabase-js";
33

44
import { createClient } from "~/utils/supabase/server";
5-
import { getOrCreateEntity, ItemValidator } from "~/utils/supabase/dbUtils";
5+
import { getOrCreateEntity } from "~/utils/supabase/dbUtils";
66
import { asPostgrestFailure } from "@repo/database/lib/contextFunctions";
77
import {
88
createApiResponse,
@@ -14,7 +14,8 @@ import type { Tables, TablesInsert } from "@repo/database/dbTypes";
1414
type DocumentDataInput = TablesInsert<"Document">;
1515
type DocumentRecord = Tables<"Document">;
1616

17-
const validateDocument: ItemValidator<DocumentDataInput> = (data) => {
17+
// ItemValidator<"Document">
18+
const validateDocument = (data: DocumentDataInput): string | null => {
1819
if (!data || typeof data !== "object")
1920
return "Invalid request body: expected a JSON object.";
2021
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -33,7 +34,7 @@ const createDocument = async (
3334
): Promise<PostgrestSingleResponse<DocumentRecord>> => {
3435
const supabase = await supabasePromise;
3536

36-
const result = await getOrCreateEntity<"Document">({
37+
const result = await getOrCreateEntity({
3738
supabase,
3839
tableName: "Document",
3940
insertData: data,
@@ -50,7 +51,7 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
5051
const supabasePromise = createClient();
5152

5253
try {
53-
const body: DocumentDataInput = await request.json();
54+
const body = (await request.json()) as DocumentDataInput;
5455
const error = validateDocument(body);
5556
if (error !== null)
5657
return createApiResponse(request, asPostgrestFailure(error, "invalid"));

apps/website/app/api/supabase/platform-account/route.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NextResponse, NextRequest } from "next/server";
22

33
import { createClient } from "~/utils/supabase/server";
4-
import { getOrCreateEntity, ItemValidator } from "~/utils/supabase/dbUtils";
4+
import { getOrCreateEntity } from "~/utils/supabase/dbUtils";
55
import { asPostgrestFailure } from "@repo/database/lib/contextFunctions";
66
import {
77
createApiResponse,
@@ -15,9 +15,8 @@ const { AgentType, Platform } = Constants.public.Enums;
1515

1616
type PlatformAccountDataInput = TablesInsert<"PlatformAccount">;
1717

18-
const accountValidator: ItemValidator<PlatformAccountDataInput> = (
19-
account: any,
20-
) => {
18+
// ItemValidator<"PlatformAccount">
19+
const accountValidator = (account: PlatformAccountDataInput): string | null => {
2120
if (!account || typeof account !== "object")
2221
return "Invalid request body: expected a JSON object.";
2322
/* eslint-disable @typescript-eslint/naming-convention */
@@ -84,16 +83,16 @@ export const POST = async (request: NextRequest): Promise<NextResponse> => {
8483
const supabasePromise = createClient();
8584

8685
try {
87-
const body = await request.json();
86+
const body = (await request.json()) as PlatformAccountDataInput;
8887
const error = accountValidator(body);
8988
if (error !== null)
9089
return createApiResponse(request, asPostgrestFailure(error, "invalid"));
9190

9291
const supabase = await supabasePromise;
93-
const result = await getOrCreateEntity<"PlatformAccount">({
92+
const result = await getOrCreateEntity({
9493
supabase,
9594
tableName: "PlatformAccount",
96-
insertData: body as PlatformAccountDataInput,
95+
insertData: body,
9796
uniqueOn: ["account_local_id", "platform"],
9897
});
9998

0 commit comments

Comments
 (0)