Skip to content

Commit fd86b66

Browse files
authored
feat: allow expressions in create/add index's column and columns functions, deprecate their expression functions. (#1664)
1 parent 15fcc57 commit fd86b66

File tree

3 files changed

+98
-33
lines changed

3 files changed

+98
-33
lines changed

src/schema/alter-table-add-index-builder.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
import type { CompiledQuery } from '../query-compiler/compiled-query.js'
1212
import type { QueryExecutor } from '../query-executor/query-executor.js'
1313
import type { Compilable } from '../util/compilable.js'
14-
import { freeze } from '../util/object-utils.js'
14+
import { freeze, isString } from '../util/object-utils.js'
1515
import type { QueryId } from '../util/query-id.js'
1616

1717
export class AlterTableAddIndexBuilder
@@ -63,28 +63,40 @@ export class AlterTableAddIndexBuilder
6363
* ### Examples
6464
*
6565
* ```ts
66+
* import { sql } from 'kysely'
67+
*
6668
* await db.schema
6769
* .alterTable('person')
6870
* .addIndex('person_first_name_and_age_index')
6971
* .column('first_name')
72+
* .column(sql`(left(lower(last_name), 1))`)
7073
* .column('age desc')
7174
* .execute()
7275
* ```
7376
*
7477
* The generated SQL (MySQL):
7578
*
7679
* ```sql
77-
* alter table `person` add index `person_first_name_and_age_index` (`first_name`, `age` desc)
80+
* alter table `person`
81+
* add index `person_first_name_and_age_index` (
82+
* `first_name`,
83+
* (left(lower(last_name), 1)),
84+
* `age` desc
85+
* )
7886
* ```
7987
*/
8088
column<CL extends string>(
8189
column: OrderedColumnName<CL>,
82-
): AlterTableAddIndexBuilder {
90+
): AlterTableAddIndexBuilder
91+
92+
column(expression: Expression<any>): AlterTableAddIndexBuilder
93+
94+
column(arg: any): any {
8395
return new AlterTableAddIndexBuilder({
8496
...this.#props,
8597
node: AlterTableNode.cloneWithTableProps(this.#props.node, {
8698
addIndex: AddIndexNode.cloneWithColumns(this.#props.node.addIndex!, [
87-
parseOrderedColumnName(column),
99+
isString(arg) ? parseOrderedColumnName(arg) : arg.toOperationNode(),
88100
]),
89101
}),
90102
})
@@ -99,28 +111,39 @@ export class AlterTableAddIndexBuilder
99111
* ### Examples
100112
*
101113
* ```ts
114+
* import { sql } from 'kysely'
115+
*
102116
* await db.schema
103117
* .alterTable('person')
104118
* .addIndex('person_first_name_and_age_index')
105-
* .columns(['first_name', 'age desc'])
119+
* .columns(['first_name', sql`(left(lower(last_name), 1))`, 'age desc'])
106120
* .execute()
107121
* ```
108122
*
109123
* The generated SQL (MySQL):
110124
*
111125
* ```sql
112-
* alter table `person` add index `person_first_name_and_age_index` (`first_name`, `age` desc)
126+
* alter table `person`
127+
* add index `person_first_name_and_age_index` (
128+
* `first_name`,
129+
* (left(lower(last_name), 1)),
130+
* `age` desc
131+
* )
113132
* ```
114133
*/
115134
columns<CL extends string>(
116-
columns: OrderedColumnName<CL>[],
135+
columns: (OrderedColumnName<CL> | Expression<any>)[],
117136
): AlterTableAddIndexBuilder {
118137
return new AlterTableAddIndexBuilder({
119138
...this.#props,
120139
node: AlterTableNode.cloneWithTableProps(this.#props.node, {
121140
addIndex: AddIndexNode.cloneWithColumns(
122141
this.#props.node.addIndex!,
123-
columns.map(parseOrderedColumnName),
142+
columns.map((item) =>
143+
isString(item)
144+
? parseOrderedColumnName(item)
145+
: item.toOperationNode(),
146+
),
124147
),
125148
}),
126149
})
@@ -146,7 +169,10 @@ export class AlterTableAddIndexBuilder
146169
* ```sql
147170
* alter table `person` add index `person_first_name_index` ((first_name < 'Sami'))
148171
* ```
172+
*
173+
* @deprecated Use {@link column} or {@link columns} with an {@link Expression} instead.
149174
*/
175+
// TODO: remove in v0.30
150176
expression(expression: Expression<any>): AlterTableAddIndexBuilder {
151177
return new AlterTableAddIndexBuilder({
152178
...this.#props,

src/schema/create-index-builder.ts

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type { CompiledQuery } from '../query-compiler/compiled-query.js'
1414
import type { Compilable } from '../util/compilable.js'
1515
import type { QueryExecutor } from '../query-executor/query-executor.js'
1616
import type { QueryId } from '../util/query-id.js'
17-
import { freeze } from '../util/object-utils.js'
17+
import { freeze, isString } from '../util/object-utils.js'
1818
import type { Expression } from '../expression/expression.js'
1919
import {
2020
type ComparisonOperatorExpression,
@@ -106,73 +106,88 @@ export class CreateIndexBuilder<C = never>
106106
/**
107107
* Adds a column to the index.
108108
*
109-
* Also see {@link columns} for adding multiple columns at once or {@link expression}
110-
* for specifying an arbitrary expression.
109+
* Also see {@link columns} for adding multiple columns at once.
111110
*
112111
* ### Examples
113112
*
114113
* ```ts
114+
* import { sql } from 'kysely'
115+
*
115116
* await db.schema
116-
* .createIndex('person_first_name_and_age_index')
117-
* .on('person')
118-
* .column('first_name')
119-
* .column('age desc')
120-
* .execute()
117+
* .createIndex('person_first_name_and_age_index')
118+
* .on('person')
119+
* .column('first_name')
120+
* .column<'last_name'>(sql`left(lower("last_name"), 1)`)
121+
* .column('age desc')
122+
* .where('last_name', 'is not', null)
123+
* .execute()
121124
* ```
122125
*
123126
* The generated SQL (PostgreSQL):
124127
*
125128
* ```sql
126-
* create index "person_first_name_and_age_index" on "person" ("first_name", "age" desc)
129+
* create index "person_first_name_and_age_index"
130+
* on "person" ("first_name", left(lower("last_name"), 1), "age" desc)
131+
* where "last_name" is not null
127132
* ```
128133
*/
129134
column<CL extends string>(
130135
column: OrderedColumnName<CL>,
131-
): CreateIndexBuilder<C | ExtractColumnNameFromOrderedColumnName<CL>> {
136+
): CreateIndexBuilder<C | ExtractColumnNameFromOrderedColumnName<CL>>
137+
column<CL extends string = never>(
138+
expression: Expression<any>,
139+
): CreateIndexBuilder<C | CL>
140+
column(arg: any): any {
132141
return new CreateIndexBuilder({
133142
...this.#props,
134143
node: CreateIndexNode.cloneWithColumns(this.#props.node, [
135-
parseOrderedColumnName(column),
144+
isString(arg) ? parseOrderedColumnName(arg) : arg.toOperationNode(),
136145
]),
137146
})
138147
}
139148

140149
/**
141-
* Specifies a list of columns for the index.
150+
* Adds a list of columns to the index.
142151
*
143-
* Also see {@link column} for adding a single column or {@link expression} for
144-
* specifying an arbitrary expression.
152+
* Also see {@link column} for adding a single column.
145153
*
146154
* ### Examples
147155
*
148156
* ```ts
157+
* import { sql } from 'kysely'
158+
*
149159
* await db.schema
150-
* .createIndex('person_first_name_and_age_index')
151-
* .on('person')
152-
* .columns(['first_name', 'age desc'])
153-
* .execute()
160+
* .createIndex('person_first_name_and_age_index')
161+
* .on('person')
162+
* .columns(['first_name', sql`left(lower("last_name"), 1)`, 'age desc'])
163+
* .execute()
154164
* ```
155165
*
156166
* The generated SQL (PostgreSQL):
157167
*
158168
* ```sql
159-
* create index "person_first_name_and_age_index" on "person" ("first_name", "age" desc)
169+
* create index "person_first_name_and_age_index"
170+
* on "person" ("first_name", left(lower("last_name"), 1), "age" desc)
160171
* ```
161172
*/
162173
columns<CL extends string>(
163-
columns: OrderedColumnName<CL>[],
174+
columns: (OrderedColumnName<CL> | Expression<any>)[],
164175
): CreateIndexBuilder<C | ExtractColumnNameFromOrderedColumnName<CL>> {
165176
return new CreateIndexBuilder({
166177
...this.#props,
167178
node: CreateIndexNode.cloneWithColumns(
168179
this.#props.node,
169-
columns.map(parseOrderedColumnName),
180+
columns.map((item) =>
181+
isString(item)
182+
? parseOrderedColumnName(item)
183+
: item.toOperationNode(),
184+
),
170185
),
171186
})
172187
}
173188

174189
/**
175-
* Specifies an arbitrary expression for the index.
190+
* Adds an arbitrary expression as a column to the index.
176191
*
177192
* ### Examples
178193
*
@@ -183,15 +198,20 @@ export class CreateIndexBuilder<C = never>
183198
* .createIndex('person_first_name_index')
184199
* .on('person')
185200
* .expression(sql`first_name COLLATE "fi_FI"`)
201+
* .column('gender')
186202
* .execute()
187203
* ```
188204
*
189205
* The generated SQL (PostgreSQL):
190206
*
191207
* ```sql
192-
* create index "person_first_name_index" on "person" (first_name COLLATE "fi_FI")
208+
* create index "person_first_name_index"
209+
* on "person" (first_name COLLATE "fi_FI", "gender")
193210
* ```
211+
*
212+
* @deprecated Use {@link column} or {@link columns} with an {@link Expression} instead.
194213
*/
214+
// TODO: remove in v0.30
195215
expression(expression: Expression<any>): CreateIndexBuilder<C> {
196216
return new CreateIndexBuilder({
197217
...this.#props,
@@ -203,6 +223,23 @@ export class CreateIndexBuilder<C = never>
203223

204224
/**
205225
* Specifies the index type.
226+
*
227+
* ### Examples
228+
*
229+
* ```ts
230+
* await db.schema
231+
* .createIndex('person_first_name_index')
232+
* .on('person')
233+
* .column('first_name')
234+
* .using('hash')
235+
* .execute()
236+
* ```
237+
*
238+
* The generated SQL (MySQL):
239+
*
240+
* ```sql
241+
* create index `person_first_name_index` on `person` (`first_name`) using hash
242+
* ```
206243
*/
207244
using(indexType: IndexType): CreateIndexBuilder<C>
208245
using(indexType: string): CreateIndexBuilder<C>
@@ -218,6 +255,8 @@ export class CreateIndexBuilder<C = never>
218255
/**
219256
* Adds a where clause to the query. This Effectively turns the index partial.
220257
*
258+
* This is only supported by some dialects like PostgreSQL and MS SQL Server.
259+
*
221260
* ### Examples
222261
*
223262
* ```ts

test/node/src/schema.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,7 +1855,7 @@ for (const dialect of DIALECTS) {
18551855
const builder = ctx.db.schema
18561856
.createIndex('test_first_name_index')
18571857
.on('test')
1858-
.expression(sql`(first_name < 'Sami')`)
1858+
.column(sql`(first_name < 'Sami')`)
18591859

18601860
testSql(builder, dialect, {
18611861
postgres: {
@@ -4093,7 +4093,7 @@ for (const dialect of DIALECTS) {
40934093
const query = ctx.db.schema
40944094
.alterTable('test')
40954095
.addIndex('test_varchar_col_index')
4096-
.expression(sql`(varchar_col < 'Sami')`)
4096+
.column(sql`(varchar_col < 'Sami')`)
40974097

40984098
testSql(query, dialect, {
40994099
mysql: {

0 commit comments

Comments
 (0)