@@ -110,6 +110,22 @@ const TIME_CONFIG = {
110110} as const ;
111111
112112export class ModelUsageStatsManager {
113+ /**
114+ * Build parameterized IN clause placeholders and params for ClickHouse queries.
115+ * Returns placeholders like ({val_0:String}, {val_1:String}, ...) and the corresponding params array.
116+ */
117+ private buildInClauseParams (
118+ values : string [ ] ,
119+ offset : number = 0
120+ ) : { placeholders : string ; params : string [ ] } {
121+ if ( values . length === 0 ) {
122+ return { placeholders : "('')" , params : [ ] } ;
123+ }
124+ const placeholders = values
125+ . map ( ( _ , i ) => `{val_${ offset + i } :String}` )
126+ . join ( ", " ) ;
127+ return { placeholders : `(${ placeholders } )` , params : [ ...values ] } ;
128+ }
113129 /**
114130 * Get model usage: top 9 models + "other" with time series and leaderboard.
115131 */
@@ -136,16 +152,15 @@ export class ModelUsageStatsManager {
136152
137153 const top9Data = top9Result . data ?? [ ] ;
138154 const top9Set = new Set ( top9Data . map ( ( r ) => r . model ) ) ;
139- const inClause = top9Data . length > 0
140- ? top9Data . map ( ( r ) => `'${ r . model } '` ) . join ( "," )
141- : "''" ;
155+ const { placeholders : modelInClause , params : modelParams } =
156+ this . buildInClauseParams ( top9Data . map ( ( r ) => r . model ) ) ;
142157
143158 // Step 2: Get "other" total + previous period data + time series (parallel)
144159 const otherQuery = `
145160 SELECT sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
146161 FROM request_stats
147162 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
148- AND model NOT IN ( ${ inClause } )
163+ AND model NOT IN ${ modelInClause }
149164 ` ;
150165
151166 const prevTop9Query = `
@@ -154,7 +169,7 @@ export class ModelUsageStatsManager {
154169 WHERE hour >= now() - ${ interval } - ${ interval }
155170 AND hour < now() - ${ interval }
156171 AND ${ BASE_WHERE_CLAUSE }
157- AND model IN ( ${ inClause } )
172+ AND model IN ${ modelInClause }
158173 GROUP BY model
159174 ` ;
160175
@@ -164,7 +179,7 @@ export class ModelUsageStatsManager {
164179 WHERE hour >= now() - ${ interval } - ${ interval }
165180 AND hour < now() - ${ interval }
166181 AND ${ BASE_WHERE_CLAUSE }
167- AND model NOT IN ( ${ inClause } )
182+ AND model NOT IN ${ modelInClause }
168183 ` ;
169184
170185 const timeSeriesQuery = `
@@ -179,9 +194,9 @@ export class ModelUsageStatsManager {
179194
180195 const [ otherResult , prevTop9Result , prevOtherResult , timeSeriesResult ] =
181196 await Promise . all ( [
182- clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , [ ] ) ,
183- clickhouseDb . dbQuery < { model : string ; total_tokens : number } > ( prevTop9Query , [ ] ) ,
184- clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , [ ] ) ,
197+ clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , modelParams ) ,
198+ clickhouseDb . dbQuery < { model : string ; total_tokens : number } > ( prevTop9Query , modelParams ) ,
199+ clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , modelParams ) ,
185200 clickhouseDb . dbQuery < { time_bucket : string ; model : string ; total_tokens : number } > ( timeSeriesQuery , [ ] ) ,
186201 ] ) ;
187202
@@ -424,15 +439,14 @@ export class ModelUsageStatsManager {
424439
425440 const top9Data = top9Result . data ?? [ ] ;
426441 const top9Set = new Set ( top9Data . map ( ( r ) => r . provider ) ) ;
427- const inClause = top9Data . length > 0
428- ? top9Data . map ( ( r ) => `'${ r . provider } '` ) . join ( "," )
429- : "''" ;
442+ const { placeholders : providerInClause , params : providerParams } =
443+ this . buildInClauseParams ( top9Data . map ( ( r ) => r . provider ) ) ;
430444
431445 const otherQuery = `
432446 SELECT sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
433447 FROM request_stats
434448 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
435- AND provider NOT IN ( ${ inClause } )
449+ AND provider NOT IN ${ providerInClause }
436450 ` ;
437451
438452 const prevTop9Query = `
@@ -441,7 +455,7 @@ export class ModelUsageStatsManager {
441455 WHERE hour >= now() - ${ interval } - ${ interval }
442456 AND hour < now() - ${ interval }
443457 AND ${ BASE_WHERE_CLAUSE }
444- AND provider IN ( ${ inClause } )
458+ AND provider IN ${ providerInClause }
445459 GROUP BY provider
446460 ` ;
447461
@@ -451,7 +465,7 @@ export class ModelUsageStatsManager {
451465 WHERE hour >= now() - ${ interval } - ${ interval }
452466 AND hour < now() - ${ interval }
453467 AND ${ BASE_WHERE_CLAUSE }
454- AND provider NOT IN ( ${ inClause } )
468+ AND provider NOT IN ${ providerInClause }
455469 ` ;
456470
457471 const timeSeriesQuery = `
@@ -466,9 +480,9 @@ export class ModelUsageStatsManager {
466480
467481 const [ otherResult , prevTop9Result , prevOtherResult , timeSeriesResult ] =
468482 await Promise . all ( [
469- clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , [ ] ) ,
470- clickhouseDb . dbQuery < { provider : string ; total_tokens : number } > ( prevTop9Query , [ ] ) ,
471- clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , [ ] ) ,
483+ clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , providerParams ) ,
484+ clickhouseDb . dbQuery < { provider : string ; total_tokens : number } > ( prevTop9Query , providerParams ) ,
485+ clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , providerParams ) ,
472486 clickhouseDb . dbQuery < { time_bucket : string ; provider : string ; total_tokens : number } > ( timeSeriesQuery , [ ] ) ,
473487 ] ) ;
474488
@@ -672,13 +686,15 @@ export class ModelUsageStatsManager {
672686 timeframe : StatsTimeFrame
673687 ) : Promise < Result < ProviderStatsResponse , string > > {
674688 const { interval, bucket } = TIME_CONFIG [ timeframe ] ;
675- const escapedProvider = provider . replace ( / ' / g, "''" ) ;
689+
690+ // Provider param is val_0
691+ const providerPlaceholder = `{val_0:String}` ;
676692
677693 const top9Query = `
678694 SELECT model, sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
679695 FROM request_stats
680696 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
681- AND provider = ' ${ escapedProvider } '
697+ AND provider = ${ providerPlaceholder }
682698 GROUP BY model
683699 ORDER BY total_tokens DESC
684700 LIMIT 9
@@ -687,7 +703,7 @@ export class ModelUsageStatsManager {
687703 const top9Result = await clickhouseDb . dbQuery < {
688704 model : string ;
689705 total_tokens : number ;
690- } > ( top9Query , [ ] ) ;
706+ } > ( top9Query , [ provider ] ) ;
691707 if ( top9Result . error ) return err ( top9Result . error ) ;
692708
693709 const top9Data = top9Result . data ?? [ ] ;
@@ -701,21 +717,24 @@ export class ModelUsageStatsManager {
701717 }
702718
703719 const top9Set = new Set ( top9Data . map ( ( r ) => r . model ) ) ;
704- const inClause = top9Data . map ( ( r ) => `'${ r . model } '` ) . join ( "," ) ;
720+ // Model params start at offset 1 (provider is val_0)
721+ const { placeholders : modelInClause , params : modelParams } =
722+ this . buildInClauseParams ( top9Data . map ( ( r ) => r . model ) , 1 ) ;
723+ const allParams = [ provider , ...modelParams ] ;
705724
706725 const otherQuery = `
707726 SELECT sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
708727 FROM request_stats
709728 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
710- AND provider = ' ${ escapedProvider } '
711- AND model NOT IN ( ${ inClause } )
729+ AND provider = ${ providerPlaceholder }
730+ AND model NOT IN ${ modelInClause }
712731 ` ;
713732
714733 const totalQuery = `
715734 SELECT sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
716735 FROM request_stats
717736 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
718- AND provider = ' ${ escapedProvider } '
737+ AND provider = ${ providerPlaceholder }
719738 ` ;
720739
721740 const prevTop9Query = `
@@ -724,8 +743,8 @@ export class ModelUsageStatsManager {
724743 WHERE hour >= now() - ${ interval } - ${ interval }
725744 AND hour < now() - ${ interval }
726745 AND ${ BASE_WHERE_CLAUSE }
727- AND provider = ' ${ escapedProvider } '
728- AND model IN ( ${ inClause } )
746+ AND provider = ${ providerPlaceholder }
747+ AND model IN ${ modelInClause }
729748 GROUP BY model
730749 ` ;
731750
@@ -735,8 +754,8 @@ export class ModelUsageStatsManager {
735754 WHERE hour >= now() - ${ interval } - ${ interval }
736755 AND hour < now() - ${ interval }
737756 AND ${ BASE_WHERE_CLAUSE }
738- AND provider = ' ${ escapedProvider } '
739- AND model NOT IN ( ${ inClause } )
757+ AND provider = ${ providerPlaceholder }
758+ AND model NOT IN ${ modelInClause }
740759 ` ;
741760
742761 const timeSeriesQuery = `
@@ -746,17 +765,17 @@ export class ModelUsageStatsManager {
746765 sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
747766 FROM request_stats
748767 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
749- AND provider = ' ${ escapedProvider } '
768+ AND provider = ${ providerPlaceholder }
750769 GROUP BY time_bucket, model
751770 ` ;
752771
753772 const [ otherResult , totalResult , prevTop9Result , prevOtherResult , timeSeriesResult ] =
754773 await Promise . all ( [
755- clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , [ ] ) ,
756- clickhouseDb . dbQuery < { total_tokens : number } > ( totalQuery , [ ] ) ,
757- clickhouseDb . dbQuery < { model : string ; total_tokens : number } > ( prevTop9Query , [ ] ) ,
758- clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , [ ] ) ,
759- clickhouseDb . dbQuery < { time_bucket : string ; model : string ; total_tokens : number } > ( timeSeriesQuery , [ ] ) ,
774+ clickhouseDb . dbQuery < { total_tokens : number } > ( otherQuery , allParams ) ,
775+ clickhouseDb . dbQuery < { total_tokens : number } > ( totalQuery , [ provider ] ) ,
776+ clickhouseDb . dbQuery < { model : string ; total_tokens : number } > ( prevTop9Query , allParams ) ,
777+ clickhouseDb . dbQuery < { total_tokens : number } > ( prevOtherQuery , allParams ) ,
778+ clickhouseDb . dbQuery < { time_bucket : string ; model : string ; total_tokens : number } > ( timeSeriesQuery , [ provider ] ) ,
760779 ] ) ;
761780
762781 if ( otherResult . error ) return err ( otherResult . error ) ;
@@ -833,13 +852,13 @@ export class ModelUsageStatsManager {
833852 timeframe : StatsTimeFrame
834853 ) : Promise < Result < ModelStatsResponse , string > > {
835854 const { interval, bucket } = TIME_CONFIG [ timeframe ] ;
836- const escapedModel = model . replace ( / ' / g , "''" ) ;
855+ const modelPlaceholder = `{val_0:String}` ;
837856
838857 const totalQuery = `
839858 SELECT sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
840859 FROM request_stats
841860 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
842- AND model = ' ${ escapedModel } '
861+ AND model = ${ modelPlaceholder }
843862 ` ;
844863
845864 const timeSeriesQuery = `
@@ -848,14 +867,14 @@ export class ModelUsageStatsManager {
848867 sum(${ TOTAL_TOKENS_EXPR } ) as total_tokens
849868 FROM request_stats
850869 WHERE hour >= now() - ${ interval } AND ${ BASE_WHERE_CLAUSE }
851- AND model = ' ${ escapedModel } '
870+ AND model = ${ modelPlaceholder }
852871 GROUP BY time_bucket
853872 ORDER BY time_bucket
854873 ` ;
855874
856875 const [ totalResult , timeSeriesResult ] = await Promise . all ( [
857- clickhouseDb . dbQuery < { total_tokens : number } > ( totalQuery , [ ] ) ,
858- clickhouseDb . dbQuery < { time_bucket : string ; total_tokens : number } > ( timeSeriesQuery , [ ] ) ,
876+ clickhouseDb . dbQuery < { total_tokens : number } > ( totalQuery , [ model ] ) ,
877+ clickhouseDb . dbQuery < { time_bucket : string ; total_tokens : number } > ( timeSeriesQuery , [ model ] ) ,
859878 ] ) ;
860879
861880 if ( totalResult . error ) return err ( totalResult . error ) ;
0 commit comments