@@ -1077,10 +1077,38 @@ function getFilterTypeForField(fieldType: string, isArray = false): string {
10771077}
10781078
10791079/**
1080- * Build properties for a table filter interface
1080+ * Build properties for a table filter interface.
1081+ *
1082+ * When typeRegistry is available, uses the schema's filter input type as
1083+ * the sole source of truth — this captures plugin-injected filter fields
1084+ * (e.g., bm25Body, tsvTsv, trgmName, vectorEmbedding, geom) that are not
1085+ * present on the entity type itself. Same pattern as buildOrderByValues().
10811086 */
1082- function buildTableFilterProperties ( table : Table ) : InterfaceProperty [ ] {
1087+ function buildTableFilterProperties (
1088+ table : Table ,
1089+ typeRegistry ?: TypeRegistry ,
1090+ ) : InterfaceProperty [ ] {
10831091 const filterName = getFilterTypeName ( table ) ;
1092+
1093+ // When the schema's filter type is available, use it as the source of truth
1094+ if ( typeRegistry ) {
1095+ const filterType = typeRegistry . get ( filterName ) ;
1096+ if ( filterType ?. kind === 'INPUT_OBJECT' && filterType . inputFields ) {
1097+ const properties : InterfaceProperty [ ] = [ ] ;
1098+ for ( const field of filterType . inputFields ) {
1099+ const tsType = typeRefToTs ( field . type ) ;
1100+ properties . push ( {
1101+ name : field . name ,
1102+ type : tsType ,
1103+ optional : true ,
1104+ description : stripSmartComments ( field . description , true ) ,
1105+ } ) ;
1106+ }
1107+ return properties ;
1108+ }
1109+ }
1110+
1111+ // Fallback: derive from table fields when schema filter type is not available
10841112 const properties : InterfaceProperty [ ] = [ ] ;
10851113
10861114 for ( const field of table . fields ) {
@@ -1105,13 +1133,19 @@ function buildTableFilterProperties(table: Table): InterfaceProperty[] {
11051133/**
11061134 * Generate table filter type statements
11071135 */
1108- function generateTableFilterTypes ( tables : Table [ ] ) : t . Statement [ ] {
1136+ function generateTableFilterTypes (
1137+ tables : Table [ ] ,
1138+ typeRegistry ?: TypeRegistry ,
1139+ ) : t . Statement [ ] {
11091140 const statements : t . Statement [ ] = [ ] ;
11101141
11111142 for ( const table of tables ) {
11121143 const filterName = getFilterTypeName ( table ) ;
11131144 statements . push (
1114- createExportedInterface ( filterName , buildTableFilterProperties ( table ) ) ,
1145+ createExportedInterface (
1146+ filterName ,
1147+ buildTableFilterProperties ( table , typeRegistry ) ,
1148+ ) ,
11151149 ) ;
11161150 }
11171151
@@ -1956,6 +1990,54 @@ function generateConnectionFieldsMap(
19561990// Plugin-Injected Type Collector
19571991// ============================================================================
19581992
1993+ /**
1994+ * Collect extra input type names referenced by plugin-injected filter fields.
1995+ *
1996+ * When the schema's filter type is used as source of truth, plugin-injected
1997+ * fields reference custom filter types (e.g., Bm25BodyFilter, TsvectorFilter,
1998+ * GeometryFilter) that also need to be generated. This function discovers
1999+ * those types by comparing the schema's filter type fields against the
2000+ * standard scalar filter types.
2001+ */
2002+ function collectFilterExtraInputTypes (
2003+ tables : Table [ ] ,
2004+ typeRegistry : TypeRegistry ,
2005+ ) : Set < string > {
2006+ const extraTypes = new Set < string > ( ) ;
2007+
2008+ for ( const table of tables ) {
2009+ const filterTypeName = getFilterTypeName ( table ) ;
2010+ const filterType = typeRegistry . get ( filterTypeName ) ;
2011+ if (
2012+ ! filterType ||
2013+ filterType . kind !== 'INPUT_OBJECT' ||
2014+ ! filterType . inputFields
2015+ ) {
2016+ continue ;
2017+ }
2018+
2019+ const tableFieldNames = new Set (
2020+ table . fields
2021+ . filter ( ( f ) => ! isRelationField ( f . name , table ) )
2022+ . map ( ( f ) => f . name ) ,
2023+ ) ;
2024+
2025+ for ( const field of filterType . inputFields ) {
2026+ // Skip standard column-derived fields and logical operators
2027+ if ( tableFieldNames . has ( field . name ) ) continue ;
2028+ if ( [ 'and' , 'or' , 'not' ] . includes ( field . name ) ) continue ;
2029+
2030+ // Collect the base type name of this extra field
2031+ const baseName = getTypeBaseName ( field . type ) ;
2032+ if ( baseName && ! SCALAR_NAMES . has ( baseName ) ) {
2033+ extraTypes . add ( baseName ) ;
2034+ }
2035+ }
2036+ }
2037+
2038+ return extraTypes ;
2039+ }
2040+
19592041/**
19602042 * Collect extra input type names referenced by plugin-injected condition fields.
19612043 *
@@ -2048,7 +2130,9 @@ export function generateInputTypesFile(
20482130 statements . push ( ...generateEntitySelectTypes ( tablesList , tableByName ) ) ;
20492131
20502132 // 4. Table filter types
2051- statements . push ( ...generateTableFilterTypes ( tablesList ) ) ;
2133+ // Pass typeRegistry to use schema's filter type as source of truth,
2134+ // capturing plugin-injected filter fields (e.g., bm25, tsvector, trgm, vector, geom)
2135+ statements . push ( ...generateTableFilterTypes ( tablesList , typeRegistry ) ) ;
20522136
20532137 // 4b. Table condition types (simple equality filter)
20542138 // Pass typeRegistry to merge plugin-injected condition fields
@@ -2071,8 +2155,17 @@ export function generateInputTypesFile(
20712155 statements . push ( ...generateConnectionFieldsMap ( tablesList , tableByName ) ) ;
20722156
20732157 // 7. Custom input types from TypeRegistry
2074- // Also include any extra types referenced by plugin-injected condition fields
2158+ // Also include any extra types referenced by plugin-injected filter/ condition fields
20752159 const mergedUsedInputTypes = new Set ( usedInputTypes ) ;
2160+ if ( hasTables ) {
2161+ const filterExtraTypes = collectFilterExtraInputTypes (
2162+ tablesList ,
2163+ typeRegistry ,
2164+ ) ;
2165+ for ( const typeName of filterExtraTypes ) {
2166+ mergedUsedInputTypes . add ( typeName ) ;
2167+ }
2168+ }
20762169 if ( hasTables && conditionEnabled ) {
20772170 const conditionExtraTypes = collectConditionExtraInputTypes (
20782171 tablesList ,
0 commit comments