@@ -3,7 +3,7 @@ import type { MySqlColumn } from '~/mysql-core/columns/index.ts';
33import type { MySqlDialect } from '~/mysql-core/dialect.ts' ;
44import type { MySqlPreparedQueryConfig , MySqlSession , PreparedQueryHKTBase } from '~/mysql-core/session.ts' ;
55import type { SubqueryWithSelection } from '~/mysql-core/subquery.ts' ;
6- import type { MySqlTable } from '~/mysql-core/table.ts' ;
6+ import { MySqlTable } from '~/mysql-core/table.ts' ;
77import { TypedQueryBuilder } from '~/query-builders/query-builder.ts' ;
88import type {
99 BuildSubquerySelection ,
@@ -21,9 +21,11 @@ import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts';
2121import { SQL , View } from '~/sql/sql.ts' ;
2222import { Subquery } from '~/subquery.ts' ;
2323import { Table } from '~/table.ts' ;
24- import { applyMixins , getTableColumns , getTableLikeName , haveSameKeys , type ValueOrArray } from '~/utils.ts' ;
25- import { orderSelectedFields } from '~/utils.ts' ;
24+ import type { ValueOrArray } from '~/utils.ts' ;
25+ import { applyMixins , getTableColumns , getTableLikeName , haveSameKeys , orderSelectedFields } from '~/utils.ts' ;
2626import { ViewBaseConfig } from '~/view-common.ts' ;
27+ import type { IndexBuilder } from '../indexes.ts' ;
28+ import { convertIndexToString , toArray } from '../utils.ts' ;
2729import { MySqlViewBase } from '../view-base.ts' ;
2830import type {
2931 AnyMySqlSelect ,
@@ -45,6 +47,14 @@ import type {
4547 SetOperatorRightSelect ,
4648} from './select.types.ts' ;
4749
50+ export type IndexForHint = IndexBuilder | string ;
51+
52+ export type IndexConfig = {
53+ useIndex ?: IndexForHint | IndexForHint [ ] ;
54+ forceIndex ?: IndexForHint | IndexForHint [ ] ;
55+ ignoreIndex ?: IndexForHint | IndexForHint [ ] ;
56+ } ;
57+
4858export class MySqlSelectBuilder <
4959 TSelection extends SelectedFields | undefined ,
5060 TPreparedQueryHKT extends PreparedQueryHKTBase ,
@@ -78,6 +88,8 @@ export class MySqlSelectBuilder<
7888
7989 from < TFrom extends MySqlTable | Subquery | MySqlViewBase | SQL > (
8090 source : TFrom ,
91+ onIndex ?: TFrom extends MySqlTable ? IndexConfig
92+ : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views' ,
8193 ) : CreateMySqlSelectFromBuilderMode <
8294 TBuilderMode ,
8395 GetSelectTableName < TFrom > ,
@@ -105,6 +117,21 @@ export class MySqlSelectBuilder<
105117 fields = getTableColumns < MySqlTable > ( source ) ;
106118 }
107119
120+ let useIndex : string [ ] = [ ] ;
121+ let forceIndex : string [ ] = [ ] ;
122+ let ignoreIndex : string [ ] = [ ] ;
123+ if ( is ( source , MySqlTable ) && onIndex && typeof onIndex !== 'string' ) {
124+ if ( onIndex . useIndex ) {
125+ useIndex = convertIndexToString ( toArray ( onIndex . useIndex ) ) ;
126+ }
127+ if ( onIndex . forceIndex ) {
128+ forceIndex = convertIndexToString ( toArray ( onIndex . forceIndex ) ) ;
129+ }
130+ if ( onIndex . ignoreIndex ) {
131+ ignoreIndex = convertIndexToString ( toArray ( onIndex . ignoreIndex ) ) ;
132+ }
133+ }
134+
108135 return new MySqlSelectBase (
109136 {
110137 table : source ,
@@ -114,6 +141,9 @@ export class MySqlSelectBuilder<
114141 dialect : this . dialect ,
115142 withList : this . withList ,
116143 distinct : this . distinct ,
144+ useIndex,
145+ forceIndex,
146+ ignoreIndex,
117147 } ,
118148 ) as any ;
119149 }
@@ -156,14 +186,17 @@ export abstract class MySqlSelectQueryBuilderBase<
156186 protected dialect : MySqlDialect ;
157187
158188 constructor (
159- { table, fields, isPartialSelect, session, dialect, withList, distinct } : {
189+ { table, fields, isPartialSelect, session, dialect, withList, distinct, useIndex , forceIndex , ignoreIndex } : {
160190 table : MySqlSelectConfig [ 'table' ] ;
161191 fields : MySqlSelectConfig [ 'fields' ] ;
162192 isPartialSelect : boolean ;
163193 session : MySqlSession | undefined ;
164194 dialect : MySqlDialect ;
165195 withList : Subquery [ ] ;
166196 distinct : boolean | undefined ;
197+ useIndex ?: string [ ] ;
198+ forceIndex ?: string [ ] ;
199+ ignoreIndex ?: string [ ] ;
167200 } ,
168201 ) {
169202 super ( ) ;
@@ -173,6 +206,9 @@ export abstract class MySqlSelectQueryBuilderBase<
173206 fields : { ...fields } ,
174207 distinct,
175208 setOperators : [ ] ,
209+ useIndex,
210+ forceIndex,
211+ ignoreIndex,
176212 } ;
177213 this . isPartialSelect = isPartialSelect ;
178214 this . session = session ;
@@ -187,9 +223,13 @@ export abstract class MySqlSelectQueryBuilderBase<
187223 private createJoin < TJoinType extends JoinType > (
188224 joinType : TJoinType ,
189225 ) : MySqlJoinFn < this, TDynamic , TJoinType > {
190- return (
226+ return <
227+ TJoinedTable extends MySqlTable | Subquery | MySqlViewBase | SQL ,
228+ > (
191229 table : MySqlTable | Subquery | MySqlViewBase | SQL ,
192230 on : ( ( aliases : TSelection ) => SQL | undefined ) | SQL | undefined ,
231+ onIndex ?: TJoinedTable extends MySqlTable ? IndexConfig
232+ : 'Index hint configuration is allowed only for MySqlTable and not for subqueries or views' ,
193233 ) => {
194234 const baseTableName = this . tableName ;
195235 const tableName = getTableLikeName ( table ) ;
@@ -228,7 +268,22 @@ export abstract class MySqlSelectQueryBuilderBase<
228268 this . config . joins = [ ] ;
229269 }
230270
231- this . config . joins . push ( { on, table, joinType, alias : tableName } ) ;
271+ let useIndex : string [ ] = [ ] ;
272+ let forceIndex : string [ ] = [ ] ;
273+ let ignoreIndex : string [ ] = [ ] ;
274+ if ( is ( table , MySqlTable ) && onIndex && typeof onIndex !== 'string' ) {
275+ if ( onIndex . useIndex ) {
276+ useIndex = convertIndexToString ( toArray ( onIndex . useIndex ) ) ;
277+ }
278+ if ( onIndex . forceIndex ) {
279+ forceIndex = convertIndexToString ( toArray ( onIndex . forceIndex ) ) ;
280+ }
281+ if ( onIndex . ignoreIndex ) {
282+ ignoreIndex = convertIndexToString ( toArray ( onIndex . ignoreIndex ) ) ;
283+ }
284+ }
285+
286+ this . config . joins . push ( { on, table, joinType, alias : tableName , useIndex, forceIndex, ignoreIndex } ) ;
232287
233288 if ( typeof tableName === 'string' ) {
234289 switch ( joinType ) {
@@ -286,6 +341,16 @@ export abstract class MySqlSelectQueryBuilderBase<
286341 * })
287342 * .from(users)
288343 * .leftJoin(pets, eq(users.id, pets.ownerId))
344+ *
345+ * // Select userId and petId with use index hint
346+ * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({
347+ * userId: users.id,
348+ * petId: pets.id,
349+ * })
350+ * .from(users)
351+ * .leftJoin(pets, eq(users.id, pets.ownerId), {
352+ * useIndex: ['pets_owner_id_index']
353+ * })
289354 * ```
290355 */
291356 leftJoin = this . createJoin ( 'left' ) ;
@@ -315,6 +380,16 @@ export abstract class MySqlSelectQueryBuilderBase<
315380 * })
316381 * .from(users)
317382 * .rightJoin(pets, eq(users.id, pets.ownerId))
383+ *
384+ * // Select userId and petId with use index hint
385+ * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({
386+ * userId: users.id,
387+ * petId: pets.id,
388+ * })
389+ * .from(users)
390+ * .leftJoin(pets, eq(users.id, pets.ownerId), {
391+ * useIndex: ['pets_owner_id_index']
392+ * })
318393 * ```
319394 */
320395 rightJoin = this . createJoin ( 'right' ) ;
@@ -344,6 +419,16 @@ export abstract class MySqlSelectQueryBuilderBase<
344419 * })
345420 * .from(users)
346421 * .innerJoin(pets, eq(users.id, pets.ownerId))
422+ *
423+ * // Select userId and petId with use index hint
424+ * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({
425+ * userId: users.id,
426+ * petId: pets.id,
427+ * })
428+ * .from(users)
429+ * .leftJoin(pets, eq(users.id, pets.ownerId), {
430+ * useIndex: ['pets_owner_id_index']
431+ * })
347432 * ```
348433 */
349434 innerJoin = this . createJoin ( 'inner' ) ;
@@ -373,6 +458,16 @@ export abstract class MySqlSelectQueryBuilderBase<
373458 * })
374459 * .from(users)
375460 * .fullJoin(pets, eq(users.id, pets.ownerId))
461+ *
462+ * // Select userId and petId with use index hint
463+ * const usersIdsAndPetIds: { userId: number; petId: number | null }[] = await db.select({
464+ * userId: users.id,
465+ * petId: pets.id,
466+ * })
467+ * .from(users)
468+ * .leftJoin(pets, eq(users.id, pets.ownerId), {
469+ * useIndex: ['pets_owner_id_index']
470+ * })
376471 * ```
377472 */
378473 fullJoin = this . createJoin ( 'full' ) ;
0 commit comments