@@ -9,6 +9,7 @@ import type {
9
9
PostgresView ,
10
10
} from '../../lib/index.js'
11
11
import type { GeneratorMetadata } from '../../lib/generators.js'
12
+ import { PostgresForeignTable } from '../../lib/types.js'
12
13
13
14
type Operation = 'Select' | 'Insert' | 'Update'
14
15
export type AccessControl = 'internal' | 'public' | 'private' | 'package'
@@ -57,7 +58,7 @@ function pgEnumToSwiftEnum(pgEnum: PostgresType): SwiftEnum {
57
58
}
58
59
59
60
function pgTypeToSwiftStruct (
60
- table : PostgresTable | PostgresView | PostgresMaterializedView ,
61
+ table : PostgresTable | PostgresForeignTable | PostgresView | PostgresMaterializedView ,
61
62
columns : PostgresColumn [ ] | undefined ,
62
63
operation : Operation ,
63
64
{
@@ -205,75 +206,80 @@ function generateStruct(
205
206
export const apply = async ( {
206
207
schemas,
207
208
tables,
209
+ foreignTables,
208
210
views,
209
211
materializedViews,
210
212
columns,
211
213
types,
212
214
accessControl,
213
215
} : GeneratorMetadata & SwiftGeneratorOptions ) : Promise < string > => {
214
- const columnsByTableId = columns
215
- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
216
- . reduce (
217
- ( acc , curr ) => {
218
- acc [ curr . table_id ] ??= [ ]
219
- acc [ curr . table_id ] . push ( curr )
220
- return acc
221
- } ,
222
- { } as Record < string , PostgresColumn [ ] >
223
- )
224
-
225
- const compositeTypes = types . filter ( ( type ) => type . attributes . length > 0 )
226
- const enums = types
227
- . filter ( ( type ) => type . enums . length > 0 )
228
- . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
229
-
230
- const swiftEnums = enums . map ( ( enum_ ) => {
231
- return { schema : enum_ . schema , enum_ : pgEnumToSwiftEnum ( enum_ ) }
232
- } )
233
-
234
- const swiftStructForTables = tables . flatMap ( ( table ) =>
235
- ( [ 'Select' , 'Insert' , 'Update' ] as Operation [ ] ) . map ( ( operation ) =>
236
- pgTypeToSwiftStruct ( table , columnsByTableId [ table . id ] , operation , { types, views, tables } )
237
- )
238
- )
239
-
240
- const swiftStructForViews = views . map ( ( view ) =>
241
- pgTypeToSwiftStruct ( view , columnsByTableId [ view . id ] , 'Select' , { types, views, tables } )
216
+ const columnsByTableId = Object . fromEntries < PostgresColumn [ ] > (
217
+ [ ...tables , ...foreignTables , ...views , ...materializedViews ] . map ( ( t ) => [ t . id , [ ] ] )
242
218
)
243
219
244
- const swiftStructForMaterializedViews = materializedViews . map ( ( materializedView ) =>
245
- pgTypeToSwiftStruct ( materializedView , columnsByTableId [ materializedView . id ] , 'Select' , {
246
- types,
247
- views,
248
- tables,
249
- } )
250
- )
251
-
252
- const swiftStructForCompositeTypes = compositeTypes . map ( ( type ) =>
253
- pgCompositeTypeToSwiftStruct ( type , { types, views, tables } )
254
- )
220
+ columns
221
+ . filter ( ( c ) => c . table_id in columnsByTableId )
222
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
223
+ . forEach ( ( c ) => columnsByTableId [ c . table_id ] . push ( c ) )
255
224
256
225
let output = [
257
226
'import Foundation' ,
258
227
'import Supabase' ,
259
228
'' ,
260
- ...schemas . flatMap ( ( schema ) => [
261
- `${ accessControl } enum ${ formatForSwiftSchemaName ( schema . name ) } {` ,
262
- ...swiftEnums . flatMap ( ( { enum_ } ) => generateEnum ( enum_ , { accessControl, level : 1 } ) ) ,
263
- ...swiftStructForTables . flatMap ( ( struct ) =>
264
- generateStruct ( struct , { accessControl, level : 1 } )
265
- ) ,
266
- ...swiftStructForViews . flatMap ( ( struct ) =>
267
- generateStruct ( struct , { accessControl, level : 1 } )
268
- ) ,
269
- ...swiftStructForMaterializedViews . flatMap ( ( struct ) =>
270
- generateStruct ( struct , { accessControl, level : 1 } )
271
- ) ,
272
- ...swiftStructForCompositeTypes . flatMap ( ( struct ) =>
273
- generateStruct ( struct , { accessControl, level : 1 } )
274
- ) ,
275
- '}' ,
276
- ] ) ,
229
+ ...schemas
230
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
231
+ . flatMap ( ( schema ) => {
232
+ const schemaTables = [ ...tables , ...foreignTables ]
233
+ . filter ( ( table ) => table . schema === schema . name )
234
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
235
+
236
+ const schemaViews = [ ...views , ...materializedViews ]
237
+ . filter ( ( table ) => table . schema === schema . name )
238
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
239
+
240
+ const schemaEnums = types
241
+ . filter ( ( type ) => type . schema === schema . name && type . enums . length > 0 )
242
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
243
+
244
+ const schemaCompositeTypes = types
245
+ . filter ( ( type ) => type . schema === schema . name && type . attributes . length > 0 )
246
+ . sort ( ( { name : a } , { name : b } ) => a . localeCompare ( b ) )
247
+
248
+ return [
249
+ `${ accessControl } enum ${ formatForSwiftSchemaName ( schema . name ) } {` ,
250
+ ...schemaEnums . flatMap ( ( enum_ ) =>
251
+ generateEnum ( pgEnumToSwiftEnum ( enum_ ) , { accessControl, level : 1 } )
252
+ ) ,
253
+ ...schemaTables . flatMap ( ( table ) =>
254
+ ( [ 'Select' , 'Insert' , 'Update' ] as Operation [ ] )
255
+ . map ( ( operation ) =>
256
+ pgTypeToSwiftStruct ( table , columnsByTableId [ table . id ] , operation , {
257
+ types,
258
+ views,
259
+ tables,
260
+ } )
261
+ )
262
+ . flatMap ( ( struct ) => generateStruct ( struct , { accessControl, level : 1 } ) )
263
+ ) ,
264
+ ...schemaViews . flatMap ( ( view ) =>
265
+ generateStruct (
266
+ pgTypeToSwiftStruct ( view , columnsByTableId [ view . id ] , 'Select' , {
267
+ types,
268
+ views,
269
+ tables,
270
+ } ) ,
271
+ { accessControl, level : 1 }
272
+ )
273
+ ) ,
274
+ ...schemaCompositeTypes . flatMap ( ( type ) =>
275
+ generateStruct ( pgCompositeTypeToSwiftStruct ( type , { types, views, tables } ) , {
276
+ accessControl,
277
+ level : 1 ,
278
+ } )
279
+ ) ,
280
+ '}' ,
281
+ ]
282
+ } ) ,
277
283
]
278
284
279
285
return output . join ( '\n' )
@@ -360,15 +366,34 @@ function ident(level: number, options: { width: number } = { width: 2 }): string
360
366
* formatForSwiftTypeName('pokemon_center') // PokemonCenter
361
367
* formatForSwiftTypeName('victory-road') // VictoryRoad
362
368
* formatForSwiftTypeName('pokemon league') // PokemonLeague
369
+ * formatForSwiftTypeName('_key_id_context') // _KeyIdContext
363
370
* ```
364
371
*/
365
372
function formatForSwiftTypeName ( name : string ) : string {
366
- return name
367
- . split ( / [ ^ a - z A - Z 0 - 9 ] / )
368
- . map ( ( word ) => `${ word [ 0 ] . toUpperCase ( ) } ${ word . slice ( 1 ) } ` )
369
- . join ( '' )
373
+ // Preserve the initial underscore if it exists
374
+ let prefix = ''
375
+ if ( name . startsWith ( '_' ) ) {
376
+ prefix = '_'
377
+ name = name . slice ( 1 ) // Remove the initial underscore for processing
378
+ }
379
+
380
+ return (
381
+ prefix +
382
+ name
383
+ . split ( / [ ^ a - z A - Z 0 - 9 ] + / )
384
+ . map ( ( word ) => {
385
+ if ( word ) {
386
+ return `${ word [ 0 ] . toUpperCase ( ) } ${ word . slice ( 1 ) } `
387
+ } else {
388
+ return ''
389
+ }
390
+ } )
391
+ . join ( '' )
392
+ )
370
393
}
371
394
395
+ const SWIFT_KEYWORDS = [ 'in' , 'default' ]
396
+
372
397
/**
373
398
* Converts a Postgres name to pascalCase.
374
399
*
@@ -381,11 +406,13 @@ function formatForSwiftTypeName(name: string): string {
381
406
* ```
382
407
*/
383
408
function formatForSwiftPropertyName ( name : string ) : string {
384
- return name
409
+ const propertyName = name
385
410
. split ( / [ ^ a - z A - Z 0 - 9 ] / )
386
411
. map ( ( word , index ) => {
387
412
const lowerWord = word . toLowerCase ( )
388
413
return index !== 0 ? lowerWord . charAt ( 0 ) . toUpperCase ( ) + lowerWord . slice ( 1 ) : lowerWord
389
414
} )
390
415
. join ( '' )
416
+
417
+ return SWIFT_KEYWORDS . includes ( propertyName ) ? `\`${ propertyName } \`` : propertyName
391
418
}
0 commit comments