@@ -123,6 +123,7 @@ pub(crate) const BLOB_DESCRIPTOR_FIELD_OPTION: &str = "blob-descriptor-field";
123123pub ( crate ) const BLOB_VIEW_FIELD_OPTION : & str = "blob-view-field" ;
124124pub const BLOB_VIEW_RESOLVE_ENABLED_OPTION : & str = "blob-view.resolve.enabled" ;
125125const PK_VECTOR_INDEX_COLUMNS_OPTION : & str = "pk-vector.index.columns" ;
126+ const PK_FULL_TEXT_INDEX_COLUMNS_OPTION : & str = "pk-full-text.index.columns" ;
126127
127128/// Merge engine for primary-key tables.
128129///
@@ -1198,6 +1199,23 @@ impl<'a> CoreOptions<'a> {
11981199 crate :: vindex:: pkvector:: metric:: VectorSearchMetric :: parse ( & raw ) ?;
11991200 Ok ( raw)
12001201 }
1202+
1203+ /// True when the PK full-text index column option key is present (any value).
1204+ pub fn primary_key_full_text_index_enabled ( & self ) -> bool {
1205+ self . options . contains_key ( PK_FULL_TEXT_INDEX_COLUMNS_OPTION )
1206+ }
1207+
1208+ /// Configured PK full-text index columns: split on ',' and trim each token,
1209+ /// mirroring Java `split(",",-1).map(trim)`. Blank tokens are PRESERVED (do NOT
1210+ /// filter them) so parsing matches Java exactly; `[]` only when the key is
1211+ /// absent. Never returns a `Result`, never errors (do not copy the fail-loud
1212+ /// shape of `primary_key_vector_index_columns`).
1213+ pub fn primary_key_full_text_index_columns ( & self ) -> Vec < String > {
1214+ match self . options . get ( PK_FULL_TEXT_INDEX_COLUMNS_OPTION ) {
1215+ None => Vec :: new ( ) ,
1216+ Some ( raw) => raw. split ( ',' ) . map ( |c| c. trim ( ) . to_string ( ) ) . collect ( ) ,
1217+ }
1218+ }
12011219}
12021220
12031221/// Parse a memory size string to bytes using binary (1024-based) semantics.
@@ -2147,4 +2165,56 @@ mod tests {
21472165 . primary_key_vector_index_type( "e" )
21482166 . is_err( ) ) ;
21492167 }
2168+
2169+ #[ test]
2170+ fn test_pk_full_text_index_absent_is_disabled_and_empty ( ) {
2171+ let opts = HashMap :: new ( ) ;
2172+ let co = CoreOptions :: new ( & opts) ;
2173+ assert ! ( !co. primary_key_full_text_index_enabled( ) ) ;
2174+ assert_eq ! (
2175+ co. primary_key_full_text_index_columns( ) ,
2176+ Vec :: <String >:: new( )
2177+ ) ;
2178+ }
2179+
2180+ #[ test]
2181+ fn test_pk_full_text_index_columns_split_and_trim ( ) {
2182+ let opts = HashMap :: from ( [ (
2183+ "pk-full-text.index.columns" . to_string ( ) ,
2184+ "a, b ,c" . to_string ( ) ,
2185+ ) ] ) ;
2186+ let co = CoreOptions :: new ( & opts) ;
2187+ assert ! ( co. primary_key_full_text_index_enabled( ) ) ;
2188+ assert_eq ! (
2189+ co. primary_key_full_text_index_columns( ) ,
2190+ vec![ "a" . to_string( ) , "b" . to_string( ) , "c" . to_string( ) ]
2191+ ) ;
2192+ }
2193+
2194+ #[ test]
2195+ fn test_pk_full_text_index_columns_preserve_blank_tokens ( ) {
2196+ // Java `split(",",-1).map(trim)` keeps empty tokens, so "a,,b" yields
2197+ // three columns with a blank in the middle.
2198+ let opts = HashMap :: from ( [ ( "pk-full-text.index.columns" . to_string ( ) , "a,,b" . to_string ( ) ) ] ) ;
2199+ let co = CoreOptions :: new ( & opts) ;
2200+ assert ! ( co. primary_key_full_text_index_enabled( ) ) ;
2201+ assert_eq ! (
2202+ co. primary_key_full_text_index_columns( ) ,
2203+ vec![ "a" . to_string( ) , "" . to_string( ) , "b" . to_string( ) ]
2204+ ) ;
2205+ }
2206+
2207+ #[ test]
2208+ fn test_pk_full_text_index_blank_value_is_enabled_but_empty_no_error ( ) {
2209+ // key present but only blanks: enabled (key exists), NO error (lenient,
2210+ // unlike vector). Blank tokens are PRESERVED to match Java's
2211+ // `split(",",-1).map(trim)`, so " , " yields two empty tokens (NOT []).
2212+ let opts = HashMap :: from ( [ ( "pk-full-text.index.columns" . to_string ( ) , " , " . to_string ( ) ) ] ) ;
2213+ let co = CoreOptions :: new ( & opts) ;
2214+ assert ! ( co. primary_key_full_text_index_enabled( ) ) ;
2215+ assert_eq ! (
2216+ co. primary_key_full_text_index_columns( ) ,
2217+ vec![ "" . to_string( ) , "" . to_string( ) ]
2218+ ) ;
2219+ }
21502220}
0 commit comments