prisma-ts-select 0.0.33 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1455 -263
- package/dist/bin.cjs +1 -1
- package/dist/bin.js +1 -1
- package/dist/chunk-47KZVQLD.js +283 -0
- package/dist/chunk-54D2J5AR.cjs +291 -0
- package/dist/extend/dialects/index.d.ts +13 -0
- package/dist/extend/dialects/index.js +186 -0
- package/dist/extend/dialects/mysql-v6.d.ts +100 -0
- package/dist/extend/dialects/mysql-v6.js +152 -0
- package/dist/extend/dialects/mysql-v7.d.ts +6 -0
- package/dist/extend/dialects/mysql-v7.js +138 -0
- package/dist/extend/dialects/mysql.d.ts +90 -0
- package/dist/extend/dialects/mysql.js +156 -0
- package/dist/extend/dialects/postgresql-v6.d.ts +97 -0
- package/dist/extend/dialects/postgresql-v6.js +136 -0
- package/dist/extend/dialects/postgresql-v7.d.ts +97 -0
- package/dist/extend/dialects/postgresql-v7.js +136 -0
- package/dist/extend/dialects/postgresql.d.ts +89 -0
- package/dist/extend/dialects/postgresql.js +147 -0
- package/dist/extend/dialects/shared.d.ts +6 -0
- package/dist/extend/dialects/shared.js +5 -0
- package/dist/extend/dialects/sqlite.d.ts +63 -0
- package/dist/extend/dialects/sqlite.js +138 -0
- package/dist/extend/dialects/types.d.ts +12 -0
- package/dist/extend/dialects/types.js +4 -0
- package/dist/extend/extend.d.ts +342 -57
- package/dist/extend/extend.js +813 -161
- package/dist/extend/sql-expr-BaKWzJ-r.d.ts +10 -0
- package/dist/extend/types-D84lxYVc.d.ts +5 -0
- package/dist/generator.cjs +1 -1
- package/dist/generator.js +1 -1
- package/package.json +52 -41
- package/built/extend.cjs +0 -565
- package/built/extend.d.cts +0 -451
- package/built/extend.d.ts +0 -451
- package/built/extend.js +0 -563
- package/dist/chunk-G66FOFCO.cjs +0 -195
- package/dist/chunk-GBXPF5FT.js +0 -187
- package/dist/extend/extend.cjs +0 -277
- package/dist/extend/extend.d.cts +0 -222
package/README.md
CHANGED
|
@@ -1,31 +1,78 @@
|
|
|
1
1
|
# prisma-ts-select
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+

|
|
4
5
|

