Skip to content

Commit 89b5561

Browse files
committed
chore: only single loop for types
1 parent 96c8ac7 commit 89b5561

File tree

1 file changed

+45
-51
lines changed

1 file changed

+45
-51
lines changed

src/server/templates/typescript.ts

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,6 @@ export const apply = async ({
3636
postgrestVersion?: string
3737
}): Promise<string> => {
3838
schemas.sort((a, b) => a.name.localeCompare(b.name))
39-
40-
const columnsByTableId: Record<number, PostgresColumn[]> = {}
41-
const tablesNamesByTableId: Record<number, string> = {}
42-
const relationTypeByIds = new Map<number, PostgresType>()
43-
// group types by id for quicker lookup
44-
const typesById = types.reduce(
45-
(acc, type) => {
46-
acc[type.id] = type
47-
return acc
48-
},
49-
{} as Record<number, (typeof types)[number]>
50-
)
51-
const tablesLike = [...tables, ...foreignTables, ...views, ...materializedViews]
52-
53-
for (const tableLike of tablesLike) {
54-
columnsByTableId[tableLike.id] = []
55-
tablesNamesByTableId[tableLike.id] = tableLike.name
56-
}
57-
for (const column of columns) {
58-
if (column.table_id in columnsByTableId) {
59-
columnsByTableId[column.table_id].push(column)
60-
}
61-
}
62-
for (const tableId in columnsByTableId) {
63-
columnsByTableId[tableId].sort((a, b) => a.name.localeCompare(b.name))
64-
}
65-
6639
const introspectionBySchema = Object.fromEntries<{
6740
tables: {
6841
table: Pick<PostgresTable, 'id' | 'name' | 'schema' | 'columns'>
@@ -81,6 +54,41 @@ export const apply = async ({
8154
{ tables: [], views: [], functions: [], enums: [], compositeTypes: [] },
8255
])
8356
)
57+
const columnsByTableId: Record<number, PostgresColumn[]> = {}
58+
const tablesNamesByTableId: Record<number, string> = {}
59+
const relationTypeByIds = new Map<number, (typeof types)[number]>()
60+
// group types by id for quicker lookup
61+
const typesById = new Map<number, (typeof types)[number]>()
62+
const tablesLike = [...tables, ...foreignTables, ...views, ...materializedViews]
63+
64+
for (const tableLike of tablesLike) {
65+
columnsByTableId[tableLike.id] = []
66+
tablesNamesByTableId[tableLike.id] = tableLike.name
67+
}
68+
for (const column of columns) {
69+
if (column.table_id in columnsByTableId) {
70+
columnsByTableId[column.table_id].push(column)
71+
}
72+
}
73+
for (const tableId in columnsByTableId) {
74+
columnsByTableId[tableId].sort((a, b) => a.name.localeCompare(b.name))
75+
}
76+
77+
for (const type of types) {
78+
typesById.set(type.id, type)
79+
// Save all the types that are relation types for quicker lookup
80+
if (type.type_relation_id) {
81+
relationTypeByIds.set(type.id, type)
82+
}
83+
if (type.schema in introspectionBySchema) {
84+
if (type.enums.length > 0) {
85+
introspectionBySchema[type.schema].enums.push(type)
86+
}
87+
if (type.attributes.length > 0) {
88+
introspectionBySchema[type.schema].compositeTypes.push(type)
89+
}
90+
}
91+
}
8492

8593
function getRelationships(
8694
object: { schema: string; name: string },
@@ -148,20 +156,6 @@ export const apply = async ({
148156
})
149157
}
150158
}
151-
for (const type of types) {
152-
// Save all the types that are relation types for quicker lookup
153-
if (type.type_relation_id) {
154-
relationTypeByIds.set(type.id, type)
155-
}
156-
if (type.schema in introspectionBySchema) {
157-
if (type.enums.length > 0) {
158-
introspectionBySchema[type.schema].enums.push(type)
159-
}
160-
if (type.attributes.length > 0) {
161-
introspectionBySchema[type.schema].compositeTypes.push(type)
162-
}
163-
}
164-
}
165159
// Helper function to get table/view name from relation id
166160
const getTableNameFromRelationId = (
167161
relationId: number | null,
@@ -235,15 +229,15 @@ export const apply = async ({
235229
// Case 1: Standard embedded function with proper setof detection
236230
if (returnsSetOfTable && returnTableName) {
237231
setofOptionsInfo = `SetofOptions: {
238-
from: ${JSON.stringify(typesById[fn.args[0].type_id].format)}
232+
from: ${JSON.stringify(typesById.get(fn.args[0].type_id)?.format)}
239233
to: ${JSON.stringify(returnTableName)}
240234
isOneToOne: ${Boolean(!returnsMultipleRows)}
241235
isSetofReturn: true
242236
}`
243237
}
244238
// Case 2: Handle RETURNS table-name those are always a one to one relationship
245239
else if (returnTableName && !returnsSetOfTable) {
246-
const sourceTable = typesById[fn.args[0].type_id].format
240+
const sourceTable = typesById.get(fn.args[0].type_id)?.format
247241
const targetTable = returnTableName
248242
setofOptionsInfo = `SetofOptions: {
249243
from: ${JSON.stringify(sourceTable)}
@@ -273,7 +267,7 @@ export const apply = async ({
273267
const tableArgs = fn.args.filter(({ mode }) => mode === 'table')
274268
if (tableArgs.length > 0) {
275269
const argsNameAndType = tableArgs.map(({ name, type_id }) => {
276-
const type = typesById[type_id]
270+
const type = typesById.get(type_id)
277271
let tsType = 'unknown'
278272
if (type) {
279273
tsType = pgTypeToTsType(schema, type.name, {
@@ -324,7 +318,7 @@ export const apply = async ({
324318
}
325319

326320
// Case 3: returns base/array/composite/enum type.
327-
const type = typesById[fn.return_type_id]
321+
const type = typesById.get(fn.return_type_id)
328322
if (type) {
329323
return pgTypeToTsType(schema, type.name, {
330324
types,
@@ -369,7 +363,7 @@ export const apply = async ({
369363

370364
if (conflictingFns.length > 0) {
371365
const conflictingFn = conflictingFns[0]
372-
const returnTypeName = typesById[conflictingFn.fn.return_type_id]?.name || 'unknown'
366+
const returnTypeName = typesById.get(conflictingFn.fn.return_type_id)?.name || 'unknown'
373367
return `Could not choose the best candidate function between: ${schema.name}.${fn.name}(), ${schema.name}.${fn.name}( => ${returnTypeName}). Try renaming the parameters or the function itself in the database so function overloading can be resolved`
374368
}
375369
}
@@ -395,7 +389,7 @@ export const apply = async ({
395389
})
396390
.map((f) => {
397391
const args = f.inArgs
398-
return `${schema.name}.${fn.name}(${args.map((a) => `${a.name || ''} => ${typesById[a.type_id]?.name || 'unknown'}`).join(', ')})`
392+
return `${schema.name}.${fn.name}(${args.map((a) => `${a.name || ''} => ${typesById.get(a.type_id)?.name || 'unknown'}`).join(', ')})`
399393
})
400394
.join(', ')
401395

@@ -420,7 +414,7 @@ export const apply = async ({
420414
if (conflictError) {
421415
if (inArgs.length > 0) {
422416
const argsNameAndType = inArgs.map(({ name, type_id, has_default }) => {
423-
const type = typesById[type_id]
417+
const type = typesById.get(type_id)
424418
let tsType = 'unknown'
425419
if (type) {
426420
tsType = pgTypeToTsType(schema, type.name, {
@@ -439,7 +433,7 @@ export const apply = async ({
439433
// Special case for computed fields returning scalars functions
440434
if (inArgs.length > 0) {
441435
const argsNameAndType = inArgs.map(({ name, type_id, has_default }) => {
442-
const type = typesById[type_id]
436+
const type = typesById.get(type_id)
443437
let tsType = 'unknown'
444438
if (type) {
445439
tsType = pgTypeToTsType(schema, type.name, {
@@ -456,7 +450,7 @@ export const apply = async ({
456450
returnType = `{ error: true } & ${JSON.stringify(`the function ${schema.name}.${fn.name} with parameter or with a single unnamed json/jsonb parameter, but no matches were found in the schema cache`)}`
457451
} else if (inArgs.length > 0) {
458452
const argsNameAndType = inArgs.map(({ name, type_id, has_default }) => {
459-
const type = typesById[type_id]
453+
const type = typesById.get(type_id)
460454
let tsType = 'unknown'
461455
if (type) {
462456
tsType = pgTypeToTsType(schema, type.name, {
@@ -708,7 +702,7 @@ export type Database = {
708702
({ name, attributes }) =>
709703
`${JSON.stringify(name)}: {
710704
${attributes.map(({ name, type_id }) => {
711-
const type = typesById[type_id]
705+
const type = typesById.get(type_id)
712706
let tsType = 'unknown'
713707
if (type) {
714708
tsType = `${pgTypeToTsType(schema, type.name, {

0 commit comments

Comments
 (0)