@@ -34,13 +34,38 @@ export interface SearchResult {
3434 content : string
3535 documentId : string
3636 chunkIndex : number
37+ // Text tags
3738 tag1 : string | null
3839 tag2 : string | null
3940 tag3 : string | null
4041 tag4 : string | null
4142 tag5 : string | null
4243 tag6 : string | null
4344 tag7 : string | null
45+ // Number tags
46+ number1 : number | null
47+ number2 : number | null
48+ number3 : number | null
49+ number4 : number | null
50+ number5 : number | null
51+ number6 : number | null
52+ number7 : number | null
53+ // Date tags
54+ date1 : Date | null
55+ date2 : Date | null
56+ date3 : Date | null
57+ date4 : Date | null
58+ date5 : Date | null
59+ date6 : Date | null
60+ date7 : Date | null
61+ // Boolean tags
62+ boolean1 : boolean | null
63+ boolean2 : boolean | null
64+ boolean3 : boolean | null
65+ boolean4 : boolean | null
66+ boolean5 : boolean | null
67+ boolean6 : boolean | null
68+ boolean7 : boolean | null
4469 distance : number
4570 knowledgeBaseId : string
4671}
@@ -56,36 +81,81 @@ export interface SearchParams {
5681// Use shared embedding utility
5782export { generateSearchEmbedding } from '@/lib/knowledge/embeddings'
5883
59- function getTagFilters ( filters : Record < string , string > , embedding : any ) {
84+ /** All valid tag slot keys */
85+ const TAG_SLOT_KEYS = [
86+ // Text tags
87+ 'tag1' , 'tag2' , 'tag3' , 'tag4' , 'tag5' , 'tag6' , 'tag7' ,
88+ // Number tags
89+ 'number1' , 'number2' , 'number3' , 'number4' , 'number5' , 'number6' , 'number7' ,
90+ // Date tags
91+ 'date1' , 'date2' , 'date3' , 'date4' , 'date5' , 'date6' , 'date7' ,
92+ // Boolean tags
93+ 'boolean1' , 'boolean2' , 'boolean3' , 'boolean4' , 'boolean5' , 'boolean6' , 'boolean7' ,
94+ ] as const
95+
96+ type TagSlotKey = ( typeof TAG_SLOT_KEYS ) [ number ]
97+
98+ function isTagSlotKey ( key : string ) : key is TagSlotKey {
99+ return TAG_SLOT_KEYS . includes ( key as TagSlotKey )
100+ }
101+
102+ function getTagFilters ( filters : Record < string , string > , embeddingTable : any ) {
60103 return Object . entries ( filters ) . map ( ( [ key , value ] ) => {
61104 // Handle OR logic within same tag
62105 const values = value . includes ( '|OR|' ) ? value . split ( '|OR|' ) : [ value ]
63106 logger . debug ( `[getTagFilters] Processing ${ key } ="${ value } " -> values:` , values )
64107
65- const getColumnForKey = ( key : string ) => {
66- switch ( key ) {
67- case 'tag1' :
68- return embedding . tag1
69- case 'tag2' :
70- return embedding . tag2
71- case 'tag3' :
72- return embedding . tag3
73- case 'tag4' :
74- return embedding . tag4
75- case 'tag5' :
76- return embedding . tag5
77- case 'tag6' :
78- return embedding . tag6
79- case 'tag7' :
80- return embedding . tag7
81- default :
82- return null
108+ // Check if the key is a valid tag slot
109+ if ( ! isTagSlotKey ( key ) ) {
110+ logger . debug ( `[getTagFilters] Unknown tag slot key: ${ key } ` )
111+ return sql `1=1` // No-op for unknown keys
112+ }
113+
114+ const column = embeddingTable [ key ]
115+ if ( ! column ) return sql `1=1` // No-op if column doesn't exist
116+
117+ // Determine if this is a text, number, date, or boolean column
118+ const isTextTag = key . startsWith ( 'tag' )
119+ const isNumberTag = key . startsWith ( 'number' )
120+ const isDateTag = key . startsWith ( 'date' )
121+ const isBooleanTag = key . startsWith ( 'boolean' )
122+
123+ if ( isBooleanTag ) {
124+ // Boolean comparison
125+ const boolValue = values [ 0 ] . toLowerCase ( ) === 'true'
126+ logger . debug ( `[getTagFilters] Boolean filter: ${ key } = ${ boolValue } ` )
127+ return sql `${ column } = ${ boolValue } `
128+ }
129+
130+ if ( isNumberTag ) {
131+ // Number comparison - for simple equality
132+ const numValue = parseFloat ( values [ 0 ] )
133+ if ( values . length === 1 ) {
134+ logger . debug ( `[getTagFilters] Number filter: ${ key } = ${ numValue } ` )
135+ return sql `${ column } = ${ numValue } `
83136 }
137+ // Multiple values - OR logic
138+ const numValues = values . map ( ( v ) => parseFloat ( v ) )
139+ logger . debug ( `[getTagFilters] OR number filter: ${ key } IN (${ numValues . join ( ', ' ) } )` )
140+ const orConditions = numValues . map ( ( v ) => sql `${ column } = ${ v } ` )
141+ return sql `(${ sql . join ( orConditions , sql ` OR ` ) } )`
84142 }
85143
86- const column = getColumnForKey ( key )
87- if ( ! column ) return sql `1=1` // No-op for unknown keys
144+ if ( isDateTag ) {
145+ // Date comparison - for simple equality
146+ const dateValue = new Date ( values [ 0 ] )
147+ if ( values . length === 1 ) {
148+ logger . debug ( `[getTagFilters] Date filter: ${ key } = ${ dateValue . toISOString ( ) } ` )
149+ return sql `${ column } = ${ dateValue } `
150+ }
151+ // Multiple values - OR logic
152+ const dateValues = values . map ( ( v ) => new Date ( v ) )
153+ logger . debug ( `[getTagFilters] OR date filter: ${ key } IN (${ dateValues . map ( ( d ) => d . toISOString ( ) ) . join ( ', ' ) } )` )
154+ const orConditions = dateValues . map ( ( v ) => sql `${ column } = ${ v } ` )
155+ return sql `(${ sql . join ( orConditions , sql ` OR ` ) } )`
156+ }
88157
158+ // Text tag - case-insensitive comparison
89159 if ( values . length === 1 ) {
90160 // Single value - simple equality
91161 logger . debug ( `[getTagFilters] Single value filter: ${ key } = ${ values [ 0 ] } ` )
0 commit comments