1- import type { GraphileConfig } from ' graphile-config' ;
1+ import type { GraphileConfig } from " graphile-config" ;
22import {
33 singularize ,
44 pluralize ,
77 distinctPluralize ,
88 fixCapitalisedPlural ,
99 camelize ,
10- } from ' inflekt' ;
10+ } from " inflekt" ;
1111
1212/**
1313 * Custom inflector plugin for Constructive using the inflekt library.
@@ -30,22 +30,22 @@ import {
3030 * Add your own mappings here as needed.
3131 */
3232const CUSTOM_OPPOSITES : Record < string , string > = {
33- parent : ' child' ,
34- child : ' parent' ,
35- author : ' authored' ,
36- editor : ' edited' ,
37- reviewer : ' reviewed' ,
38- owner : ' owned' ,
39- creator : ' created' ,
40- updater : ' updated' ,
33+ parent : " child" ,
34+ child : " parent" ,
35+ author : " authored" ,
36+ editor : " edited" ,
37+ reviewer : " reviewed" ,
38+ owner : " owned" ,
39+ creator : " created" ,
40+ updater : " updated" ,
4141} ;
4242
4343/**
4444 * Extract base name from attribute names like "author_id" -> "author"
4545 */
4646function getBaseName ( attributeName : string ) : string | null {
4747 const matches = attributeName . match (
48- / ^ ( .+ ?) ( _ r o w _ i d | _ i d | _ u u i d | _ f k | _ p k | R o w I d | I d | U u i d | U U I D | F k | P k ) $ /
48+ / ^ ( .+ ?) ( _ r o w _ i d | _ i d | _ u u i d | _ f k | _ p k | R o w I d | I d | U u i d | U U I D | F k | P k ) $ / ,
4949 ) ;
5050 if ( matches ) {
5151 return matches [ 1 ] ;
@@ -74,7 +74,7 @@ function getOppositeBaseName(baseName: string): string | null {
7474function arraysMatch < T > (
7575 array1 : readonly T [ ] ,
7676 array2 : readonly T [ ] ,
77- comparator : ( v1 : T , v2 : T ) => boolean = ( v1 , v2 ) => v1 === v2
77+ comparator : ( v1 : T , v2 : T ) => boolean = ( v1 , v2 ) => v1 === v2 ,
7878) : boolean {
7979 if ( array1 === array2 ) return true ;
8080 const l = array1 . length ;
@@ -86,8 +86,8 @@ function arraysMatch<T>(
8686}
8787
8888export const InflektPlugin : GraphileConfig . Plugin = {
89- name : ' InflektPlugin' ,
90- version : ' 1.0.0' ,
89+ name : " InflektPlugin" ,
90+ version : " 1.0.0" ,
9191
9292 inflection : {
9393 replace : {
@@ -126,7 +126,40 @@ export const InflektPlugin: GraphileConfig.Plugin = {
126126 * same name in different schemas. Use @name smart tags to disambiguate.
127127 */
128128 _schemaPrefix ( _previous , _options , _details ) {
129- return '' ;
129+ return "" ;
130+ } ,
131+
132+ /**
133+ * Restore PostGraphile's default schema prefix logic for functions.
134+ *
135+ * Our _schemaPrefix override returns '' for all schemas to give clean
136+ * table names. However, this strips prefixes from functions too, causing
137+ * resource naming collisions when a function and table share the same
138+ * base name across schemas (e.g., actions_public.table_grant() collides
139+ * with metaschema_public.table_grant table).
140+ *
141+ * Fix: bypass our _schemaPrefix override for functions and use
142+ * PostGraphile's default prefix logic instead.
143+ */
144+ functionResourceName ( _previous , options : any , details : any ) {
145+ const { serviceName, pgProc } = details ;
146+ const { tags } = pgProc . getTagsAndDescription ( ) ;
147+
148+ if ( typeof tags . name === "string" ) {
149+ return tags . name ;
150+ }
151+
152+ const pgNamespace = pgProc . getNamespace ( ) ;
153+
154+ if ( ! pgNamespace ) {
155+ return pgProc . proname ;
156+ }
157+
158+ const pgService = ( options . pgServices ?? [ ] ) . find ( ( db : any ) => db . name === serviceName ) ;
159+ const primarySchema = pgService ?. schemas ?. [ 0 ] ?? "public" ;
160+ const databasePrefix = serviceName === "main" ? "" : `${ serviceName } _` ;
161+ const schemaPrefix = pgNamespace . nspname === primarySchema ? "" : `${ pgNamespace . nspname } _` ;
162+ return `${ databasePrefix } ${ schemaPrefix } ${ pgProc . proname } ` ;
130163 } ,
131164
132165 /**
@@ -167,7 +200,10 @@ export const InflektPlugin: GraphileConfig.Plugin = {
167200 _attributeName (
168201 _previous ,
169202 _options ,
170- details : { attributeName : string ; codec : { attributes : Record < string , { extensions ?: { tags ?: { name ?: string } } } > } }
203+ details : {
204+ attributeName : string ;
205+ codec : { attributes : Record < string , { extensions ?: { tags ?: { name ?: string } } } > } ;
206+ } ,
171207 ) {
172208 const attribute = details . codec . attributes [ details . attributeName ] ;
173209 const name = attribute ?. extensions ?. tags ?. name || details . attributeName ;
@@ -211,7 +247,7 @@ export const InflektPlugin: GraphileConfig.Plugin = {
211247 */
212248 allRowsList ( _previous , _options , resource ) {
213249 const resourceName = this . _singularizedResourceName ( resource ) ;
214- return camelize ( distinctPluralize ( resourceName ) , true ) + ' List' ;
250+ return camelize ( distinctPluralize ( resourceName ) , true ) + " List" ;
215251 } ,
216252
217253 /**
@@ -220,7 +256,7 @@ export const InflektPlugin: GraphileConfig.Plugin = {
220256 singleRelation ( previous , _options , details ) {
221257 const { registry, codec, relationName } = details ;
222258 const relation = registry . pgRelations [ codec . name ] ?. [ relationName ] ;
223- if ( typeof relation . extensions ?. tags ?. fieldName === ' string' ) {
259+ if ( typeof relation . extensions ?. tags ?. fieldName === " string" ) {
224260 return relation . extensions . tags . fieldName ;
225261 }
226262
@@ -235,16 +271,10 @@ export const InflektPlugin: GraphileConfig.Plugin = {
235271
236272 // Fall back to the remote resource name
237273 const foreignPk = relation . remoteResource . uniques . find (
238- ( u : { isPrimary : boolean } ) => u . isPrimary
274+ ( u : { isPrimary : boolean } ) => u . isPrimary ,
239275 ) ;
240- if (
241- foreignPk &&
242- arraysMatch ( foreignPk . attributes , relation . remoteAttributes )
243- ) {
244- return camelize (
245- this . _singularizedCodecName ( relation . remoteResource . codec ) ,
246- true
247- ) ;
276+ if ( foreignPk && arraysMatch ( foreignPk . attributes , relation . remoteAttributes ) ) {
277+ return camelize ( this . _singularizedCodecName ( relation . remoteResource . codec ) , true ) ;
248278 }
249279 return previous ! ( details ) ;
250280 } ,
@@ -255,12 +285,10 @@ export const InflektPlugin: GraphileConfig.Plugin = {
255285 singleRelationBackwards ( previous , _options , details ) {
256286 const { registry, codec, relationName } = details ;
257287 const relation = registry . pgRelations [ codec . name ] ?. [ relationName ] ;
258- if (
259- typeof relation . extensions ?. tags ?. foreignSingleFieldName === 'string'
260- ) {
288+ if ( typeof relation . extensions ?. tags ?. foreignSingleFieldName === "string" ) {
261289 return relation . extensions . tags . foreignSingleFieldName ;
262290 }
263- if ( typeof relation . extensions ?. tags ?. foreignFieldName === ' string' ) {
291+ if ( typeof relation . extensions ?. tags ?. foreignFieldName === " string" ) {
264292 return relation . extensions . tags . foreignFieldName ;
265293 }
266294
@@ -273,14 +301,11 @@ export const InflektPlugin: GraphileConfig.Plugin = {
273301 if ( oppositeBaseName ) {
274302 return camelize (
275303 `${ oppositeBaseName } _${ this . _singularizedCodecName ( relation . remoteResource . codec ) } ` ,
276- true
304+ true ,
277305 ) ;
278306 }
279307 if ( baseNameMatches ( baseName , codec . name ) ) {
280- return camelize (
281- this . _singularizedCodecName ( relation . remoteResource . codec ) ,
282- true
283- ) ;
308+ return camelize ( this . _singularizedCodecName ( relation . remoteResource . codec ) , true ) ;
284309 }
285310 }
286311 }
@@ -295,7 +320,7 @@ export const InflektPlugin: GraphileConfig.Plugin = {
295320 const { registry, codec, relationName } = details ;
296321 const relation = registry . pgRelations [ codec . name ] ?. [ relationName ] ;
297322 const baseOverride = relation . extensions ?. tags . foreignFieldName ;
298- if ( typeof baseOverride === ' string' ) {
323+ if ( typeof baseOverride === " string" ) {
299324 return baseOverride ;
300325 }
301326
@@ -308,30 +333,24 @@ export const InflektPlugin: GraphileConfig.Plugin = {
308333 if ( oppositeBaseName ) {
309334 return camelize (
310335 `${ oppositeBaseName } _${ distinctPluralize ( this . _singularizedCodecName ( relation . remoteResource . codec ) ) } ` ,
311- true
336+ true ,
312337 ) ;
313338 }
314339 if ( baseNameMatches ( baseName , codec . name ) ) {
315340 return camelize (
316- distinctPluralize (
317- this . _singularizedCodecName ( relation . remoteResource . codec )
318- ) ,
319- true
341+ distinctPluralize ( this . _singularizedCodecName ( relation . remoteResource . codec ) ) ,
342+ true ,
320343 ) ;
321344 }
322345 }
323346 }
324347
325348 // Fall back to pluralized remote resource name
326- const pk = relation . remoteResource . uniques . find (
327- ( u : { isPrimary : boolean } ) => u . isPrimary
328- ) ;
349+ const pk = relation . remoteResource . uniques . find ( ( u : { isPrimary : boolean } ) => u . isPrimary ) ;
329350 if ( pk && arraysMatch ( pk . attributes , relation . remoteAttributes ) ) {
330351 return camelize (
331- distinctPluralize (
332- this . _singularizedCodecName ( relation . remoteResource . codec )
333- ) ,
334- true
352+ distinctPluralize ( this . _singularizedCodecName ( relation . remoteResource . codec ) ) ,
353+ true ,
335354 ) ;
336355 }
337356 return previous ! ( details ) ;
@@ -349,19 +368,17 @@ export const InflektPlugin: GraphileConfig.Plugin = {
349368 * - There are multiple many-to-many relations to the same target table
350369 */
351370 _manyToManyRelation ( previous , _options , details ) {
352- const { leftTable, rightTable, junctionTable, rightRelationName } =
353- details ;
371+ const { leftTable, rightTable, junctionTable, rightRelationName } = details ;
354372
355373 const junctionRightRelation = junctionTable . getRelation ( rightRelationName ) ;
356- const baseOverride =
357- junctionRightRelation . extensions ?. tags ?. manyToManyFieldName ;
358- if ( typeof baseOverride === 'string' ) {
374+ const baseOverride = junctionRightRelation . extensions ?. tags ?. manyToManyFieldName ;
375+ if ( typeof baseOverride === "string" ) {
359376 return baseOverride ;
360377 }
361378
362379 const simpleName = camelize (
363380 distinctPluralize ( this . _singularizedCodecName ( rightTable . codec ) ) ,
364- true
381+ true ,
365382 ) ;
366383
367384 const leftRelations = leftTable . getRelations ( ) ;
@@ -374,10 +391,7 @@ export const InflektPlugin: GraphileConfig.Plugin = {
374391 hasDirectRelation = true ;
375392 }
376393 }
377- if (
378- rel . isReferencee &&
379- rel . remoteResource ?. codec ?. name !== rightTable . codec . name
380- ) {
394+ if ( rel . isReferencee && rel . remoteResource ?. codec ?. name !== rightTable . codec . name ) {
381395 const junctionRelations = rel . remoteResource ?. getRelations ?.( ) || { } ;
382396 for ( const [ _jRelName , jRel ] of Object . entries ( junctionRelations ) ) {
383397 if (
@@ -402,7 +416,7 @@ export const InflektPlugin: GraphileConfig.Plugin = {
402416 */
403417 rowByUnique ( previous , _options , details ) {
404418 const { unique, resource } = details ;
405- if ( typeof unique . extensions ?. tags ?. fieldName === ' string' ) {
419+ if ( typeof unique . extensions ?. tags ?. fieldName === " string" ) {
406420 return unique . extensions ?. tags ?. fieldName ;
407421 }
408422 if ( unique . isPrimary ) {
@@ -416,14 +430,11 @@ export const InflektPlugin: GraphileConfig.Plugin = {
416430 */
417431 updateByKeysField ( previous , _options , details ) {
418432 const { resource, unique } = details ;
419- if ( typeof unique . extensions ?. tags . updateFieldName === ' string' ) {
433+ if ( typeof unique . extensions ?. tags . updateFieldName === " string" ) {
420434 return unique . extensions . tags . updateFieldName ;
421435 }
422436 if ( unique . isPrimary ) {
423- return camelize (
424- `update_${ this . _singularizedCodecName ( resource . codec ) } ` ,
425- true
426- ) ;
437+ return camelize ( `update_${ this . _singularizedCodecName ( resource . codec ) } ` , true ) ;
427438 }
428439 return previous ! ( details ) ;
429440 } ,
@@ -433,14 +444,11 @@ export const InflektPlugin: GraphileConfig.Plugin = {
433444 */
434445 deleteByKeysField ( previous , _options , details ) {
435446 const { resource, unique } = details ;
436- if ( typeof unique . extensions ?. tags . deleteFieldName === ' string' ) {
447+ if ( typeof unique . extensions ?. tags . deleteFieldName === " string" ) {
437448 return unique . extensions . tags . deleteFieldName ;
438449 }
439450 if ( unique . isPrimary ) {
440- return camelize (
441- `delete_${ this . _singularizedCodecName ( resource . codec ) } ` ,
442- true
443- ) ;
451+ return camelize ( `delete_${ this . _singularizedCodecName ( resource . codec ) } ` , true ) ;
444452 }
445453 return previous ! ( details ) ;
446454 } ,
0 commit comments