|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
## Test Matrix
|
|
8
|
+
|
|
9
|
+
| | SQLite | MySQL | PostgreSQL |
|
|
10
|
+
|----------------|--------|-------|------------|
|
|
11
|
+
| **Prisma v6** |  |  |  |
|
|
12
|
+
| **Prisma v7** |  |  |  |
|
|
6
13
|
|
|
7
14
|
<!-- toc -->
|
|
8
15
|
|
|
9
16
|
* [Summary](#summary)
|
|
10
17
|
* [Installation](#installation)
|
|
18
|
+
* [Setup](#setup)
|
|
19
|
+
+ [Schema](#schema)
|
|
20
|
+
+ [Client — Prisma v6](#client--prisma-v6)
|
|
21
|
+
+ [Client — Prisma v7](#client--prisma-v7)
|
|
11
22
|
* [Supported DBs](#supported-dbs)
|
|
12
23
|
* [Usage](#usage)
|
|
13
24
|
+ [Generator](#generator)
|
|
14
25
|
* [API](#api)
|
|
15
26
|
+ [`.$from`](#from)
|
|
27
|
+
- [Example](#example)
|
|
28
|
+
- [Example - With Table Alias](#example---with-table-alias)
|
|
29
|
+
* [SQL](#sql)
|
|
30
|
+
- [Example - Inline Alias Syntax](#example---inline-alias-syntax)
|
|
31
|
+
* [SQL](#sql-1)
|
|
32
|
+
+ [`.$with`](#with)
|
|
33
|
+
- [Example — CTE as joined table](#example--cte-as-joined-table)
|
|
34
|
+
* [SQL](#sql-2)
|
|
35
|
+
- [Example — CTE as base table](#example--cte-as-base-table)
|
|
36
|
+
* [SQL](#sql-3)
|
|
37
|
+
- [Example — Multiple CTEs](#example--multiple-ctes)
|
|
38
|
+
* [SQL](#sql-4)
|
|
39
|
+
+ [Table Aliases](#table-aliases)
|
|
40
|
+
- [Table Alias Syntax Options](#table-alias-syntax-options)
|
|
41
|
+
- [Basic Table Alias](#basic-table-alias)
|
|
42
|
+
* [SQL](#sql-2)
|
|
43
|
+
- [Table Aliases with Joins](#table-aliases-with-joins)
|
|
44
|
+
* [Inline Alias Syntax](#inline-alias-syntax)
|
|
45
|
+
* [Object Syntax](#object-syntax)
|
|
46
|
+
* [SQL](#sql-3)
|
|
47
|
+
- [Self-Joins with Aliases](#self-joins-with-aliases)
|
|
48
|
+
* [SQL](#sql-4)
|
|
49
|
+
- [Table.* with Aliases](#table-with-aliases)
|
|
50
|
+
* [SQL](#sql-5)
|
|
51
|
+
* [SQL](#sql-6)
|
|
16
52
|
+ [Joins](#joins)
|
|
53
|
+
- [Dialect Support](#dialect-support)
|
|
54
|
+
- [Nullability Semantics](#nullability-semantics)
|
|
17
55
|
- [`.join`](#join)
|
|
18
|
-
* [Example](#example)
|
|
19
|
-
* [SQL](#sql)
|
|
56
|
+
* [Example](#example-1)
|
|
57
|
+
* [SQL](#sql-7)
|
|
20
58
|
* [Parameters](#parameters)
|
|
21
59
|
- [`.joinUnsafeTypeEnforced`](#joinunsafetypeenforced)
|
|
22
|
-
* [Example](#example-
|
|
23
|
-
* [SQL](#sql-
|
|
60
|
+
* [Example](#example-2)
|
|
61
|
+
* [SQL](#sql-8)
|
|
24
62
|
* [Parameters](#parameters-1)
|
|
25
63
|
- [`.joinUnsafeIgnoreType`](#joinunsafeignoretype)
|
|
26
|
-
* [Example](#example-
|
|
27
|
-
* [SQL](#sql-
|
|
64
|
+
* [Example](#example-3)
|
|
65
|
+
* [SQL](#sql-9)
|
|
28
66
|
* [Parameters](#parameters-2)
|
|
67
|
+
- [`.innerJoin`](#innerjoin)
|
|
68
|
+
- [`.leftJoin`](#leftjoin)
|
|
69
|
+
- [`.crossJoin`](#crossjoin)
|
|
70
|
+
- [`.rightJoin`](#rightjoin) *(MySQL / PostgreSQL)*
|
|
71
|
+
- [`.fullJoin`](#fulljoin) *(PostgreSQL only)*
|
|
72
|
+
- [`.manyToManyJoin`](#manytomanyjoin)
|
|
73
|
+
* [Example](#example-4)
|
|
74
|
+
* [SQL](#sql-10)
|
|
75
|
+
* [Parameters](#parameters-3)
|
|
29
76
|
+ [Where](#where)
|
|
30
77
|
- [`.where`](#where)
|
|
31
78
|
* [TypeSyntax](#typesyntax)
|
|
@@ -37,54 +84,62 @@
|
|
|
37
84
|
+ [$NOT](#not)
|
|
38
85
|
+ [$NOR](#nor)
|
|
39
86
|
- [`.whereNotNull`](#wherenotnull)
|
|
40
|
-
* [Example](#example-3)
|
|
41
|
-
* [SQL](#sql-3)
|
|
42
|
-
- [`.whereIsNull`](#whereisnull)
|
|
43
87
|
* [Example](#example-4)
|
|
44
|
-
* [SQL](#sql-
|
|
45
|
-
- [`.
|
|
88
|
+
* [SQL](#sql-10)
|
|
89
|
+
- [`.whereIsNull`](#whereisnull)
|
|
46
90
|
* [Example](#example-5)
|
|
47
|
-
* [SQL](#sql-
|
|
91
|
+
* [SQL](#sql-11)
|
|
92
|
+
- [`.whereRaw`](#whereraw)
|
|
93
|
+
* [Example](#example-6)
|
|
94
|
+
* [SQL](#sql-12)
|
|
48
95
|
+ [Group By](#group-by)
|
|
49
|
-
- [Example](#example-
|
|
50
|
-
- [SQL](#sql-
|
|
96
|
+
- [Example](#example-7)
|
|
97
|
+
- [SQL](#sql-13)
|
|
51
98
|
+ [Selecting](#selecting)
|
|
52
99
|
- [`.selectDistinct`](#selectdistinct)
|
|
53
|
-
- [Example](#example-
|
|
54
|
-
- [SQL](#sql-
|
|
100
|
+
- [Example](#example-8)
|
|
101
|
+
- [SQL](#sql-14)
|
|
55
102
|
- [`.selectAll`](#selectall)
|
|
56
103
|
- [Example - Single Table](#example---single-table)
|
|
57
|
-
* [SQL](#sql-
|
|
104
|
+
* [SQL](#sql-15)
|
|
58
105
|
- [Example - Join table](#example---join-table)
|
|
59
|
-
* [SQL](#sql-
|
|
106
|
+
* [SQL](#sql-16)
|
|
107
|
+
- [`.selectAllOmit`](#selectallomit)
|
|
60
108
|
- [`.select`](#select)
|
|
61
109
|
- [Example - `*`](#example---)
|
|
62
|
-
* [SQL](#sql-
|
|
110
|
+
* [SQL](#sql-17)
|
|
111
|
+
- [Example - `Table.*` (Single Table)](#example---table-single-table)
|
|
112
|
+
* [SQL](#sql-18)
|
|
113
|
+
- [Example - `Table.*` (With Join)](#example---table-with-join)
|
|
114
|
+
* [SQL](#sql-19)
|
|
63
115
|
- [Example - Chained](#example---chained)
|
|
64
|
-
* [SQL](#sql-
|
|
116
|
+
* [SQL](#sql-20)
|
|
65
117
|
- [Example - Join + Chained](#example---join--chained)
|
|
66
|
-
* [SQL](#sql-
|
|
118
|
+
* [SQL](#sql-21)
|
|
119
|
+
- [Example - Column Aliases](#example---column-aliases)
|
|
120
|
+
* [SQL](#sql-22)
|
|
121
|
+
- [Example - Aliases with Joins](#example---aliases-with-joins)
|
|
122
|
+
* [SQL](#sql-23)
|
|
67
123
|
+ [Having](#having)
|
|
68
|
-
- [Example](#example-8)
|
|
69
|
-
* [SQL](#sql-13)
|
|
70
|
-
+ [Order By](#order-by)
|
|
71
124
|
- [Example](#example-9)
|
|
72
|
-
* [SQL](#sql-
|
|
73
|
-
+ [
|
|
125
|
+
* [SQL](#sql-24)
|
|
126
|
+
+ [Order By](#order-by)
|
|
74
127
|
- [Example](#example-10)
|
|
75
|
-
* [SQL](#sql-
|
|
76
|
-
+ [
|
|
128
|
+
* [SQL](#sql-25)
|
|
129
|
+
+ [Limit](#limit)
|
|
77
130
|
- [Example](#example-11)
|
|
78
|
-
* [SQL](#sql-
|
|
131
|
+
* [SQL](#sql-26)
|
|
132
|
+
+ [Offset](#offset)
|
|
133
|
+
- [Example](#example-12)
|
|
134
|
+
* [SQL](#sql-27)
|
|
135
|
+
* [Select Functions](#select-functions)
|
|
136
|
+
+ [Shared (all dialects)](#shared-all-dialects)
|
|
137
|
+
+ [MySQL-specific](#mysql-specific)
|
|
138
|
+
+ [PostgreSQL-specific](#postgresql-specific)
|
|
139
|
+
+ [SQLite-specific](#sqlite-specific)
|
|
79
140
|
* [Future updates](#future-updates)
|
|
80
141
|
* [Changelog / Versioning](#changelog--versioning)
|
|
81
142
|
* [License](#license)
|
|
82
|
-
- [prisma-ts-select](#prisma-ts-select)
|
|
83
|
-
* [Install](#install)
|
|
84
|
-
* [Setup](#setup)
|
|
85
|
-
+ [Extract](#extract)
|
|
86
|
-
* [Usage](#usage-1)
|
|
87
|
-
|
|
88
143
|
<!-- tocstop -->
|
|
89
144
|
|
|
90
145
|
## Summary
|
|
@@ -93,13 +148,9 @@
|
|
|
93
148
|
It simplifies the selection of fields in Prisma queries, ensuring type safety and reducing boilerplate when working with nested fields.
|
|
94
149
|
Ideal for developers seeking an efficient, type-safe way to select data with Prisma in TypeScript.
|
|
95
150
|
|
|
96
|
-
[!NOTE]
|
|
97
|
-
>
|
|
98
|
-
>
|
|
99
|
-
> - HAVING
|
|
100
|
-
> - SQLite
|
|
101
|
-
> - Requires you to have either an aggregate function in the `SELECT` or make use of `GROUP BY`
|
|
102
|
-
> - Can only use columns that are specified in `SELECT` or `GROUP BY`
|
|
151
|
+
> [!NOTE]
|
|
152
|
+
> Fully tested on SQLite, MySQL, and PostgreSQL. Known exceptions:
|
|
153
|
+
> - HAVING on SQLite requires either an aggregate function in `SELECT` or a `GROUP BY` clause, and can only reference columns from `SELECT` or `GROUP BY`.
|
|
103
154
|
|
|
104
155
|
|
|
105
156
|
## Installation
|
|
@@ -111,15 +162,108 @@ npm install prisma-ts-select
|
|
|
111
162
|
pnpm add prisma-ts-select
|
|
112
163
|
```
|
|
113
164
|
|
|
165
|
+
## Setup
|
|
166
|
+
|
|
167
|
+
### Schema
|
|
168
|
+
|
|
169
|
+
Add both generators to `prisma/schema.prisma`. The `output` path is relative to the schema file.
|
|
170
|
+
|
|
171
|
+
```prisma
|
|
172
|
+
generator prisma-ts-select {
|
|
173
|
+
provider = "prisma-ts-select"
|
|
174
|
+
output = "../generated/prisma-ts-select"
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The client generator differs between Prisma versions:
|
|
179
|
+
|
|
180
|
+
**Prisma v6**
|
|
181
|
+
```prisma
|
|
182
|
+
generator client {
|
|
183
|
+
provider = "prisma-client-js"
|
|
184
|
+
output = "../generated/prisma"
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Prisma v7**
|
|
189
|
+
```prisma
|
|
190
|
+
generator client {
|
|
191
|
+
provider = "prisma-client"
|
|
192
|
+
output = "../generated/prisma"
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Then generate:
|
|
197
|
+
|
|
198
|
+
```shell
|
|
199
|
+
pnpm exec prisma generate
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Client — Prisma v6
|
|
203
|
+
|
|
204
|
+
No driver adapter needed. Import from the generated `extend-v6.js`:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { PrismaClient } from './generated/prisma/index.js'
|
|
208
|
+
import tsSelectExtend from './generated/prisma-ts-select/extend-v6.js'
|
|
209
|
+
|
|
210
|
+
export const prisma = new PrismaClient().$extends(tsSelectExtend)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Client — Prisma v7
|
|
214
|
+
|
|
215
|
+
Prisma v7 requires a driver adapter. Install the adapter for your database and import from the generated `extend-v7.js`:
|
|
216
|
+
|
|
217
|
+
**SQLite**
|
|
218
|
+
```shell
|
|
219
|
+
pnpm add @prisma/adapter-better-sqlite3
|
|
220
|
+
```
|
|
221
|
+
```typescript
|
|
222
|
+
import { PrismaClient } from './generated/prisma/client.ts'
|
|
223
|
+
import tsSelectExtend from './generated/prisma-ts-select/extend-v7.js'
|
|
224
|
+
import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3'
|
|
225
|
+
|
|
226
|
+
const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL })
|
|
227
|
+
export const prisma = new PrismaClient({ adapter }).$extends(tsSelectExtend)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**MySQL**
|
|
231
|
+
```shell
|
|
232
|
+
pnpm add @prisma/adapter-mariadb
|
|
233
|
+
```
|
|
234
|
+
```typescript
|
|
235
|
+
import { PrismaClient } from './generated/prisma/client.ts'
|
|
236
|
+
import tsSelectExtend from './generated/prisma-ts-select/extend-v7.js'
|
|
237
|
+
import { PrismaMariaDb } from '@prisma/adapter-mariadb'
|
|
238
|
+
|
|
239
|
+
const url = new URL(process.env.DATABASE_URL!)
|
|
240
|
+
const adapter = new PrismaMariaDb({
|
|
241
|
+
host: url.hostname, port: +url.port,
|
|
242
|
+
user: url.username, password: url.password,
|
|
243
|
+
database: url.pathname.slice(1),
|
|
244
|
+
})
|
|
245
|
+
export const prisma = new PrismaClient({ adapter }).$extends(tsSelectExtend)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**PostgreSQL**
|
|
249
|
+
```shell
|
|
250
|
+
pnpm add @prisma/adapter-pg
|
|
251
|
+
```
|
|
252
|
+
```typescript
|
|
253
|
+
import { PrismaClient } from './generated/prisma/client.ts'
|
|
254
|
+
import tsSelectExtend from './generated/prisma-ts-select/extend-v7.js'
|
|
255
|
+
import { PrismaPg } from '@prisma/adapter-pg'
|
|
256
|
+
|
|
257
|
+
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL })
|
|
258
|
+
export const prisma = new PrismaClient({ adapter }).$extends(tsSelectExtend)
|
|
259
|
+
```
|
|
260
|
+
|
|
114
261
|
## Supported DBs
|
|
115
262
|
|
|
116
|
-
|
|
263
|
+
Fully tested on:
|
|
117
264
|
|
|
118
265
|
- SQLite
|
|
119
266
|
- MySQL
|
|
120
|
-
|
|
121
|
-
Most items should also work for
|
|
122
|
-
|
|
123
267
|
- PostgreSQL
|
|
124
268
|
|
|
125
269
|
Other DBs will be added when I have chance.
|
|
@@ -180,13 +324,221 @@ The way the methods are chained, are heavily inspired by [Dr Milan Milanović](h
|
|
|
180
324
|
### `.$from`
|
|
181
325
|
This takes the `base` table to work from.
|
|
182
326
|
|
|
327
|
+
#### Example
|
|
328
|
+
```typescript file=../usage/tests/readme/from-basic.ts region=example
|
|
329
|
+
prisma.$from("User");
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### Example - With Table Alias
|
|
333
|
+
```typescript file=../usage/tests/readme/from-inline-alias.ts region=example
|
|
334
|
+
prisma.$from("User u");
|
|
335
|
+
```
|
|
336
|
+
##### SQL
|
|
337
|
+
```sql file=../usage/tests/readme/from-inline-alias.ts region=inline-alias-sql
|
|
338
|
+
FROM User AS `u`;
|
|
339
|
+
```
|
|
340
|
+
**Note:** Alias can be inline (space-separated) or as second parameter.
|
|
341
|
+
**Note:** Table aliases are particularly useful for self-joins where you need to join a table to itself with different aliases.
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
### `.$with`
|
|
345
|
+
|
|
346
|
+
Defines one or more Common Table Expressions (CTEs) that can be referenced in `.join()` calls or used directly as the base table via `.from('cteName')`.
|
|
347
|
+
|
|
348
|
+
| Param | Description |
|
|
349
|
+
|-------|-------------|
|
|
350
|
+
| `name` | CTE name — used to reference the CTE in `join()` or `from()` |
|
|
351
|
+
| `query` | Any query built with `.$from()` |
|
|
352
|
+
|
|
353
|
+
Chain `.with(name, query)` before `.from()` to define additional CTEs.
|
|
354
|
+
|
|
355
|
+
#### Example — CTE as joined table
|
|
356
|
+
|
|
357
|
+
```typescript file=../shared-tests/readme/with-cte.ts region=join
|
|
358
|
+
const posts = prisma.$from("Post").select("id").select("authorId").select("title");
|
|
359
|
+
|
|
360
|
+
prisma.$with("pp", posts)
|
|
361
|
+
.from("User")
|
|
362
|
+
.join("pp", "authorId", "User.id")
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
##### SQL
|
|
366
|
+
|
|
367
|
+
```sql file=../shared-tests/readme/with-cte.ts region=join-sql
|
|
368
|
+
WITH pp AS (SELECT id, authorId, title FROM Post) FROM User JOIN pp ON pp.authorId = User.id;
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### Example — CTE as base table
|
|
372
|
+
|
|
373
|
+
Use `.from('cteName')` to query a CTE directly, without a real table as the base.
|
|
374
|
+
|
|
375
|
+
```typescript file=../shared-tests/readme/with-cte.ts region=cte-base
|
|
376
|
+
const posts = prisma.$from("Post").select("id").select("title");
|
|
377
|
+
|
|
378
|
+
prisma.$with("pp", posts)
|
|
379
|
+
.from("pp")
|
|
380
|
+
.select("pp.id")
|
|
381
|
+
.select("pp.title")
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
##### SQL
|
|
385
|
+
|
|
386
|
+
```sql file=../shared-tests/readme/with-cte.ts region=cte-base-sql
|
|
387
|
+
WITH pp AS (SELECT id, title FROM Post) SELECT pp.id AS `pp.id`, pp.title AS `pp.title` FROM pp;
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Type safety:** only CTEs declared in `.$with()` / `.with()` are accepted by `.from()`. Unknown CTE names are rejected at compile time.
|
|
391
|
+
|
|
392
|
+
#### Example — Multiple CTEs
|
|
393
|
+
|
|
394
|
+
```typescript file=../shared-tests/readme/with-cte.ts region=multi-cte
|
|
395
|
+
const posts = prisma.$from("Post").select("id").select("authorId").select("title");
|
|
396
|
+
const users = prisma.$from("User").select("id").select("name");
|
|
397
|
+
|
|
398
|
+
prisma.$with("pp", posts)
|
|
399
|
+
.with("uu", users)
|
|
400
|
+
.from("User")
|
|
401
|
+
.join("pp", "authorId", "User.id")
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
##### SQL
|
|
405
|
+
|
|
406
|
+
```sql file=../shared-tests/readme/with-cte.ts region=multi-cte-sql
|
|
407
|
+
WITH pp AS (SELECT id, authorId, title FROM Post), uu AS (SELECT id, name FROM User) FROM User JOIN pp ON pp.authorId = User.id;
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Table Aliases
|
|
411
|
+
|
|
412
|
+
Table aliases allow you to give tables shorter or more meaningful names in your queries. This is especially useful for:
|
|
413
|
+
- Self-joins (joining a table to itself)
|
|
414
|
+
- Long table names
|
|
415
|
+
- Clearer query readability
|
|
416
|
+
|
|
417
|
+
#### Table Alias Syntax Options
|
|
418
|
+
|
|
419
|
+
Multiple syntaxes supported:
|
|
420
|
+
- **Inline in .$from()**: `prisma.$from("User u")` - Note: Second parameter syntax `.$from("User", "u")` is NOT supported
|
|
421
|
+
- **Inline in .join()**: `.join("Post p", "authorId", "User.id")`
|
|
422
|
+
- **Object syntax**: `.join({table: "Post", src: "authorId", on: "User.id", alias: "p"})`
|
|
423
|
+
|
|
424
|
+
#### Table Aliases with Joins
|
|
425
|
+
|
|
426
|
+
##### Inline Alias Syntax
|
|
427
|
+
```typescript file=../usage/tests/readme/table-alias.ts region=inline-join
|
|
428
|
+
prisma.$from("User u")
|
|
429
|
+
.join("Post p", "authorId", "u.id")
|
|
430
|
+
.select("u.name")
|
|
431
|
+
.select("p.title");
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
##### Object Syntax
|
|
435
|
+
```typescript file=../usage/tests/readme/table-alias.ts region=object-join
|
|
436
|
+
prisma.$from("User u")
|
|
437
|
+
.join({table: "Post", src: "authorId", on: "u.id", alias: "p"})
|
|
438
|
+
.select("u.name")
|
|
439
|
+
.select("p.title");
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
##### SQL
|
|
443
|
+
```sql file=../usage/tests/readme/table-alias.ts region=inline-join-sql
|
|
444
|
+
SELECT name, title
|
|
445
|
+
FROM User AS `u`
|
|
446
|
+
JOIN Post AS `p` ON p.authorId = u.id;
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Note:** The object syntax provides a foundation for future enhancements like multiple join conditions and complex WHERE-style conditions in joins.
|
|
450
|
+
|
|
451
|
+
#### Self-Joins with Aliases
|
|
452
|
+
|
|
453
|
+
Self-joins require aliases to distinguish between the different "instances" of the same table:
|
|
454
|
+
|
|
455
|
+
```typescript file=../usage/tests/readme/table-alias.ts region=self-join
|
|
456
|
+
prisma.$from("User u1")
|
|
457
|
+
.joinUnsafeTypeEnforced("User u2", "id", "u1.id")
|
|
458
|
+
.select("u1.name", "user1Name")
|
|
459
|
+
.select("u2.name", "user2Name");
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
##### SQL
|
|
463
|
+
```sql file=../usage/tests/readme/table-alias.ts region=self-join-sql
|
|
464
|
+
SELECT
|
|
465
|
+
u1.name AS `user1Name`,
|
|
466
|
+
u2.name AS `user2Name`
|
|
467
|
+
FROM User AS `u1`
|
|
468
|
+
JOIN User AS `u2` ON u2.id = u1.id;
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
#### Table.* with Aliases
|
|
472
|
+
|
|
473
|
+
You can use the `alias.*` syntax to select all columns from an aliased table:
|
|
474
|
+
|
|
475
|
+
```typescript file=../usage/tests/readme/table-alias.ts region=star-single
|
|
476
|
+
prisma.$from("User u")
|
|
477
|
+
.select("u.*");
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
##### SQL
|
|
481
|
+
```sql file=../usage/tests/readme/table-alias.ts region=star-single-sql
|
|
482
|
+
SELECT
|
|
483
|
+
id,
|
|
484
|
+
email,
|
|
485
|
+
name,
|
|
486
|
+
age
|
|
487
|
+
FROM User AS `u`;
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
With joins:
|
|
491
|
+
```typescript file=../usage/tests/readme/table-alias.ts region=star-join
|
|
492
|
+
prisma.$from("User u")
|
|
493
|
+
.join("Post p", "authorId", "u.id")
|
|
494
|
+
.select("u.*")
|
|
495
|
+
.select("p.*");
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
##### SQL
|
|
499
|
+
```sql file=../usage/tests/readme/table-alias.ts region=star-join-sql
|
|
500
|
+
SELECT
|
|
501
|
+
u.id AS `u.id`,
|
|
502
|
+
u.email AS `u.email`,
|
|
503
|
+
u.name AS `u.name`,
|
|
504
|
+
u.age AS `u.age`,
|
|
505
|
+
p.id AS `p.id`,
|
|
506
|
+
p.title AS `p.title`,
|
|
507
|
+
p.content AS `p.content`,
|
|
508
|
+
p.published AS `p.published`,
|
|
509
|
+
p.authorId AS `p.authorId`,
|
|
510
|
+
p.lastModifiedById AS `p.lastModifiedById`
|
|
511
|
+
FROM User AS `u`
|
|
512
|
+
JOIN Post AS `p` ON p.authorId = u.id;
|
|
513
|
+
```
|
|
514
|
+
|
|
183
515
|
### Joins
|
|
516
|
+
|
|
517
|
+
#### Dialect Support
|
|
518
|
+
|
|
519
|
+
| Method | SQLite | MySQL | PostgreSQL |
|
|
520
|
+
|--------|--------|-------|------------|
|
|
521
|
+
| `join` / `innerJoin` / `crossJoin` / `leftJoin` | ✓ | ✓ | ✓ |
|
|
522
|
+
| `rightJoin` | ✗ | ✓ | ✓ |
|
|
523
|
+
| `fullJoin` | ✗ | ✗ | ✓ |
|
|
524
|
+
|
|
525
|
+
Each method has `*UnsafeTypeEnforced` and `*UnsafeIgnoreType` variants with the same dialect restrictions.
|
|
526
|
+
|
|
527
|
+
#### Nullability Semantics
|
|
528
|
+
|
|
529
|
+
| Join type | Effect on result type |
|
|
530
|
+
|-----------|----------------------|
|
|
531
|
+
| `join` / `innerJoin` / `crossJoin` | No nullable change — both sides guaranteed to match |
|
|
532
|
+
| `leftJoin` | Joined table fields become `T \| null` |
|
|
533
|
+
| `rightJoin` | Base table fields become `T \| null` |
|
|
534
|
+
| `fullJoin` | Both sides become `T \| null` |
|
|
535
|
+
|
|
184
536
|
#### `.join`
|
|
185
537
|
|
|
186
538
|
Using the defined links (foreign keys) defined in the schema, provides a type-safe way of joining on tables.
|
|
187
539
|
|
|
188
540
|
##### Example
|
|
189
|
-
```typescript
|
|
541
|
+
```typescript file=../usage/tests/readme/join-basic.ts region=example
|
|
190
542
|
prisma.$from("User")
|
|
191
543
|
.join("Post", "authorId", "User.id");
|
|
192
544
|
```
|
|
@@ -197,24 +549,113 @@ prisma.$from("User")
|
|
|
197
549
|
|
|
198
550
|
The resulting SQL will look like:
|
|
199
551
|
|
|
200
|
-
```sql
|
|
552
|
+
```sql file=../usage/tests/readme/join-basic.ts region=join-basic-sql
|
|
201
553
|
FROM User
|
|
202
|
-
JOIN Post ON authorId = User.id;
|
|
554
|
+
JOIN Post ON Post.authorId = User.id;
|
|
203
555
|
```
|
|
204
556
|
|
|
205
557
|
##### Parameters
|
|
206
|
-
| column | Description
|
|
207
|
-
|
|
208
|
-
| `table` | The table to join on. <br/>TS autocomplete will show tables that can join with previously defined tables on.
|
|
209
|
-
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on.
|
|
210
|
-
| `reference` | `Table.Column` to a previously defined table (either the base, or another join), with a FK that is defined in the schema definition.
|
|
558
|
+
| column | Description |
|
|
559
|
+
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
560
|
+
| `table` | The table to join on (supports inline alias: `"Post p"` or `"Post", "p"`). <br/>TS autocomplete will show tables that can join with previously defined tables on. |
|
|
561
|
+
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on. |
|
|
562
|
+
| `reference` | `Table.Column` to a previously defined table (either the base, or another join), with a FK that is defined in the schema definition. |
|
|
563
|
+
| `where` | *(optional)* Criteria added to the `ON` clause (`ON a = b AND ...`). Same syntax as `.where()`. Keys scoped to the joined table only. |
|
|
564
|
+
| `joinType` | *(optional)* Join variant. One of `"INNER"`, `"LEFT"`, `"LEFT OUTER"`, `"RIGHT"`, `"RIGHT OUTER"`, `"FULL"`, `"FULL OUTER"`, `"CROSS"`. Default: plain `JOIN`. |
|
|
565
|
+
|
|
566
|
+
**Alternative Syntaxes:**
|
|
567
|
+
```typescript
|
|
568
|
+
// Inline alias
|
|
569
|
+
.join("Post p", "authorId", "User.id")
|
|
570
|
+
|
|
571
|
+
// Object syntax
|
|
572
|
+
.join({
|
|
573
|
+
table: "Post",
|
|
574
|
+
src: "authorId",
|
|
575
|
+
on: "User.id",
|
|
576
|
+
alias: "p", // optional
|
|
577
|
+
joinType: "LEFT", // optional
|
|
578
|
+
where: { "Post.published": true } // optional
|
|
579
|
+
})
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
##### Join Type
|
|
583
|
+
|
|
584
|
+
Control the SQL join variant via the `joinType` option:
|
|
585
|
+
|
|
586
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-left
|
|
587
|
+
prisma.$from("User")
|
|
588
|
+
.join("Post", "authorId", "User.id", { joinType: "LEFT" })
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-left-sql
|
|
592
|
+
FROM User LEFT JOIN Post ON Post.authorId = User.id;
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
`CROSS JOIN` has no `ON` clause — it is suppressed automatically:
|
|
596
|
+
|
|
597
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-cross
|
|
598
|
+
prisma.$from("User")
|
|
599
|
+
.joinUnsafeIgnoreType("Post", "id", "User.id", { joinType: "CROSS" })
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-cross-sql
|
|
603
|
+
FROM User CROSS JOIN Post;
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
`joinType` and `where` can be combined — `where` is ignored for `CROSS`:
|
|
607
|
+
|
|
608
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-with-where
|
|
609
|
+
prisma.$from("User")
|
|
610
|
+
.join("Post", "authorId", "User.id", {
|
|
611
|
+
joinType: "LEFT",
|
|
612
|
+
where: { "Post.published": true }
|
|
613
|
+
})
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-type.ts region=join-type-with-where-sql
|
|
617
|
+
FROM User LEFT JOIN Post ON Post.authorId = User.id AND Post.published = true;
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
##### Join-level WHERE
|
|
621
|
+
|
|
622
|
+
Conditions placed on the `ON` clause instead of the top-level `WHERE`:
|
|
623
|
+
|
|
624
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-where.ts region=join-where-example
|
|
625
|
+
prisma.$from("User")
|
|
626
|
+
.join("Post", "authorId", "User.id", { where: { "Post.published": true } })
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-where.ts region=join-where-sql
|
|
630
|
+
FROM User JOIN Post ON Post.authorId = User.id AND Post.published = true;
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
Supports the same MongoDB-inspired operators as `.where()` — `$AND`, `$OR`, `$NOT`, `$NOR`:
|
|
634
|
+
|
|
635
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-where.ts region=join-where-ops-example
|
|
636
|
+
prisma.$from("User")
|
|
637
|
+
.join("Post", "authorId", "User.id", {
|
|
638
|
+
where: {
|
|
639
|
+
$AND: [
|
|
640
|
+
{ "Post.published": true },
|
|
641
|
+
{ "Post.id": { op: ">", value: 0 } }
|
|
642
|
+
]
|
|
643
|
+
}
|
|
644
|
+
})
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-where.ts region=join-where-ops-sql
|
|
648
|
+
FROM User JOIN Post ON Post.authorId = User.id AND (Post.published = true AND Post.id > 0);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
> **Type safety**: only `"JoinedTable.field"` keys are accepted — other tables' fields are rejected at compile time.
|
|
211
652
|
|
|
212
653
|
#### `.joinUnsafeTypeEnforced`
|
|
213
654
|
|
|
214
655
|
Unlike the `.join` command, this will allow you to join on columns that are not explicitly linked by a FK, but have the same type.
|
|
215
656
|
|
|
216
657
|
##### Example
|
|
217
|
-
```typescript
|
|
658
|
+
```typescript file=../usage/tests/readme/join-unsafe.ts region=type-enforced
|
|
218
659
|
prisma.$from("User")
|
|
219
660
|
.joinUnsafeTypeEnforced("Post", "title", "User.name");
|
|
220
661
|
```
|
|
@@ -223,24 +664,26 @@ prisma.$from("User")
|
|
|
223
664
|
##### SQL
|
|
224
665
|
The resulting SQL will look like:
|
|
225
666
|
|
|
226
|
-
```sql
|
|
227
|
-
FROM User
|
|
667
|
+
```sql file=../usage/tests/readme/join-unsafe.ts region=type-enforced-sql
|
|
668
|
+
FROM User
|
|
228
669
|
JOIN Post ON Post.title = User.name;
|
|
229
670
|
```
|
|
230
671
|
|
|
231
672
|
##### Parameters
|
|
232
|
-
| column | Description
|
|
233
|
-
|
|
234
|
-
| `table` | The table to join on. <br/>TS autocomplete will show tables that can join with previously defined tables on.
|
|
235
|
-
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on.
|
|
236
|
-
| `reference` | `Table.Column` to a previously defined table (either the base, or another join), with a column that is of the same type.
|
|
673
|
+
| column | Description |
|
|
674
|
+
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
675
|
+
| `table` | The table to join on (supports inline alias: `"Post p"` or `"Post", "p"`). <br/>TS autocomplete will show tables that can join with previously defined tables on. |
|
|
676
|
+
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on. |
|
|
677
|
+
| `reference` | `Table.Column` to a previously defined table (either the base, or another join), with a column that is of the same type. |
|
|
678
|
+
| `where` | *(optional)* Criteria added to the `ON` clause. See [Join-level WHERE](#join-level-where). |
|
|
679
|
+
| `joinType` | *(optional)* Join variant. See [Join Type](#join-type). |
|
|
237
680
|
|
|
238
681
|
#### `.joinUnsafeIgnoreType`
|
|
239
682
|
|
|
240
683
|
Unlike the `.joinUnsafeIgnoreType` command, this will allow you to join on columns that are not explicitly linked by a FK, and do not have the same type.
|
|
241
684
|
|
|
242
685
|
##### Example
|
|
243
|
-
```typescript
|
|
686
|
+
```typescript file=../usage/tests/readme/join-unsafe.ts region=ignore-type
|
|
244
687
|
prisma.$from("User")
|
|
245
688
|
.joinUnsafeIgnoreType("Post", "id", "User.name");
|
|
246
689
|
```
|
|
@@ -249,17 +692,255 @@ prisma.$from("User")
|
|
|
249
692
|
##### SQL
|
|
250
693
|
The resulting SQL will look like:
|
|
251
694
|
|
|
695
|
+
```sql file=../usage/tests/readme/join-unsafe.ts region=ignore-type-sql
|
|
696
|
+
FROM User
|
|
697
|
+
JOIN Post ON Post.id = User.name;
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
##### Parameters
|
|
701
|
+
| column | Description |
|
|
702
|
+
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
703
|
+
| `table` | The table to join on (supports inline alias: `"Post p"` or `"Post", "p"`). <br/>TS autocomplete will show tables that can join with previously defined tables on. |
|
|
704
|
+
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on. |
|
|
705
|
+
| `reference` | `Table.Column` to a previously defined table (either the base, or another join). Referencing any column, of any type. |
|
|
706
|
+
| `where` | *(optional)* Criteria added to the `ON` clause. See [Join-level WHERE](#join-level-where). |
|
|
707
|
+
| `joinType` | *(optional)* Join variant. See [Join Type](#join-type). |
|
|
708
|
+
|
|
709
|
+
#### `.manyToManyJoin`
|
|
710
|
+
|
|
711
|
+
Joins through Prisma's implicit or explicit many-to-many junction tables. Automatically detects the junction table and join columns from the generated schema.
|
|
712
|
+
|
|
713
|
+
##### Example
|
|
714
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-basic
|
|
715
|
+
prisma.$from("M2M_Post")
|
|
716
|
+
.manyToManyJoin("M2M_Category");
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
##### SQL
|
|
720
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-basic-sql
|
|
721
|
+
FROM M2M_Post JOIN _M2M_CategoryToM2M_Post ON _M2M_CategoryToM2M_Post.B = M2M_Post.id JOIN M2M_Category ON M2M_Category.id = _M2M_CategoryToM2M_Post.A;
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
##### Parameters
|
|
725
|
+
| Param | Type | Description |
|
|
726
|
+
|-------|------|-------------|
|
|
727
|
+
| `targetTable` | `string` | Target table, optionally with alias: `"M2M_Category"` or `"M2M_Category mc"` |
|
|
728
|
+
| `options.refName` | `string?` | Junction ref name — required when multiple M2M relations point to the same target |
|
|
729
|
+
| `options.source` | `string?` | Explicit source as `"alias.column"` — useful when the source table is aliased |
|
|
730
|
+
|
|
731
|
+
##### With Alias
|
|
732
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-alias
|
|
733
|
+
prisma.$from("M2M_Post")
|
|
734
|
+
.manyToManyJoin("M2M_Category mc");
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-alias-sql
|
|
738
|
+
FROM M2M_Post JOIN _M2M_CategoryToM2M_Post ON _M2M_CategoryToM2M_Post.B = M2M_Post.id JOIN M2M_Category AS `mc` ON mc.id = _M2M_CategoryToM2M_Post.A;
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
##### Named Junction (`refName`)
|
|
742
|
+
|
|
743
|
+
Use `refName` when a model has multiple M2M relations to the same target:
|
|
744
|
+
|
|
745
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-refname
|
|
746
|
+
prisma.$from("MMM_Post")
|
|
747
|
+
.manyToManyJoin("MMM_Category", { refName: "M2M_NC_M1" });
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-refname-sql
|
|
751
|
+
FROM MMM_Post JOIN _M2M_NC_M1 ON _M2M_NC_M1.B = MMM_Post.id JOIN MMM_Category ON MMM_Category.id = _M2M_NC_M1.A;
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
##### Explicit Source (`source`)
|
|
755
|
+
|
|
756
|
+
Use `source` to pin the source alias and column when the source table is aliased:
|
|
757
|
+
|
|
758
|
+
```typescript file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-source
|
|
759
|
+
prisma.$from("M2M_Post mp")
|
|
760
|
+
.manyToManyJoin("M2M_Category mc", { source: "mp.id" });
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
```sql file=../usage-sqlite-v7/tests/readme/join-many-to-many.ts region=m2m-source-sql
|
|
764
|
+
FROM M2M_Post AS `mp` JOIN _M2M_CategoryToM2M_Post ON _M2M_CategoryToM2M_Post.B = mp.id JOIN M2M_Category AS `mc` ON mc.id = _M2M_CategoryToM2M_Post.A;
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### `.innerJoin`
|
|
768
|
+
|
|
769
|
+
Alias for `.join` — explicitly emits `INNER JOIN`. Same type-safe FK constraints.
|
|
770
|
+
|
|
771
|
+
##### Example
|
|
772
|
+
```typescript file=../shared-tests/readme/join-inner.ts region=example
|
|
773
|
+
prisma.$from("User")
|
|
774
|
+
.innerJoin("Post", "authorId", "User.id")
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
##### SQL
|
|
778
|
+
```sql file=../shared-tests/readme/join-inner.ts region=sql
|
|
779
|
+
FROM User INNER JOIN Post ON Post.authorId = User.id;
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
##### `.innerJoinUnsafeTypeEnforced`
|
|
783
|
+
|
|
784
|
+
Same-type column join, INNER semantics.
|
|
785
|
+
|
|
786
|
+
```typescript file=../shared-tests/readme/join-inner.ts region=type-enforced
|
|
787
|
+
prisma.$from("User")
|
|
788
|
+
.innerJoinUnsafeTypeEnforced("Post", "title", "User.name")
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
```sql file=../shared-tests/readme/join-inner.ts region=type-enforced-sql
|
|
792
|
+
FROM User INNER JOIN Post ON Post.title = User.name;
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
##### `.innerJoinUnsafeIgnoreType`
|
|
796
|
+
|
|
797
|
+
Any-column join, INNER semantics.
|
|
798
|
+
|
|
799
|
+
```typescript file=../shared-tests/readme/join-inner.ts region=ignore-type
|
|
800
|
+
prisma.$from("User")
|
|
801
|
+
.innerJoinUnsafeIgnoreType("Post", "id", "User.name")
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
```sql file=../shared-tests/readme/join-inner.ts region=ignore-type-sql
|
|
805
|
+
FROM User INNER JOIN Post ON Post.id = User.name;
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
---
|
|
809
|
+
|
|
810
|
+
#### `.leftJoin`
|
|
811
|
+
|
|
812
|
+
FK-safe LEFT JOIN. Joined table fields become `T | null` in the result type.
|
|
813
|
+
|
|
814
|
+
##### Example
|
|
815
|
+
```typescript file=../shared-tests/readme/join-left.ts region=example
|
|
816
|
+
prisma.$from("User")
|
|
817
|
+
.leftJoin("Post", "authorId", "User.id")
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
##### SQL
|
|
821
|
+
```sql file=../shared-tests/readme/join-left.ts region=sql
|
|
822
|
+
FROM User LEFT JOIN Post ON Post.authorId = User.id;
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
##### `.leftJoinUnsafeTypeEnforced`
|
|
826
|
+
|
|
827
|
+
Same-type column join, LEFT semantics.
|
|
828
|
+
|
|
829
|
+
```typescript file=../shared-tests/readme/join-left.ts region=type-enforced
|
|
830
|
+
prisma.$from("User")
|
|
831
|
+
.leftJoinUnsafeTypeEnforced("Post", "title", "User.name")
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
```sql file=../shared-tests/readme/join-left.ts region=type-enforced-sql
|
|
835
|
+
FROM User LEFT JOIN Post ON Post.title = User.name;
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
##### `.leftJoinUnsafeIgnoreType`
|
|
839
|
+
|
|
840
|
+
Any-column join, LEFT semantics.
|
|
841
|
+
|
|
842
|
+
```typescript file=../shared-tests/readme/join-left.ts region=ignore-type
|
|
843
|
+
prisma.$from("User")
|
|
844
|
+
.leftJoinUnsafeIgnoreType("Post", "id", "User.name")
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
```sql file=../shared-tests/readme/join-left.ts region=ignore-type-sql
|
|
848
|
+
FROM User LEFT JOIN Post ON Post.id = User.name;
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
---
|
|
852
|
+
|
|
853
|
+
#### `.crossJoin`
|
|
854
|
+
|
|
855
|
+
Produces a cartesian product — no `ON` clause. All dialects supported.
|
|
856
|
+
|
|
857
|
+
##### Example
|
|
858
|
+
```typescript file=../shared-tests/readme/join-cross.ts region=example
|
|
859
|
+
prisma.$from("User")
|
|
860
|
+
.crossJoin("Post")
|
|
861
|
+
```
|
|
862
|
+
|
|
863
|
+
##### SQL
|
|
864
|
+
```sql file=../shared-tests/readme/join-cross.ts region=sql
|
|
865
|
+
FROM User CROSS JOIN Post;
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
##### `.crossJoinUnsafeTypeEnforced` / `.crossJoinUnsafeIgnoreType`
|
|
869
|
+
|
|
870
|
+
Type-permission variants — still emit `CROSS JOIN` with no `ON` clause (takes only a table argument).
|
|
871
|
+
|
|
872
|
+
```typescript file=../shared-tests/readme/join-cross.ts region=type-enforced
|
|
873
|
+
prisma.$from("User")
|
|
874
|
+
.crossJoinUnsafeTypeEnforced("Post")
|
|
875
|
+
```
|
|
876
|
+
|
|
877
|
+
```sql file=../shared-tests/readme/join-cross.ts region=type-enforced-sql
|
|
878
|
+
FROM User CROSS JOIN Post;
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
---
|
|
882
|
+
|
|
883
|
+
#### `.rightJoin`
|
|
884
|
+
|
|
885
|
+
> **MySQL / PostgreSQL only** — not supported by SQLite.
|
|
886
|
+
|
|
887
|
+
Base table fields become `T | null`. Use when the joined table drives the result set.
|
|
888
|
+
|
|
889
|
+
##### Example
|
|
890
|
+
```typescript
|
|
891
|
+
prisma.$from("Post")
|
|
892
|
+
.rightJoin("User", "id", "Post.authorId")
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
##### SQL
|
|
896
|
+
```sql
|
|
897
|
+
FROM Post RIGHT JOIN User ON User.id = Post.authorId;
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
##### `.rightJoinUnsafeTypeEnforced`
|
|
901
|
+
```typescript
|
|
902
|
+
prisma.$from("Post")
|
|
903
|
+
.rightJoinUnsafeTypeEnforced("User", "name", "Post.title")
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
##### `.rightJoinUnsafeIgnoreType`
|
|
907
|
+
```typescript
|
|
908
|
+
prisma.$from("Post")
|
|
909
|
+
.rightJoinUnsafeIgnoreType("User", "id", "Post.title")
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
#### `.fullJoin`
|
|
915
|
+
|
|
916
|
+
> **PostgreSQL only** — not supported by SQLite or MySQL.
|
|
917
|
+
|
|
918
|
+
Both sides become `T | null`. Use for outer joins where either side may have no match.
|
|
919
|
+
|
|
920
|
+
##### Example
|
|
921
|
+
```typescript
|
|
922
|
+
prisma.$from("User")
|
|
923
|
+
.fullJoin("Post", "authorId", "User.id")
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
##### SQL
|
|
252
927
|
```sql
|
|
253
|
-
FROM User
|
|
254
|
-
|
|
928
|
+
FROM User FULL JOIN Post ON Post.authorId = User.id;
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
##### `.fullJoinUnsafeTypeEnforced`
|
|
932
|
+
```typescript
|
|
933
|
+
prisma.$from("User")
|
|
934
|
+
.fullJoinUnsafeTypeEnforced("Post", "title", "User.name")
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
##### `.fullJoinUnsafeIgnoreType`
|
|
938
|
+
```typescript
|
|
939
|
+
prisma.$from("User")
|
|
940
|
+
.fullJoinUnsafeIgnoreType("Post", "id", "User.name")
|
|
255
941
|
```
|
|
256
942
|
|
|
257
|
-
|
|
258
|
-
| column | Description |
|
|
259
|
-
|-------------|----------------------------------------------------------------------------------------------------------------------------|
|
|
260
|
-
| `table` | The table to join on. <br/>TS autocomplete will show tables that can join with previously defined tables on. |
|
|
261
|
-
| `field` | Column on table. <br/>TS autocomplete will show known columns that this table, can join with previously defined tables on. |
|
|
262
|
-
| `reference` | `Table.Column` to a previously defined table (either the base, or another join). Referencing any column, of any type. |
|
|
943
|
+
---
|
|
263
944
|
|
|
264
945
|
### Where
|
|
265
946
|
|
|
@@ -270,9 +951,12 @@ The `where` syntax takes inspiration from how mongoDB does queries.
|
|
|
270
951
|
##### TypeSyntax
|
|
271
952
|
```TypeScript
|
|
272
953
|
type WhereClause = {
|
|
273
|
-
"Table.Column": <value>
|
|
954
|
+
"Table.Column": <value>
|
|
955
|
+
| [<value>, ...<value>[]] // scalar array → IN
|
|
956
|
+
| { "op": "<condition>", "value": <value> }
|
|
957
|
+
| [{ "op": "<condition>", "value": <value> }, ...] // op-array → OR
|
|
274
958
|
"$AND": [WhereClause, ...Array<WhereClause>],
|
|
275
|
-
"$OR":
|
|
959
|
+
"$OR": [WhereClause, ...Array<WhereClause>],
|
|
276
960
|
"$NOT": [WhereClause, ...Array<WhereClause>],
|
|
277
961
|
"$NOR": [WhereClause, ...Array<WhereClause>]
|
|
278
962
|
}
|
|
@@ -293,6 +977,7 @@ type WhereClause = {
|
|
|
293
977
|
| < | | Numbers, Date |
|
|
294
978
|
| <= | | Numbers, Date |
|
|
295
979
|
| != | | Numbers, String, Date |
|
|
980
|
+
| = | | Numbers, String, Date |
|
|
296
981
|
|
|
297
982
|
|
|
298
983
|
##### Examples
|
|
@@ -303,155 +988,190 @@ type WhereClause = {
|
|
|
303
988
|
| $OR | Will join all items with a `OR` | <pre>.where({ <br /> $OR:[<br /> {"User.name": {op: "LIKE", value:"a%"}},<br /> {"User.name": {op: "LIKE", value:"d%"}},<br />]})</pre> | `(User.name LIKE "a%" OR User.name LIKE "d%")` |
|
|
304
989
|
| $NOT | Will wrap statement in a `NOT (/*...*/)` and join any items with a `AND` | <pre>.where({ <br /> $NOT:[<br /> {"User.age": 20 },<br /> {<br /> "User.age": {op: "=", value:60},<br /> "User.name": "Bob",<br /> },<br />]})</pre> | `(NOT (User.age = 20 AND (User.age = 60 AND User.name = "Bob")))` |
|
|
305
990
|
| $NOR | Will wrap statement in a `NOT (/*...*/)` and join any items with a `OR` | <pre>.where({ <br /> $NOR:[<br /> {"User.age": 20 },<br /> {<br /> "User.age": {op: "!=", value:60},<br /> "User.name": "Bob",<br /> },<br />]})</pre> | `(NOT (User.age = 20 OR (User.age != 60 AND User.name = "Bob")))` |
|
|
991
|
+
| `Array (scalar)` | Non-empty array of values → SQL `IN` | `.where({ "User.name": ["Alice", "Bob"] })` | `User.name IN ('Alice', 'Bob')` |
|
|
992
|
+
| `Array (op-objects)` | Non-empty array of op-objects → `OR` chain | `.where({ "User.name": [{ op: "LIKE", value: "A%" }, { op: "LIKE", value: "B%" }] })` | `(User.name LIKE 'A%' OR User.name LIKE 'B%')` |
|
|
306
993
|
|
|
307
994
|
|
|
308
995
|
###### Columns
|
|
309
|
-
```typescript
|
|
996
|
+
```typescript file=../usage/tests/readme/where.ts region=columns
|
|
310
997
|
prisma.$from("User")
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
998
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
999
|
+
.where({
|
|
1000
|
+
"User.age": 20,
|
|
1001
|
+
"User.name": {op: "LIKE", value: "Stuart%"},
|
|
1002
|
+
});
|
|
316
1003
|
```
|
|
317
1004
|
|
|
318
1005
|
###### $AND
|
|
319
|
-
```typescript
|
|
1006
|
+
```typescript file=../usage/tests/readme/where.ts region=and
|
|
320
1007
|
prisma.$from("User")
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
1008
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1009
|
+
.where({
|
|
1010
|
+
$AND: [
|
|
1011
|
+
{"User.age": {op: ">", value: 20}},
|
|
1012
|
+
{"User.age": {op: "<", value: 60}},
|
|
1013
|
+
]
|
|
1014
|
+
});
|
|
328
1015
|
```
|
|
329
1016
|
|
|
330
1017
|
###### $OR
|
|
331
|
-
```typescript
|
|
1018
|
+
```typescript file=../usage/tests/readme/where.ts region=or
|
|
332
1019
|
prisma.$from("User")
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
1020
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1021
|
+
.where({
|
|
1022
|
+
$OR: [
|
|
1023
|
+
{"User.name": {op: "LIKE", value: "a%"}},
|
|
1024
|
+
{"User.name": {op: "LIKE", value: "d%"}},
|
|
1025
|
+
]
|
|
1026
|
+
});
|
|
340
1027
|
```
|
|
341
1028
|
|
|
342
1029
|
###### $NOT
|
|
343
|
-
```typescript
|
|
1030
|
+
```typescript file=../usage/tests/readme/where.ts region=not
|
|
344
1031
|
prisma.$from("User")
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
1032
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1033
|
+
.where({
|
|
1034
|
+
$NOT: [
|
|
1035
|
+
{"User.age": 20},
|
|
1036
|
+
{
|
|
1037
|
+
"User.age": {op: "=", value: 60},
|
|
1038
|
+
"User.name": "Bob",
|
|
1039
|
+
},
|
|
1040
|
+
]
|
|
1041
|
+
});
|
|
355
1042
|
```
|
|
356
1043
|
|
|
357
1044
|
###### $NOR
|
|
358
|
-
```typescript
|
|
1045
|
+
```typescript file=../usage/tests/readme/where.ts region=nor
|
|
359
1046
|
prisma.$from("User")
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
1047
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1048
|
+
.where({
|
|
1049
|
+
$NOR: [
|
|
1050
|
+
{"User.age": 20},
|
|
1051
|
+
{
|
|
1052
|
+
"User.age": {op: "!=", value: 60},
|
|
1053
|
+
"User.name": "Bob",
|
|
1054
|
+
},
|
|
1055
|
+
]
|
|
1056
|
+
});
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
###### Array (Scalar → IN)
|
|
1060
|
+
```typescript file=../usage/tests/readme/where.ts region=array-scalar
|
|
1061
|
+
prisma.$from("User")
|
|
1062
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1063
|
+
.where({
|
|
1064
|
+
"User.name": ["Alice", "Bob"],
|
|
1065
|
+
});
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
###### Array (Op-Object → OR)
|
|
1069
|
+
```typescript file=../usage/tests/readme/where.ts region=array-op
|
|
1070
|
+
prisma.$from("User")
|
|
1071
|
+
.joinUnsafeIgnoreType("Post", "id", "User.name")
|
|
1072
|
+
.where({
|
|
1073
|
+
"User.name": [
|
|
1074
|
+
{ op: "LIKE", value: "A%" },
|
|
1075
|
+
{ op: "LIKE", value: "B%" },
|
|
1076
|
+
],
|
|
1077
|
+
});
|
|
370
1078
|
```
|
|
371
1079
|
|
|
372
1080
|
#### `.whereNotNull`
|
|
373
1081
|
|
|
374
|
-
|
|
375
|
-
|
|
1082
|
+
Removes `null` from the column's type union and adds an `IS NOT NULL` condition to the WHERE clause.
|
|
1083
|
+
Type narrowing is reflected in all downstream `.select()` calls.
|
|
376
1084
|
|
|
377
1085
|
##### Example
|
|
378
|
-
```typescript
|
|
1086
|
+
```typescript file=../usage-sqlite-v7/tests/readme/whereNotNull.ts region=whereNotNull
|
|
379
1087
|
prisma.$from("User")
|
|
380
|
-
|
|
381
|
-
|
|
1088
|
+
.join("Post", "authorId", "User.id")
|
|
1089
|
+
.whereNotNull("User.name")
|
|
382
1090
|
```
|
|
383
1091
|

|
|
384
1092
|
|
|
385
1093
|
##### SQL
|
|
386
1094
|
The resulting SQL will look like:
|
|
387
1095
|
|
|
388
|
-
```sql
|
|
389
|
-
FROM User
|
|
390
|
-
JOIN Post ON authorId = User.id
|
|
391
|
-
WHERE User.name IS NOT NULL;
|
|
1096
|
+
```sql file=../usage-sqlite-v7/tests/readme/whereNotNull.ts region=whereNotNull-sql
|
|
1097
|
+
FROM User JOIN Post ON Post.authorId = User.id WHERE (User.name IS NOT NULL);
|
|
392
1098
|
```
|
|
393
1099
|
|
|
394
1100
|
#### `.whereIsNull`
|
|
395
1101
|
|
|
396
|
-
|
|
397
|
-
To use `.whereIsNull`, you need to add it before a `.where`.
|
|
1102
|
+
Narrows the column's type to exactly `null` and adds an `IS NULL` condition to the WHERE clause.
|
|
398
1103
|
|
|
399
1104
|
##### Example
|
|
400
|
-
```typescript
|
|
1105
|
+
```typescript file=../usage-sqlite-v7/tests/readme/whereNotNull.ts region=whereIsNull
|
|
401
1106
|
prisma.$from("User")
|
|
402
|
-
|
|
403
|
-
|
|
1107
|
+
.join("Post", "authorId", "User.id")
|
|
1108
|
+
.whereIsNull("Post.content")
|
|
404
1109
|
```
|
|
405
1110
|

|
|
406
1111
|
|
|
407
1112
|
##### SQL
|
|
408
1113
|
The resulting SQL will look like:
|
|
409
1114
|
|
|
410
|
-
```sql
|
|
411
|
-
FROM User
|
|
412
|
-
|
|
413
|
-
|
|
1115
|
+
```sql file=../usage-sqlite-v7/tests/readme/whereNotNull.ts region=whereIsNull-sql
|
|
1116
|
+
FROM User JOIN Post ON Post.authorId = User.id WHERE (Post.content IS NULL);
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
#### `.where` — fn overload (SQL expressions)
|
|
1120
|
+
|
|
1121
|
+
Pass a callback instead of a criteria object to apply SQL functions as conditions. The callback receives the same select-fn context as `.select()`, giving access to `upper`, `lower`, `length`, `count`, `avg`, etc.
|
|
1122
|
+
|
|
1123
|
+
```typescript file=../shared-tests/readme/where.ts region=fn-upper-like
|
|
1124
|
+
prisma.$from("User")
|
|
1125
|
+
.where(({ upper }) => [[upper('name'), { op: 'LIKE', value: 'John%' }]])
|
|
1126
|
+
.select("name")
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
```sql file=../shared-tests/readme/where.ts region=fn-upper-like-sql
|
|
1130
|
+
SELECT name FROM User WHERE UPPER(name) LIKE 'John%';
|
|
414
1131
|
```
|
|
415
1132
|
|
|
1133
|
+
Each array element is an `[SQLExpr<T>, condition]` pair — multiple pairs are AND-ed. The condition type is inferred from `SQLExpr<T>`: string expressions accept LIKE/NOT LIKE, numeric expressions accept `>`, `<`, BETWEEN, etc.
|
|
1134
|
+
|
|
416
1135
|
#### `.whereRaw`
|
|
417
1136
|
|
|
418
|
-
When you want to write a complex `where`, or you just don't want the TypeSafety offered by the other methods, you can use `.whereRaw`.
|
|
1137
|
+
When you want to write a complex `where`, or you just don't want the TypeSafety offered by the other methods, you can use `.whereRaw`.
|
|
419
1138
|
|
|
420
1139
|
##### Example
|
|
421
|
-
```typescript
|
|
1140
|
+
```typescript file=../usage/tests/readme/where.ts region=raw
|
|
422
1141
|
prisma.$from("User")
|
|
423
|
-
|
|
424
|
-
|
|
1142
|
+
.join("Post", "authorId", "User.id")
|
|
1143
|
+
.whereRaw("this is a raw where statement");
|
|
425
1144
|
```
|
|
426
1145
|
|
|
427
1146
|
##### SQL
|
|
428
1147
|
The resulting SQL will look like:
|
|
429
1148
|
|
|
430
|
-
```sql
|
|
431
|
-
FROM User
|
|
432
|
-
JOIN Post ON authorId = User.id
|
|
433
|
-
WHERE this is a raw
|
|
1149
|
+
```sql file=../usage/tests/readme/where.ts region=raw-sql
|
|
1150
|
+
FROM User
|
|
1151
|
+
JOIN Post ON Post.authorId = User.id
|
|
1152
|
+
WHERE this is a raw
|
|
1153
|
+
WHERE statement;
|
|
434
1154
|
```
|
|
435
1155
|
|
|
436
1156
|
|
|
437
1157
|
### Group By
|
|
438
1158
|
|
|
439
|
-
Will allow you to pass a list of columns, that haven been specified from the `.$from` and any `.join` methods.
|
|
1159
|
+
Will allow you to pass a list of columns, that haven been specified from the `.$from` and any `.join` methods.
|
|
440
1160
|
|
|
441
1161
|
#### Example
|
|
442
|
-
```typescript
|
|
1162
|
+
```typescript file=../usage/tests/readme/groupby.ts region=basic
|
|
443
1163
|
prisma.$from("User")
|
|
444
|
-
|
|
445
|
-
|
|
1164
|
+
.join("Post", "authorId", "User.id")
|
|
1165
|
+
.groupBy(["name", "Post.content"]);
|
|
446
1166
|
```
|
|
447
1167
|

|
|
448
1168
|
|
|
449
1169
|
#### SQL
|
|
450
1170
|
The resulting SQL will look like:
|
|
451
1171
|
|
|
452
|
-
```sql
|
|
453
|
-
FROM User
|
|
454
|
-
JOIN Post ON authorId = User.id
|
|
1172
|
+
```sql file=../usage/tests/readme/groupby.ts region=basic-sql
|
|
1173
|
+
FROM User
|
|
1174
|
+
JOIN Post ON Post.authorId = User.id
|
|
455
1175
|
GROUP BY name, Post.content;
|
|
456
1176
|
```
|
|
457
1177
|
|
|
@@ -462,16 +1182,17 @@ GROUP BY name, Post.content;
|
|
|
462
1182
|
Will add the keyword `DISTINCT` after the select.
|
|
463
1183
|
|
|
464
1184
|
#### Example
|
|
465
|
-
```typescript
|
|
1185
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=distinct
|
|
466
1186
|
prisma.$from("User")
|
|
467
|
-
|
|
1187
|
+
.selectDistinct()
|
|
1188
|
+
.select("name");
|
|
468
1189
|
```
|
|
469
1190
|
|
|
470
1191
|
#### SQL
|
|
471
1192
|
The resulting SQL will look like:
|
|
472
1193
|
|
|
473
|
-
```sql
|
|
474
|
-
SELECT DISTINCT
|
|
1194
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=distinct-sql
|
|
1195
|
+
SELECT DISTINCT name
|
|
475
1196
|
FROM User;
|
|
476
1197
|
```
|
|
477
1198
|
|
|
@@ -482,151 +1203,329 @@ This method will explicitly list all the tables from the `$from` and `.join`. So
|
|
|
482
1203
|
|
|
483
1204
|
|
|
484
1205
|
#### Example - Single Table
|
|
485
|
-
```typescript
|
|
1206
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=all-single
|
|
486
1207
|
prisma.$from("User")
|
|
487
|
-
|
|
1208
|
+
.selectAll();
|
|
488
1209
|
```
|
|
489
1210
|
|
|
490
1211
|
##### SQL
|
|
491
1212
|
The resulting SQL will look like:
|
|
492
1213
|
|
|
493
|
-
```sql
|
|
494
|
-
SELECT
|
|
495
|
-
|
|
1214
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=all-single-sql
|
|
1215
|
+
SELECT
|
|
1216
|
+
id,
|
|
1217
|
+
email,
|
|
1218
|
+
name,
|
|
1219
|
+
age
|
|
1220
|
+
FROM User;
|
|
496
1221
|
```
|
|
497
1222
|
|
|
498
1223
|
#### Example - Join table
|
|
499
|
-
```typescript
|
|
1224
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=all-join
|
|
500
1225
|
prisma.$from("User")
|
|
501
|
-
|
|
502
|
-
|
|
1226
|
+
.join("Post", "authorId", "User.id")
|
|
1227
|
+
.selectAll();
|
|
503
1228
|
```
|
|
504
1229
|
|
|
505
1230
|
##### SQL
|
|
506
1231
|
The resulting SQL will look like:
|
|
507
1232
|
|
|
508
|
-
```sql
|
|
509
|
-
SELECT
|
|
510
|
-
|
|
511
|
-
|
|
1233
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=all-join-sql
|
|
1234
|
+
SELECT
|
|
1235
|
+
User.id AS `User.id`,
|
|
1236
|
+
User.email AS `User.email`,
|
|
1237
|
+
User.name AS `User.name`,
|
|
1238
|
+
User.age AS `User.age`,
|
|
1239
|
+
Post.id AS `Post.id`,
|
|
1240
|
+
Post.title AS `Post.title`,
|
|
1241
|
+
Post.content AS `Post.content`,
|
|
1242
|
+
Post.published AS `Post.published`,
|
|
1243
|
+
Post.authorId AS `Post.authorId`,
|
|
1244
|
+
Post.lastModifiedById AS `Post.lastModifiedById`
|
|
1245
|
+
FROM User
|
|
1246
|
+
JOIN Post ON Post.authorId = User.id;
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
#### `.selectAllOmit`
|
|
1250
|
+
|
|
1251
|
+
Like `.selectAll`, but excludes specific columns. Accepts `Table.column` or bare `column` references.
|
|
1252
|
+
|
|
1253
|
+
#### Example - Single Table
|
|
1254
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-all-omit.ts region=single-omit
|
|
1255
|
+
prisma.$from("User")
|
|
1256
|
+
.selectAllOmit(["User.email"]);
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
##### SQL
|
|
1260
|
+
```sql file=../usage-sqlite-v7/tests/readme/select-all-omit.ts region=single-omit-sql
|
|
1261
|
+
SELECT id, name, age FROM User;
|
|
1262
|
+
```
|
|
1263
|
+
|
|
1264
|
+
#### Example - Multiple Columns
|
|
1265
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-all-omit.ts region=multi-omit
|
|
1266
|
+
prisma.$from("User")
|
|
1267
|
+
.selectAllOmit(["User.email", "User.age"]);
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
#### Example - With Join
|
|
1271
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-all-omit.ts region=join-omit
|
|
1272
|
+
prisma.$from("User")
|
|
1273
|
+
.join("Post", "authorId", "User.id")
|
|
1274
|
+
.selectAllOmit(["User.email", "Post.content"]);
|
|
512
1275
|
```
|
|
513
1276
|
|
|
514
|
-
|
|
1277
|
+
> **Note:** `*` and `Table.*` are not valid arguments — use `Table.column` or bare `column` references.
|
|
515
1278
|
|
|
516
1279
|
#### `.select`
|
|
517
1280
|
|
|
518
|
-
You can supply either;
|
|
1281
|
+
You can supply either; `*`, `Table.*` OR `table.field` and then chain them together.
|
|
519
1282
|
|
|
520
1283
|
#### Example - `*`
|
|
521
|
-
```typescript
|
|
1284
|
+
```typescript file=../usage/tests/readme/select-star.ts region=example
|
|
522
1285
|
prisma.$from("User")
|
|
523
|
-
|
|
1286
|
+
.select("*");
|
|
524
1287
|
```
|
|
525
1288
|
|
|
526
1289
|
##### SQL
|
|
527
1290
|
The resulting SQL will look like:
|
|
528
1291
|
|
|
529
|
-
```sql
|
|
1292
|
+
```sql file=../usage/tests/readme/select-star.ts region=example-sql
|
|
530
1293
|
SELECT *
|
|
531
|
-
FROM User;
|
|
1294
|
+
FROM User;
|
|
1295
|
+
```
|
|
1296
|
+
|
|
1297
|
+
#### Example - `Table.*` (Single Table)
|
|
1298
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=table-star-single
|
|
1299
|
+
prisma.$from("User")
|
|
1300
|
+
.select("User.*");
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
##### SQL
|
|
1304
|
+
The resulting SQL will look like:
|
|
1305
|
+
|
|
1306
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=table-star-single-sql
|
|
1307
|
+
SELECT
|
|
1308
|
+
id,
|
|
1309
|
+
email,
|
|
1310
|
+
name,
|
|
1311
|
+
age
|
|
1312
|
+
FROM User;
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
#### Example - `Table.*` (With Join)
|
|
1316
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=table-star-join
|
|
1317
|
+
prisma.$from("User")
|
|
1318
|
+
.join("Post", "authorId", "User.id")
|
|
1319
|
+
.select("User.*")
|
|
1320
|
+
.select("Post.*");
|
|
1321
|
+
```
|
|
1322
|
+
|
|
1323
|
+
##### SQL
|
|
1324
|
+
The resulting SQL will look like:
|
|
1325
|
+
|
|
1326
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=table-star-join-sql
|
|
1327
|
+
SELECT
|
|
1328
|
+
User.id AS `User.id`,
|
|
1329
|
+
User.email AS `User.email`,
|
|
1330
|
+
User.name AS `User.name`,
|
|
1331
|
+
User.age AS `User.age`,
|
|
1332
|
+
Post.id AS `Post.id`,
|
|
1333
|
+
Post.title AS `Post.title`,
|
|
1334
|
+
Post.content AS `Post.content`,
|
|
1335
|
+
Post.published AS `Post.published`,
|
|
1336
|
+
Post.authorId AS `Post.authorId`,
|
|
1337
|
+
Post.lastModifiedById AS `Post.lastModifiedById`
|
|
1338
|
+
FROM User
|
|
1339
|
+
JOIN Post ON Post.authorId = User.id;
|
|
532
1340
|
```
|
|
533
1341
|
|
|
1342
|
+
> [!NOTE]
|
|
1343
|
+
> When using `Table.*` with joins, all columns are automatically aliased with the table name prefix to avoid column name conflicts.
|
|
1344
|
+
|
|
534
1345
|
#### Example - Chained
|
|
535
|
-
```typescript
|
|
1346
|
+
```typescript file=../usage/tests/readme/select-chained.ts region=example
|
|
536
1347
|
prisma.$from("User")
|
|
537
|
-
|
|
538
|
-
|
|
1348
|
+
.select("name")
|
|
1349
|
+
.select("email");
|
|
539
1350
|
```
|
|
540
1351
|
|
|
541
1352
|
##### SQL
|
|
542
1353
|
The resulting SQL will look like:
|
|
543
1354
|
|
|
544
|
-
```sql
|
|
1355
|
+
```sql file=../usage/tests/readme/select-chained.ts region=example-sql
|
|
545
1356
|
SELECT name, email
|
|
546
|
-
FROM User;
|
|
1357
|
+
FROM User;
|
|
547
1358
|
```
|
|
548
1359
|
|
|
549
1360
|
#### Example - Join + Chained
|
|
550
|
-
```typescript
|
|
1361
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=join-chained
|
|
551
1362
|
prisma.$from("User")
|
|
552
|
-
.join("Post", "authorId", "User.id")
|
|
1363
|
+
.join("Post", "authorId", "User.id")
|
|
553
1364
|
.select("name")
|
|
554
1365
|
.select("Post.title");
|
|
555
1366
|
```
|
|
556
1367
|
|
|
557
|
-
|
|
558
|
-
|
|
1368
|
+
##### SQL
|
|
1369
|
+
The resulting SQL will look like:
|
|
1370
|
+
|
|
1371
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=join-chained-sql
|
|
1372
|
+
SELECT name, title
|
|
1373
|
+
FROM User
|
|
1374
|
+
JOIN Post ON Post.authorId = User.id;
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
#### Example - Column Aliases
|
|
1378
|
+
```typescript file=../usage/tests/readme/select-column-alias.ts region=basic
|
|
1379
|
+
prisma.$from("User")
|
|
1380
|
+
.select("User.name", "username");
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
```typescript file=../usage/tests/readme/select-column-alias.ts region=multiple
|
|
1384
|
+
prisma.$from("User")
|
|
1385
|
+
.select("User.id", "userId")
|
|
1386
|
+
.select("User.email", "emailAddress");
|
|
1387
|
+
```
|
|
1388
|
+
|
|
1389
|
+
```typescript file=../usage/tests/readme/select-column-alias.ts region=mixed
|
|
1390
|
+
prisma.$from("User")
|
|
1391
|
+
.select("User.id")
|
|
1392
|
+
.select("User.name", "username")
|
|
1393
|
+
.select("User.email");
|
|
1394
|
+
```
|
|
559
1395
|
|
|
560
1396
|
##### SQL
|
|
561
1397
|
The resulting SQL will look like:
|
|
562
1398
|
|
|
563
|
-
```sql
|
|
564
|
-
SELECT name
|
|
565
|
-
FROM User;
|
|
1399
|
+
```sql file=../usage/tests/readme/select-column-alias.ts region=basic-sql
|
|
1400
|
+
SELECT User.name AS `username`
|
|
1401
|
+
FROM User;
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
```sql file=../usage/tests/readme/select-column-alias.ts region=multiple-sql
|
|
1405
|
+
SELECT
|
|
1406
|
+
User.id AS `userId`,
|
|
1407
|
+
User.email AS `emailAddress`
|
|
1408
|
+
FROM User;
|
|
1409
|
+
```
|
|
1410
|
+
|
|
1411
|
+
```sql file=../usage/tests/readme/select-column-alias.ts region=mixed-sql
|
|
1412
|
+
SELECT
|
|
1413
|
+
id,
|
|
1414
|
+
User.name AS `username`,
|
|
1415
|
+
email
|
|
1416
|
+
FROM User;
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
#### Example - Aliases with Joins
|
|
1420
|
+
```typescript file=../usage/tests/readme/select-advanced.ts region=aliases-joins
|
|
1421
|
+
prisma.$from("User")
|
|
1422
|
+
.join("Post", "authorId", "User.id")
|
|
1423
|
+
.select("User.name", "authorName")
|
|
1424
|
+
.select("Post.title", "postTitle");
|
|
1425
|
+
```
|
|
1426
|
+
|
|
1427
|
+
##### SQL
|
|
1428
|
+
The resulting SQL will look like:
|
|
1429
|
+
|
|
1430
|
+
```sql file=../usage/tests/readme/select-advanced.ts region=aliases-joins-sql
|
|
1431
|
+
SELECT
|
|
1432
|
+
User.name AS `authorName`,
|
|
1433
|
+
Post.title AS `postTitle`
|
|
1434
|
+
FROM User
|
|
1435
|
+
JOIN Post ON Post.authorId = User.id;
|
|
566
1436
|
```
|
|
567
1437
|
|
|
1438
|
+
> [!NOTE]
|
|
1439
|
+
> When using column aliases, you can reference the alias in `ORDER BY` clauses. The returned type will use the alias names instead of the original column names.
|
|
1440
|
+
|
|
568
1441
|
### Having
|
|
569
1442
|
|
|
570
|
-
`.having`
|
|
1443
|
+
`.having` accepts two overloads — a criteria object (same syntax as [`.where`](#where)) or a fn callback for SQL expressions and aggregate functions.
|
|
571
1444
|
|
|
572
|
-
####
|
|
1445
|
+
#### Criteria object
|
|
573
1446
|
|
|
574
|
-
```typescript
|
|
1447
|
+
```typescript file=../shared-tests/readme/having.ts region=with-groupby
|
|
575
1448
|
prisma.$from("User")
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
1449
|
+
.join("Post", "authorId", "User.id")
|
|
1450
|
+
.groupBy(["name", "Post.content"])
|
|
1451
|
+
.having({
|
|
1452
|
+
"User.name": {
|
|
1453
|
+
"op": "LIKE",
|
|
1454
|
+
"value": "bob%"
|
|
1455
|
+
}
|
|
1456
|
+
})
|
|
1457
|
+
.select("*");
|
|
584
1458
|
```
|
|
585
1459
|
|
|
586
|
-
```
|
|
1460
|
+
```sql file=../shared-tests/readme/having.ts region=with-groupby-sql
|
|
1461
|
+
SELECT * FROM User JOIN Post ON Post.authorId = User.id GROUP BY name, Post.content HAVING User.name LIKE 'bob%';
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
#### fn overload — aggregate functions
|
|
1465
|
+
|
|
1466
|
+
Pass a callback returning `Array<[SQLExpr<T>, condition]>` pairs. The callback receives the full select-fn context, including all aggregate and string functions.
|
|
1467
|
+
|
|
1468
|
+
##### `countAll()` with comparison op
|
|
1469
|
+
|
|
1470
|
+
```typescript file=../shared-tests/readme/having.ts region=agg-fn-tuple-countall
|
|
587
1471
|
prisma.$from("User")
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
"value": "stuart%"
|
|
593
|
-
}
|
|
594
|
-
});
|
|
1472
|
+
.join("Post", "authorId", "User.id")
|
|
1473
|
+
.groupBy(["User.name"])
|
|
1474
|
+
.having(({ countAll }) => [[countAll(), { op: '>', value: 1 }]])
|
|
1475
|
+
.select("User.name")
|
|
595
1476
|
```
|
|
596
1477
|
|
|
1478
|
+
```sql file=../shared-tests/readme/having.ts region=agg-fn-tuple-countall-sql
|
|
1479
|
+
SELECT name FROM User JOIN Post ON Post.authorId = User.id GROUP BY User.name HAVING COUNT(*) > 1;
|
|
1480
|
+
```
|
|
597
1481
|
|
|
598
|
-
#####
|
|
1482
|
+
##### `count(col)` with bigint value
|
|
599
1483
|
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
1484
|
+
```typescript file=../shared-tests/readme/having.ts region=agg-fn-tuple-count
|
|
1485
|
+
prisma.$from("User")
|
|
1486
|
+
.join("Post", "authorId", "User.id")
|
|
1487
|
+
.groupBy(["User.name"])
|
|
1488
|
+
.having(({ count }) => [[count('User.id'), { op: '>=', value: 2n }]])
|
|
1489
|
+
.select("User.name")
|
|
605
1490
|
```
|
|
606
1491
|
|
|
607
|
-
```
|
|
608
|
-
FROM User
|
|
609
|
-
JOIN Post ON authorId = User.id
|
|
610
|
-
HAVING (User.name LIKE 'stuart%');
|
|
1492
|
+
```sql file=../shared-tests/readme/having.ts region=agg-fn-tuple-count-sql
|
|
1493
|
+
SELECT name FROM User JOIN Post ON Post.authorId = User.id GROUP BY User.name HAVING COUNT(User.id) >= 2;
|
|
611
1494
|
```
|
|
612
1495
|
|
|
1496
|
+
##### String expr — `upper(col)` LIKE
|
|
1497
|
+
|
|
1498
|
+
```typescript file=../shared-tests/readme/having.ts region=agg-fn-string-upper
|
|
1499
|
+
prisma.$from("User")
|
|
1500
|
+
.join("Post", "authorId", "User.id")
|
|
1501
|
+
.groupBy(["User.name"])
|
|
1502
|
+
.having(({ upper }) => [[upper('User.name'), { op: 'LIKE', value: 'John%' }]])
|
|
1503
|
+
.select("User.name")
|
|
1504
|
+
```
|
|
1505
|
+
|
|
1506
|
+
```sql file=../shared-tests/readme/having.ts region=agg-fn-string-upper-sql
|
|
1507
|
+
SELECT name FROM User JOIN Post ON Post.authorId = User.id GROUP BY User.name HAVING UPPER(User.name) LIKE 'John%';
|
|
1508
|
+
```
|
|
1509
|
+
|
|
1510
|
+
Multiple pairs in one `.having()` call are AND-ed together. `.having()` can also be chained — each call appends an AND condition.
|
|
1511
|
+
|
|
613
1512
|
### Order By
|
|
614
1513
|
|
|
615
1514
|
`.orderBy`, takes an array of column names, with the optional suffix of `ASC` or `DESC`.
|
|
616
1515
|
|
|
617
1516
|
#### Example
|
|
618
1517
|
|
|
619
|
-
```typescript
|
|
1518
|
+
```typescript file=../usage/tests/readme/orderby.ts region=basic
|
|
620
1519
|
prisma.$from("User")
|
|
621
1520
|
.join("Post", "authorId", "User.id")
|
|
622
|
-
.orderBy(["name", "Post.content DESC"]);
|
|
1521
|
+
.orderBy(["name", "Post.content DESC"]);
|
|
623
1522
|
```
|
|
624
1523
|
|
|
625
1524
|
##### SQL
|
|
626
1525
|
|
|
627
|
-
```sql
|
|
1526
|
+
```sql file=../usage/tests/readme/orderby.ts region=basic-sql
|
|
628
1527
|
FROM User
|
|
629
|
-
JOIN Post ON authorId = User.id
|
|
1528
|
+
JOIN Post ON Post.authorId = User.id
|
|
630
1529
|
ORDER BY name, Post.content DESC;
|
|
631
1530
|
```
|
|
632
1531
|
|
|
@@ -636,7 +1535,7 @@ ORDER BY name, Post.content DESC;
|
|
|
636
1535
|
|
|
637
1536
|
#### Example
|
|
638
1537
|
|
|
639
|
-
```typescript
|
|
1538
|
+
```typescript file=../usage/tests/readme/pagination.ts region=limit
|
|
640
1539
|
prisma.$from("User")
|
|
641
1540
|
.join("Post", "authorId", "User.id")
|
|
642
1541
|
.limit(1);
|
|
@@ -644,9 +1543,9 @@ prisma.$from("User")
|
|
|
644
1543
|
|
|
645
1544
|
##### SQL
|
|
646
1545
|
|
|
647
|
-
```
|
|
1546
|
+
```sql file=../usage/tests/readme/pagination.ts region=limit-sql
|
|
648
1547
|
FROM User
|
|
649
|
-
JOIN Post ON authorId = User.id
|
|
1548
|
+
JOIN Post ON Post.authorId = User.id
|
|
650
1549
|
LIMIT 1;
|
|
651
1550
|
```
|
|
652
1551
|
|
|
@@ -655,71 +1554,364 @@ LIMIT 1;
|
|
|
655
1554
|
`.offSet`, the number of rows to skip. Requires `.limit` to have been used first.
|
|
656
1555
|
|
|
657
1556
|
#### Example
|
|
658
|
-
```typescript
|
|
1557
|
+
```typescript file=../usage/tests/readme/pagination.ts region=offset
|
|
659
1558
|
prisma.$from("User")
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
1559
|
+
.join("Post", "authorId", "User.id")
|
|
1560
|
+
.limit(1)
|
|
1561
|
+
.offset(1);
|
|
663
1562
|
```
|
|
664
1563
|
|
|
665
1564
|
##### SQL
|
|
666
1565
|
|
|
667
|
-
```
|
|
1566
|
+
```sql file=../usage/tests/readme/pagination.ts region=offset-sql
|
|
668
1567
|
FROM User
|
|
669
|
-
JOIN Post ON authorId = User.id
|
|
1568
|
+
JOIN Post ON Post.authorId = User.id
|
|
670
1569
|
LIMIT 1
|
|
671
|
-
OFFSET 1
|
|
1570
|
+
OFFSET 1;
|
|
672
1571
|
```
|
|
673
1572
|
|
|
674
|
-
##
|
|
1573
|
+
## Select Functions
|
|
675
1574
|
|
|
676
|
-
|
|
677
|
-
- Support Select Functions
|
|
678
|
-
- [Aggregation #4](https://github.com/adrianbrowning/prisma-ts-select/issues/4)
|
|
679
|
-
- [String #5](https://github.com/adrianbrowning/prisma-ts-select/issues/5)
|
|
680
|
-
- [Date & Time #6](https://github.com/adrianbrowning/prisma-ts-select/issues/6)
|
|
681
|
-
- [Math #7](https://github.com/adrianbrowning/prisma-ts-select/issues/7)
|
|
682
|
-
- [Control Flow #8](https://github.com/adrianbrowning/prisma-ts-select/issues/8)
|
|
683
|
-
- [JSON #9](https://github.com/adrianbrowning/prisma-ts-select/issues/9)
|
|
684
|
-
- [Support a `Many-To-Many` join #19](https://github.com/adrianbrowning/prisma-ts-select/issues/19)
|
|
685
|
-
- [Select column alias #27](https://github.com/adrianbrowning/prisma-ts-select/issues/27)
|
|
686
|
-
- [Table name alias #28](https://github.com/adrianbrowning/prisma-ts-select/issues/28)
|
|
687
|
-
- [whereRaw supporting Prisma.sql](https://github.com/adrianbrowning/prisma-ts-select/issues/29)
|
|
1575
|
+
Pass a callback to `.select()` to use SQL expressions and aggregate functions. The callback receives a context object with all available functions for the active dialect.
|
|
688
1576
|
|
|
689
|
-
|
|
690
|
-
Changelog is available [here](https://github.com/adrianbrowning/prisma-ts-select/releases). We use [semantic versioning](https://semver.org/) for versioning.
|
|
1577
|
+
### Shared (all dialects)
|
|
691
1578
|
|
|
692
|
-
|
|
693
|
-
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
1579
|
+
#### `lit(value)` — SQL literal
|
|
694
1580
|
|
|
695
|
-
|
|
1581
|
+
Produces a typed SQL literal from a JS value.
|
|
696
1582
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
- missing @deprecated
|
|
703
|
-
- ts-exptect-error - might not be needed
|
|
704
|
-
- GetColsFromTableType missing ts-expect-error - might not be needed
|
|
705
|
-
- DB needs to be in the same file.
|
|
1583
|
+
##### Example
|
|
1584
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=lit-string
|
|
1585
|
+
prisma.$from("User")
|
|
1586
|
+
.select(({ lit }) => lit("hello"), "greeting");
|
|
1587
|
+
```
|
|
706
1588
|
|
|
1589
|
+
#### `countAll()` — COUNT(*)
|
|
707
1590
|
|
|
1591
|
+
The most common aggregate. Always produces `COUNT(*)`.
|
|
708
1592
|
|
|
709
|
-
|
|
1593
|
+
##### Example
|
|
1594
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=count-all
|
|
1595
|
+
prisma.$from("User")
|
|
1596
|
+
.select(({ countAll }) => countAll(), "total");
|
|
1597
|
+
```
|
|
710
1598
|
|
|
711
|
-
|
|
1599
|
+
##### SQL
|
|
1600
|
+
```sql file=../usage-sqlite-v7/tests/readme/select-fns.ts region=count-all-sql
|
|
1601
|
+
SELECT COUNT(*) AS `total` FROM User;
|
|
1602
|
+
```
|
|
712
1603
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
1604
|
+
#### `count(col)` — COUNT(col)
|
|
1605
|
+
|
|
1606
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=count-col
|
|
1607
|
+
prisma.$from("User")
|
|
1608
|
+
.select(({ count }) => count("User.id"), "cnt");
|
|
716
1609
|
```
|
|
717
1610
|
|
|
718
|
-
|
|
1611
|
+
#### `countDistinct(col)` — COUNT(DISTINCT col)
|
|
1612
|
+
|
|
1613
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=count-distinct
|
|
1614
|
+
prisma.$from("User")
|
|
1615
|
+
.select(({ countDistinct }) => countDistinct("User.id"), "cnt");
|
|
1616
|
+
```
|
|
719
1617
|
|
|
720
|
-
|
|
1618
|
+
#### `sum(col)` / `avg(col)` / `min(col)` / `max(col)`
|
|
721
1619
|
|
|
1620
|
+
Standard numeric aggregates. **Return types vary by dialect** — `sum` and `avg` return `Decimal` on MySQL (matching Prisma's numeric precision model), `number` on SQLite and PostgreSQL. `min`/`max` always return `T | null` (NULL for empty sets) where `T` is the column's TypeScript type.
|
|
722
1621
|
|
|
723
|
-
|
|
1622
|
+
| Function | SQLite | MySQL | PostgreSQL |
|
|
1623
|
+
|---|---|---|---|
|
|
1624
|
+
| `sum(col)` | `number` | `Decimal` | `number` |
|
|
1625
|
+
| `avg(col)` | `number` | `Decimal` | `number` |
|
|
1626
|
+
| `min(col)` | `T \| null` | `T \| null` | `T \| null` |
|
|
1627
|
+
| `max(col)` | `T \| null` | `T \| null` | `T \| null` |
|
|
1628
|
+
|
|
1629
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=sum
|
|
1630
|
+
prisma.$from("User")
|
|
1631
|
+
.select(({ sum }) => sum("User.age"), "total");
|
|
1632
|
+
```
|
|
1633
|
+
|
|
1634
|
+
#### String Functions (all dialects)
|
|
1635
|
+
|
|
1636
|
+
| Function | SQL | Returns |
|
|
1637
|
+
|---|---|---|
|
|
1638
|
+
| `upper(col)` | `UPPER(col)` | `string` |
|
|
1639
|
+
| `lower(col)` | `LOWER(col)` | `string` |
|
|
1640
|
+
| `length(col)` | `LENGTH(col)` | `number` |
|
|
1641
|
+
| `trim(col)` | `TRIM(col)` | `string` |
|
|
1642
|
+
| `ltrim(col)` | `LTRIM(col)` | `string` |
|
|
1643
|
+
| `rtrim(col)` | `RTRIM(col)` | `string` |
|
|
1644
|
+
| `replace(col, from, to)` | `REPLACE(col, 'from', 'to')` | `string` |
|
|
1645
|
+
|
|
1646
|
+
> **Note:** MySQL `LENGTH()` returns byte-length (not char-length). For character-length on multi-byte strings use a dialect-specific fn.
|
|
1647
|
+
|
|
1648
|
+
#### DateTime Functions (all dialects)
|
|
1649
|
+
|
|
1650
|
+
All dialects provide these functions. Return types differ for `year`/`month`/`day`/`hour`/`minute`/`second` — see note below.
|
|
1651
|
+
|
|
1652
|
+
| Function | SQL (MySQL / PG / SQLite) | Returns |
|
|
1653
|
+
|---|---|---|
|
|
1654
|
+
| `now()` | `NOW()` / `NOW()` / `datetime('now')` | `Date` |
|
|
1655
|
+
| `curDate()` | `CURDATE()` / `CURRENT_DATE` / `date('now')` | `Date` |
|
|
1656
|
+
| `year(col)` | `YEAR(col)` / `EXTRACT(YEAR FROM col)::integer` / `strftime('%Y', col)` | `number` (SQLite: `string`) |
|
|
1657
|
+
| `month(col)` | `MONTH(col)` / `EXTRACT(MONTH FROM col)::integer` / `strftime('%m', col)` | `number` (SQLite: `string`) |
|
|
1658
|
+
| `day(col)` | `DAY(col)` / `EXTRACT(DAY FROM col)::integer` / `strftime('%d', col)` | `number` (SQLite: `string`) |
|
|
1659
|
+
| `hour(col)` | `HOUR(col)` / `EXTRACT(HOUR FROM col)::integer` / `strftime('%H', col)` | `number` (SQLite: `string`) |
|
|
1660
|
+
| `minute(col)` | `MINUTE(col)` / `EXTRACT(MINUTE FROM col)::integer` / `strftime('%M', col)` | `number` (SQLite: `string`) |
|
|
1661
|
+
| `second(col)` | `SECOND(col)` / `EXTRACT(SECOND FROM col)::integer` / `strftime('%S', col)` | `number` (SQLite: `string`) |
|
|
1662
|
+
|
|
1663
|
+
> **Note:** `year`, `month`, `day`, `hour`, `minute`, and `second` return `string` on SQLite because `strftime()` always returns text (e.g. `'2024'`, `'03'`). MySQL and PostgreSQL return `number`.
|
|
1664
|
+
|
|
1665
|
+
DateTime column args also accept `SQLExpr<Date>`, enabling composition:
|
|
1666
|
+
|
|
1667
|
+
```typescript
|
|
1668
|
+
prisma.$from("Post").select(({ year, now }) => year(now()), "y");
|
|
1669
|
+
```
|
|
1670
|
+
|
|
1671
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=upper
|
|
1672
|
+
prisma.$from("User")
|
|
1673
|
+
.select(({ upper }) => upper("User.name"), "uname");
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1676
|
+
String fns accept a `SQLExpr<string>` as input, enabling composition:
|
|
1677
|
+
|
|
1678
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=lower
|
|
1679
|
+
prisma.$from("User")
|
|
1680
|
+
.select(({ lower }) => lower("User.name"), "lname");
|
|
1681
|
+
```
|
|
1682
|
+
|
|
1683
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=replace
|
|
1684
|
+
prisma.$from("User")
|
|
1685
|
+
.select(({ replace }) => replace("User.email", "@example.com", ""), "handle");
|
|
1686
|
+
```
|
|
1687
|
+
|
|
1688
|
+
#### Math Functions (all dialects)
|
|
1689
|
+
|
|
1690
|
+
| Function | SQL | Returns |
|
|
1691
|
+
|---|---|---|
|
|
1692
|
+
| `abs(col)` | `ABS(col)` | `number` |
|
|
1693
|
+
| `ceil(col)` | `CEIL(col)` | `number` |
|
|
1694
|
+
| `floor(col)` | `FLOOR(col)` | `number` |
|
|
1695
|
+
| `round(col, decimals?)` | `ROUND(col)` / `ROUND(col, n)` | `number` |
|
|
1696
|
+
| `power(base, exp)` | `POWER(base, exp)` | `number` |
|
|
1697
|
+
| `sqrt(col)` | `SQRT(col)` | `number` |
|
|
1698
|
+
| `mod(col, divisor)` | `MOD(col, divisor)` | `number` |
|
|
1699
|
+
| `sign(col)` | `SIGN(col)` | `number` |
|
|
1700
|
+
| `exp(col)` | `EXP(col)` | `number` |
|
|
1701
|
+
|
|
1702
|
+
Math fns accept `SQLExpr<number>` or a column reference, enabling composition:
|
|
1703
|
+
|
|
1704
|
+
```typescript
|
|
1705
|
+
// Absolute value of a literal
|
|
1706
|
+
prisma.$from("User")
|
|
1707
|
+
.select(({ abs, lit }) => abs(lit(-5)), "absVal");
|
|
1708
|
+
|
|
1709
|
+
// Round to 2 decimal places
|
|
1710
|
+
prisma.$from("User")
|
|
1711
|
+
.select(({ round, lit }) => round(lit(4.567), 2), "val");
|
|
1712
|
+
|
|
1713
|
+
// Compose: sqrt(power(x, 2))
|
|
1714
|
+
prisma.$from("User")
|
|
1715
|
+
.select(({ sqrt, power }) => sqrt(power("User.age", 2)), "val");
|
|
1716
|
+
```
|
|
1717
|
+
|
|
1718
|
+
#### Control Flow Functions (all dialects)
|
|
1719
|
+
|
|
1720
|
+
| Function | SQL | Returns |
|
|
1721
|
+
|---|---|---|
|
|
1722
|
+
| `cond(criteria)` | *(WhereCriteria → SQL condition string)* | `SQLExpr<boolean>` |
|
|
1723
|
+
| `coalesce(...args)` | `COALESCE(a, b, ...)` | `SQLExpr<T>` |
|
|
1724
|
+
| `nullif(expr1, expr2)` | `NULLIF(a, b)` | `SQLExpr<T \| null>` |
|
|
1725
|
+
| `caseWhen(cases, elseVal?)` | `CASE WHEN ... THEN ... END` | `SQLExpr<T \| null>` |
|
|
1726
|
+
|
|
1727
|
+
`cond()` converts a `WhereCriteria` object into a `SQLExpr<unknown>` — useful when you need a condition expression outside of a dedicated function. Note: `$if()`/`iif()` and `caseWhen()` all accept `WhereCriteria` directly, so `cond()` is rarely needed.
|
|
1728
|
+
|
|
1729
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns-control-flow.ts region=coalesce
|
|
1730
|
+
prisma.$from("User")
|
|
1731
|
+
.select(({ coalesce, lit }) => coalesce("User.email", lit("unknown")), "contact")
|
|
1732
|
+
```
|
|
1733
|
+
|
|
1734
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns-control-flow.ts region=nullif
|
|
1735
|
+
prisma.$from("User")
|
|
1736
|
+
.select(({ nullif, lit }) => nullif(lit(0), lit(0)), "val")
|
|
1737
|
+
```
|
|
1738
|
+
|
|
1739
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns-control-flow.ts region=case-when
|
|
1740
|
+
prisma.$from("User")
|
|
1741
|
+
.select(({ caseWhen, lit }) => caseWhen([
|
|
1742
|
+
{ when: { age: { op: ">=", value: 18 } }, then: lit("adult") },
|
|
1743
|
+
], lit("minor")), "status")
|
|
1744
|
+
```
|
|
1745
|
+
|
|
1746
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns-control-flow.ts region=cond
|
|
1747
|
+
prisma.$from("User")
|
|
1748
|
+
.select(({ cond }) => cond({ age: { op: ">", value: 0 } }), "flag")
|
|
1749
|
+
```
|
|
1750
|
+
|
|
1751
|
+
#### Combining with `.groupBy()`
|
|
1752
|
+
|
|
1753
|
+
```typescript file=../usage-sqlite-v7/tests/readme/select-fns.ts region=count-groupby
|
|
1754
|
+
prisma.$from("User")
|
|
1755
|
+
.join("Post", "authorId", "User.id")
|
|
1756
|
+
.groupBy(["User.name"])
|
|
1757
|
+
.select("User.name")
|
|
1758
|
+
.select(({ countAll }) => countAll(), "postCount");
|
|
1759
|
+
```
|
|
1760
|
+
|
|
1761
|
+
##### SQL
|
|
1762
|
+
```sql
|
|
1763
|
+
SELECT User.name, COUNT(*) AS `postCount`
|
|
1764
|
+
FROM User
|
|
1765
|
+
JOIN Post ON Post.authorId = User.id
|
|
1766
|
+
GROUP BY User.name;
|
|
1767
|
+
```
|
|
1768
|
+
|
|
1769
|
+
---
|
|
1770
|
+
|
|
1771
|
+
### MySQL-specific
|
|
1772
|
+
|
|
1773
|
+
| Function | SQL | Returns |
|
|
1774
|
+
|---|---|---|
|
|
1775
|
+
| `groupConcat(col, sep?)` | `GROUP_CONCAT(col SEPARATOR sep)` | `string` |
|
|
1776
|
+
| `bitAnd(col)` | `BIT_AND(col)` | `number` |
|
|
1777
|
+
| `bitOr(col)` | `BIT_OR(col)` | `number` |
|
|
1778
|
+
| `bitXor(col)` | `BIT_XOR(col)` | `number` |
|
|
1779
|
+
| `stddev(col)` | `STDDEV(col)` | `number` |
|
|
1780
|
+
| `stddevSamp(col)` | `STDDEV_SAMP(col)` | `number` |
|
|
1781
|
+
| `variance(col)` | `VARIANCE(col)` | `number` |
|
|
1782
|
+
| `varSamp(col)` | `VAR_SAMP(col)` | `number` |
|
|
1783
|
+
| `jsonArrayAgg(col)` | `JSON_ARRAYAGG(col)` | `JSONValue` |
|
|
1784
|
+
| `jsonObjectAgg(key, val)` | `JSON_OBJECTAGG(key, val)` | `JSONValue` |
|
|
1785
|
+
| `concat(...cols)` | `CONCAT(a, b, ...)` | `string` |
|
|
1786
|
+
| `substring(col, start, len?)` | `SUBSTRING(col, start, len)` | `string` |
|
|
1787
|
+
| `left(col, n)` | `LEFT(col, n)` | `string` |
|
|
1788
|
+
| `right(col, n)` | `RIGHT(col, n)` | `string` |
|
|
1789
|
+
| `repeat(col, n)` | `REPEAT(col, n)` | `string` |
|
|
1790
|
+
| `reverse(col)` | `REVERSE(col)` | `string` |
|
|
1791
|
+
| `lpad(col, len, pad)` | `LPAD(col, len, 'pad')` | `string` |
|
|
1792
|
+
| `rpad(col, len, pad)` | `RPAD(col, len, 'pad')` | `string` |
|
|
1793
|
+
| `locate(substr, col)` | `LOCATE('substr', col)` | `number` |
|
|
1794
|
+
| `space(n)` | `SPACE(n)` | `string` |
|
|
1795
|
+
| `$if(cond, trueVal, falseVal)` | `IF(cond, a, b)` | `T` |
|
|
1796
|
+
| `ifNull(col, fallback)` | `IFNULL(col, fallback)` | `NonNullable<T>` |
|
|
1797
|
+
| `greatest(...args)` | `GREATEST(a, b, ...)` | `T \| null` |
|
|
1798
|
+
| `least(...args)` | `LEAST(a, b, ...)` | `T \| null` |
|
|
1799
|
+
| `dateAdd(col, n, unit)` | `DATE_ADD(col, INTERVAL n unit)` | `Date` |
|
|
1800
|
+
| `dateSub(col, n, unit)` | `DATE_SUB(col, INTERVAL n unit)` | `Date` |
|
|
1801
|
+
| `dateFormat(col, fmt)` | `DATE_FORMAT(col, 'fmt')` | `string` |
|
|
1802
|
+
| `dateDiff(d1, d2)` | `DATEDIFF(d1, d2)` | `number` |
|
|
1803
|
+
| `quarter(col)` | `QUARTER(col)` | `number` |
|
|
1804
|
+
| `weekOfYear(col)` | `WEEKOFYEAR(col)` | `number` |
|
|
1805
|
+
| `dayName(col)` | `DAYNAME(col)` | `string` |
|
|
1806
|
+
| `lastDay(col)` | `LAST_DAY(col)` | `Date` |
|
|
1807
|
+
| `pi()` | `PI()` | `number` |
|
|
1808
|
+
| `ln(x)` | `LN(x)` | `number` |
|
|
1809
|
+
| `log(x)` | `LOG(x)` | `number` |
|
|
1810
|
+
| `log2(x)` | `LOG2(x)` | `number` |
|
|
1811
|
+
| `log10(x)` | `LOG10(x)` | `number` |
|
|
1812
|
+
| `truncate(x, n)` | `TRUNCATE(x, n)` | `number` |
|
|
1813
|
+
| `rand(seed?)` | `RAND()` / `RAND(seed)` | `number` |
|
|
1814
|
+
|
|
1815
|
+
> **Note:** MySQL `LOG(x)` is natural log (ln). `rand()` returns a float in [0, 1).
|
|
1816
|
+
|
|
1817
|
+
`unit` is one of: `'MICROSECOND' | 'SECOND' | 'MINUTE' | 'HOUR' | 'DAY' | 'WEEK' | 'MONTH' | 'QUARTER' | 'YEAR'`
|
|
1818
|
+
|
|
1819
|
+
> **Note:** `jsonArrayAgg` and `jsonObjectAgg` require MySQL 5.7.22+.
|
|
1820
|
+
|
|
1821
|
+
---
|
|
1822
|
+
|
|
1823
|
+
### PostgreSQL-specific
|
|
1824
|
+
|
|
1825
|
+
| Function | SQL | Returns |
|
|
1826
|
+
|---|---|---|
|
|
1827
|
+
| `greatest(...args)` | `GREATEST(a, b, ...)` | `T` |
|
|
1828
|
+
| `least(...args)` | `LEAST(a, b, ...)` | `T` |
|
|
1829
|
+
| `stringAgg(col, sep)` | `STRING_AGG(col, sep)` | `string` |
|
|
1830
|
+
| `arrayAgg(col)` | `ARRAY_AGG(col)` | `unknown[]` |
|
|
1831
|
+
| `stddevPop(col)` | `STDDEV_POP(col)` | `number` |
|
|
1832
|
+
| `stddevSamp(col)` | `STDDEV_SAMP(col)` | `number` |
|
|
1833
|
+
| `varPop(col)` | `VAR_POP(col)` | `number` |
|
|
1834
|
+
| `varSamp(col)` | `VAR_SAMP(col)` | `number` |
|
|
1835
|
+
| `boolAnd(col)` | `BOOL_AND(col)` | `boolean` |
|
|
1836
|
+
| `boolOr(col)` | `BOOL_OR(col)` | `boolean` |
|
|
1837
|
+
| `jsonAgg(col)` | `JSON_AGG(col)` | `JSONValue[]` |
|
|
1838
|
+
| `bitAnd(col)` | `BIT_AND(col)` | `number` |
|
|
1839
|
+
| `bitOr(col)` | `BIT_OR(col)` | `number` |
|
|
1840
|
+
| `jsonObjectAgg(key, val)` | `JSON_OBJECT_AGG(key, val)` | `JSONValue` |
|
|
1841
|
+
| `concat(...cols)` | `CONCAT(a, b, ...)` | `string` |
|
|
1842
|
+
| `substring(col, start, len?)` | `SUBSTRING(col, start, len)` | `string` |
|
|
1843
|
+
| `left(col, n)` | `LEFT(col, n)` | `string` |
|
|
1844
|
+
| `right(col, n)` | `RIGHT(col, n)` | `string` |
|
|
1845
|
+
| `repeat(col, n)` | `REPEAT(col, n)` | `string` |
|
|
1846
|
+
| `reverse(col)` | `REVERSE(col)` | `string` |
|
|
1847
|
+
| `lpad(col, len, pad)` | `LPAD(col, len, 'pad')` | `string` |
|
|
1848
|
+
| `rpad(col, len, pad)` | `RPAD(col, len, 'pad')` | `string` |
|
|
1849
|
+
| `initcap(col)` | `INITCAP(col)` | `string` |
|
|
1850
|
+
| `strpos(col, substr)` | `STRPOS(col, 'substr')` | `number` |
|
|
1851
|
+
| `splitPart(col, delimiter, field)` | `SPLIT_PART(col, 'delimiter', field)` | `string` |
|
|
1852
|
+
| `btrim(col, chars?)` | `BTRIM(col)` / `BTRIM(col, 'chars')` | `string` |
|
|
1853
|
+
| `md5(col)` | `MD5(col)` | `string` |
|
|
1854
|
+
| `extract(field, col)` | `EXTRACT(field FROM col)` | `number` |
|
|
1855
|
+
| `dateTrunc(unit, col)` | `DATE_TRUNC('unit', col)` | `Date` |
|
|
1856
|
+
| `age(ts1, ts2?)` | `AGE(ts1)` / `AGE(ts1, ts2)` | `string` (PG `interval` mapped to string) |
|
|
1857
|
+
| `toDate(text, fmt)` | `TO_DATE(text, 'fmt')` | `Date` |
|
|
1858
|
+
| `pi()` | `PI()` | `number` |
|
|
1859
|
+
| `ln(x)` | `LN(x)` | `number` |
|
|
1860
|
+
| `log(x)` | `LOG(x)` | `number` |
|
|
1861
|
+
| `logBase(base, x)` | `LOG(base, x)` | `number` |
|
|
1862
|
+
| `trunc(x, n?)` | `TRUNC(x)` / `TRUNC(x, n)` | `number` |
|
|
1863
|
+
| `div(x, y)` | `DIV(x, y)` | `number` |
|
|
1864
|
+
| `random()` | `RANDOM()` | `number` |
|
|
1865
|
+
|
|
1866
|
+
> **Note:** PG `LOG(x)` is log base 10 (unlike MySQL where it is natural log). `random()` returns a float in [0, 1).
|
|
1867
|
+
|
|
1868
|
+
`field` for `extract` is one of: `'YEAR' | 'MONTH' | 'DAY' | 'HOUR' | 'MINUTE' | 'SECOND' | 'DOW' | 'DOY' | 'EPOCH' | 'WEEK' | 'QUARTER'`
|
|
1869
|
+
|
|
1870
|
+
`unit` for `dateTrunc` is one of: `'microseconds' | 'milliseconds' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' | 'decade' | 'century' | 'millennium'`
|
|
1871
|
+
|
|
1872
|
+
---
|
|
1873
|
+
|
|
1874
|
+
### SQLite-specific
|
|
1875
|
+
|
|
1876
|
+
| Function | SQL | Returns |
|
|
1877
|
+
|---|---|---|
|
|
1878
|
+
| `iif(cond, trueVal, falseVal)` | `IIF(cond, a, b)` | `T` |
|
|
1879
|
+
| `ifNull(col, fallback)` | `IFNULL(col, fallback)` | `NonNullable<T>` |
|
|
1880
|
+
| `groupConcat(col, sep?)` | `GROUP_CONCAT(col, sep)` | `string` |
|
|
1881
|
+
| `total(col)` | `TOTAL(col)` | `number` |
|
|
1882
|
+
| `concat(...cols)` | `a \|\| b \|\| ...` | `string` |
|
|
1883
|
+
| `substr(col, start, len?)` | `SUBSTR(col, start, len)` | `string` |
|
|
1884
|
+
| `instr(col, substr)` | `INSTR(col, 'substr')` | `number` |
|
|
1885
|
+
| `char(...codes)` | `CHAR(n1, n2, ...)` | `string` |
|
|
1886
|
+
| `hex(col)` | `HEX(col)` | `string` |
|
|
1887
|
+
| `unicode(col)` | `UNICODE(col)` | `number` |
|
|
1888
|
+
| `strftime(fmt, col)` | `strftime('fmt', col)` | `string` |
|
|
1889
|
+
| `julianday(col)` | `julianday(col)` | `number` |
|
|
1890
|
+
| `date(col)` | `date(col)` | `string` |
|
|
1891
|
+
| `datetime(col)` | `datetime(col)` | `string` |
|
|
1892
|
+
| `random()` | `RANDOM()` | `number` |
|
|
1893
|
+
| `log(x)` | `LOG(x)` | `number` |
|
|
1894
|
+
| `log2(x)` | `LOG2(x)` | `number` |
|
|
1895
|
+
| `log10(x)` | `LOG10(x)` | `number` |
|
|
1896
|
+
|
|
1897
|
+
> **Note:** SQLite `random()` returns a random integer (not float). `log`, `log2`, `log10` require SQLite 3.35+. `total()` behaves like `SUM()` but returns `0.0` instead of `NULL` for empty sets. SQLite uses the `||` operator for string concatenation.
|
|
1898
|
+
|
|
1899
|
+
> **Note:** SQLite stores `DateTime` differently between Prisma v6 (integer milliseconds) and v7 (ISO 8601 text). All SQLite datetime fns automatically normalise both formats via a `CASE WHEN typeof(...) = 'integer' THEN datetime(.../1000, 'unixepoch') ELSE ... END` wrapper, so they work correctly on both versions.
|
|
1900
|
+
|
|
1901
|
+
---
|
|
1902
|
+
|
|
1903
|
+
## Future updates
|
|
1904
|
+
|
|
1905
|
+
- Support specifying `JOIN` type [issue#2](https://github.com/adrianbrowning/prisma-ts-select/issues/2)
|
|
1906
|
+
- Support additional Select Functions
|
|
1907
|
+
- [JSON #9](https://github.com/adrianbrowning/prisma-ts-select/issues/9)
|
|
1908
|
+
- [CAST #71](https://github.com/adrianbrowning/prisma-ts-select/issues/71)
|
|
1909
|
+
- [whereRaw supporting Prisma.sql](https://github.com/adrianbrowning/prisma-ts-select/issues/29)
|
|
1910
|
+
|
|
1911
|
+
## Changelog / Versioning
|
|
1912
|
+
Changelog is available [here](https://github.com/adrianbrowning/prisma-ts-select/releases). We use [semantic versioning](https://semver.org/) for versioning.
|
|
1913
|
+
|
|
1914
|
+
## License
|
|
1915
|
+
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
724
1916
|
|
|
725
1917
|
|