-
Notifications
You must be signed in to change notification settings - Fork 280
/
dynamic.ts
93 lines (92 loc) · 3.17 KB
/
dynamic.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { DynamicReferenceBuilder } from './dynamic-reference-builder.js'
export class DynamicModule {
/**
* Creates a dynamic reference to a column that is not know at compile time.
*
* Kysely is built in a way that by default you can't refer to tables or columns
* that are not actually visible in the current query and context. This is all
* done by typescript at compile time, which means that you need to know the
* columns and tables at compile time. This is not always the case of course.
*
* This method is meant to be used in those cases where the column names
* come from the user input or are not otherwise known at compile time.
*
* WARNING! Unlike values, column names are not escaped by the database engine
* or Kysely and if you pass in unchecked column names using this method, you
* create an SQL injection vulnerability. Always __always__ validate the user
* input before passing it to this method.
*
* There are couple of examples below for some use cases, but you can pass
* `ref` to other methods as well. If the types allow you to pass a `ref`
* value to some place, it should work.
*
* @example
* Filter by a column not know at compile time:
*
* ```ts
* async function someQuery(filterColumn: string, filterValue: string) {
* const { ref } = db.dynamic
*
* return await db
* .selectFrom('person')
* .selectAll()
* .where(ref(filterColumn), '=', filterValue)
* .execute()
* }
*
* someQuery('first_name', 'Arnold')
* someQuery('person.last_name', 'Aniston')
* ```
*
* @example
* Order by a column not know at compile time:
*
* ```ts
* async function someQuery(orderBy: string) {
* const { ref } = db.dynamic
*
* return await db
* .selectFrom('person')
* .select('person.first_name as fn')
* .orderBy(ref(orderBy))
* .execute()
* }
*
* someQuery('fn')
* ```
*
* @example
* In this example we add selections dynamically:
*
* ```ts
* const { ref } = db.dynamic
*
* // Some column name provided by the user. Value not known at compile time.
* const columnFromUserInput = req.query.select;
*
* // A type that lists all possible values `columnFromUserInput` can have.
* // You can use `keyof Person` if any column of an interface is allowed.
* type PossibleColumns = 'last_name' | 'first_name' | 'birth_date'
*
* const [person] = await db.selectFrom('person')
* .select([
* ref<PossibleColumns>(columnFromUserInput)
* 'id'
* ])
* .execute()
*
* // The resulting type contains all `PossibleColumns` as optional fields
* // because we cannot know which field was actually selected before
* // running the code.
* const lastName: string | undefined = person.last_name
* const firstName: string | undefined = person.first_name
* const birthDate: string | undefined = person.birth_date
*
* // The result type also contains the compile time selection `id`.
* person.id
* ```
*/
ref<R extends string = never>(reference: string): DynamicReferenceBuilder<R> {
return new DynamicReferenceBuilder<R>(reference)
}
}