prisma-sql 1.7.0 → 1.9.0
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/dist/generator.cjs +4661 -0
- package/dist/generator.cjs.map +1 -0
- package/dist/generator.d.mts +1 -0
- package/dist/generator.d.ts +1 -0
- package/dist/generator.js +44 -82
- package/dist/generator.js.map +1 -0
- package/dist/{index.mjs → index.cjs} +41 -70
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +26 -96
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +331 -12
- package/dist/index.mjs.map +0 -1
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# prisma-sql
|
|
2
2
|
|
|
3
|
-
Speed up Prisma reads **2-7x** by executing queries via postgres.js instead of Prisma's query engine.
|
|
3
|
+
Speed up Prisma reads **2-7x** by executing queries via postgres.js or better-sqlite3 instead of Prisma's query engine.
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
6
|
import { convertDMMFToModels } from 'prisma-sql'
|
|
@@ -44,7 +44,82 @@ npm install prisma-sql better-sqlite3
|
|
|
44
44
|
|
|
45
45
|
## Quick Start
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
You can use prisma-sql in two ways:
|
|
48
|
+
|
|
49
|
+
### 1. Generator Mode (Recommended - Fastest)
|
|
50
|
+
|
|
51
|
+
Prebake SQL queries at build time for maximum performance.
|
|
52
|
+
|
|
53
|
+
**Add generator to schema:**
|
|
54
|
+
|
|
55
|
+
```prisma
|
|
56
|
+
// schema.prisma
|
|
57
|
+
datasource db {
|
|
58
|
+
provider = "postgresql"
|
|
59
|
+
url = env("DATABASE_URL")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
generator client {
|
|
63
|
+
provider = "prisma-client-js"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
generator sql {
|
|
67
|
+
provider = "prisma-sql-generator"
|
|
68
|
+
// Dialect auto-detected from datasource.provider
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
model User {
|
|
72
|
+
id Int @id @default(autoincrement())
|
|
73
|
+
email String @unique
|
|
74
|
+
status String
|
|
75
|
+
posts Post[]
|
|
76
|
+
|
|
77
|
+
/// @sql.findMany({ where: { status: "ACTIVE" } })
|
|
78
|
+
/// @sql.findMany({ where: { status: "PENDING" } })
|
|
79
|
+
/// @sql.count({ where: { status: "ACTIVE" } })
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
model Post {
|
|
83
|
+
id Int @id @default(autoincrement())
|
|
84
|
+
title String
|
|
85
|
+
published Boolean
|
|
86
|
+
authorId Int
|
|
87
|
+
author User @relation(fields: [authorId], references: [id])
|
|
88
|
+
|
|
89
|
+
/// @sql.findMany({ where: { published: true }, include: { author: true } })
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Generate and use:**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx prisma generate
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import { PrismaClient } from '@prisma/client'
|
|
101
|
+
import { createExtension } from '.prisma/client/sql'
|
|
102
|
+
import postgres from 'postgres'
|
|
103
|
+
|
|
104
|
+
const sql = postgres(process.env.DATABASE_URL)
|
|
105
|
+
const prisma = new PrismaClient().$extends(createExtension({ postgres: sql }))
|
|
106
|
+
|
|
107
|
+
// ⚡ PREBAKED - Uses pre-generated SQL (instant)
|
|
108
|
+
const activeUsers = await prisma.user.findMany({
|
|
109
|
+
where: { status: 'ACTIVE' },
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// 🔨 RUNTIME - Generates SQL on-the-fly (still fast)
|
|
113
|
+
const searchUsers = await prisma.user.findMany({
|
|
114
|
+
where: { email: { contains: '@example.com' } },
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 2. Runtime Mode (Simpler, No Build Step)
|
|
119
|
+
|
|
120
|
+
Generate SQL on-the-fly without code generation.
|
|
121
|
+
|
|
122
|
+
**PostgreSQL:**
|
|
48
123
|
|
|
49
124
|
```typescript
|
|
50
125
|
import { PrismaClient, Prisma } from '@prisma/client'
|
|
@@ -63,7 +138,7 @@ const users = await prisma.user.findMany({
|
|
|
63
138
|
})
|
|
64
139
|
```
|
|
65
140
|
|
|
66
|
-
|
|
141
|
+
**SQLite:**
|
|
67
142
|
|
|
68
143
|
```typescript
|
|
69
144
|
import { PrismaClient, Prisma } from '@prisma/client'
|
|
@@ -79,6 +154,167 @@ const prisma = new PrismaClient().$extends(
|
|
|
79
154
|
const users = await prisma.user.findMany({ where: { status: 'ACTIVE' } })
|
|
80
155
|
```
|
|
81
156
|
|
|
157
|
+
## Generator Mode vs Runtime Mode
|
|
158
|
+
|
|
159
|
+
### Generator Mode (Recommended)
|
|
160
|
+
|
|
161
|
+
**Pros:**
|
|
162
|
+
|
|
163
|
+
- ⚡ **Fastest** - SQL pre-generated at build time
|
|
164
|
+
- 🎯 **Zero overhead** for known queries
|
|
165
|
+
- 🔨 **Auto-fallback** to runtime for unknown queries
|
|
166
|
+
- 📊 **Track performance** with `prebaked` flag
|
|
167
|
+
|
|
168
|
+
**Cons:**
|
|
169
|
+
|
|
170
|
+
- Requires `npx prisma generate` step
|
|
171
|
+
- Need to define common queries upfront
|
|
172
|
+
|
|
173
|
+
**When to use:**
|
|
174
|
+
|
|
175
|
+
- ✅ Production applications
|
|
176
|
+
- ✅ Known query patterns (dashboards, APIs)
|
|
177
|
+
- ✅ Want maximum performance
|
|
178
|
+
- ✅ Build step is acceptable
|
|
179
|
+
|
|
180
|
+
### Runtime Mode
|
|
181
|
+
|
|
182
|
+
**Pros:**
|
|
183
|
+
|
|
184
|
+
- 🚀 **Simple** - no build step
|
|
185
|
+
- 🔧 **Flexible** - handles any query
|
|
186
|
+
- 📝 **Easy prototyping**
|
|
187
|
+
|
|
188
|
+
**Cons:**
|
|
189
|
+
|
|
190
|
+
- Small overhead (~0.2ms) for SQL generation
|
|
191
|
+
- Still 2-7x faster than Prisma
|
|
192
|
+
|
|
193
|
+
**When to use:**
|
|
194
|
+
|
|
195
|
+
- ✅ Rapid prototyping
|
|
196
|
+
- ✅ Fully dynamic queries
|
|
197
|
+
- ✅ No build step desired
|
|
198
|
+
- ✅ Query patterns unknown
|
|
199
|
+
|
|
200
|
+
## Generator Mode Details
|
|
201
|
+
|
|
202
|
+
### How It Works
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
Build Time:
|
|
206
|
+
schema.prisma
|
|
207
|
+
↓
|
|
208
|
+
/// @sql.findMany({ where: { status: "ACTIVE" } })
|
|
209
|
+
↓
|
|
210
|
+
npx prisma generate
|
|
211
|
+
↓
|
|
212
|
+
.prisma/client/sql/index.ts
|
|
213
|
+
↓
|
|
214
|
+
QUERIES = {
|
|
215
|
+
User: {
|
|
216
|
+
'{"where":{"status":"ACTIVE"}}': {
|
|
217
|
+
sql: 'SELECT * FROM users WHERE status = $1',
|
|
218
|
+
params: ['ACTIVE'],
|
|
219
|
+
dynamicKeys: []
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Runtime:
|
|
225
|
+
prisma.user.findMany({ where: { status: 'ACTIVE' } })
|
|
226
|
+
↓
|
|
227
|
+
Normalize query → '{"where":{"status":"ACTIVE"}}'
|
|
228
|
+
↓
|
|
229
|
+
QUERIES.User[query] found?
|
|
230
|
+
↓
|
|
231
|
+
YES → ⚡ Use prebaked SQL (0.03ms overhead)
|
|
232
|
+
↓
|
|
233
|
+
NO → 🔨 Generate SQL runtime (0.2ms overhead)
|
|
234
|
+
↓
|
|
235
|
+
Execute via postgres.js/better-sqlite3
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Generator Configuration
|
|
239
|
+
|
|
240
|
+
```prisma
|
|
241
|
+
generator sql {
|
|
242
|
+
provider = "prisma-sql-generator"
|
|
243
|
+
|
|
244
|
+
// Optional: Override auto-detected dialect (rarely needed)
|
|
245
|
+
// dialect = "postgres" // or "sqlite"
|
|
246
|
+
|
|
247
|
+
// Optional: Output directory (default: ../node_modules/.prisma/client/sql)
|
|
248
|
+
// output = "./generated/sql"
|
|
249
|
+
|
|
250
|
+
// Optional: Skip invalid directives instead of failing (default: false)
|
|
251
|
+
// skipInvalid = "true"
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Supported Directive Patterns
|
|
256
|
+
|
|
257
|
+
```prisma
|
|
258
|
+
model User {
|
|
259
|
+
// Simple queries
|
|
260
|
+
/// @sql.findMany({ where: { status: "ACTIVE" } })
|
|
261
|
+
/// @sql.findFirst({ where: { email: "test@example.com" } })
|
|
262
|
+
/// @sql.findUnique({ where: { id: 1 } })
|
|
263
|
+
|
|
264
|
+
// With relations
|
|
265
|
+
/// @sql.findMany({ include: { posts: true } })
|
|
266
|
+
/// @sql.findMany({ include: { posts: { where: { published: true } } } })
|
|
267
|
+
|
|
268
|
+
// With pagination
|
|
269
|
+
/// @sql.findMany({ take: 10, skip: 20, orderBy: { createdAt: "desc" } })
|
|
270
|
+
|
|
271
|
+
// Aggregations
|
|
272
|
+
/// @sql.count({ where: { status: "ACTIVE" } })
|
|
273
|
+
/// @sql.aggregate({ _count: { _all: true }, _avg: { age: true } })
|
|
274
|
+
/// @sql.groupBy({ by: ["status"], _count: { _all: true } })
|
|
275
|
+
|
|
276
|
+
// Dynamic parameters
|
|
277
|
+
/// @sql.findMany({ where: { status: { $param: "status" } } })
|
|
278
|
+
/// @sql.findMany({ where: { age: { gte: { $param: "minAge" } } } })
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Dynamic Parameters
|
|
283
|
+
|
|
284
|
+
Use `$param` for runtime values:
|
|
285
|
+
|
|
286
|
+
```prisma
|
|
287
|
+
model User {
|
|
288
|
+
/// @sql.findMany({ where: { status: { $param: "status" } } })
|
|
289
|
+
/// @sql.findMany({ where: { age: { gte: { $param: "minAge" } } } })
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// Prebaked SQL with runtime parameters
|
|
295
|
+
const users = await prisma.user.findMany({
|
|
296
|
+
where: { status: 'ACTIVE' }, // Matches directive with $param
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
// SQL: SELECT * FROM users WHERE status = $1
|
|
300
|
+
// Params: ['ACTIVE']
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Performance Tracking
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
const prisma = new PrismaClient().$extends(
|
|
307
|
+
createExtension({
|
|
308
|
+
postgres: sql,
|
|
309
|
+
debug: true,
|
|
310
|
+
onQuery: (info) => {
|
|
311
|
+
console.log(`${info.model}.${info.method}: ${info.duration}ms`)
|
|
312
|
+
console.log(info.prebaked ? '⚡ PREBAKED' : '🔨 RUNTIME')
|
|
313
|
+
},
|
|
314
|
+
}),
|
|
315
|
+
)
|
|
316
|
+
```
|
|
317
|
+
|
|
82
318
|
## What Gets Faster
|
|
83
319
|
|
|
84
320
|
**Accelerated (via raw SQL):**
|
|
@@ -613,7 +849,30 @@ const prisma = new PrismaClient()
|
|
|
613
849
|
const users = await prisma.user.findMany()
|
|
614
850
|
```
|
|
615
851
|
|
|
616
|
-
**After:**
|
|
852
|
+
**After (Generator Mode):**
|
|
853
|
+
|
|
854
|
+
```prisma
|
|
855
|
+
// schema.prisma
|
|
856
|
+
generator sql {
|
|
857
|
+
provider = "prisma-sql-generator"
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
model User {
|
|
861
|
+
/// @sql.findMany({ where: { status: "ACTIVE" } })
|
|
862
|
+
}
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
```typescript
|
|
866
|
+
import { createExtension } from '.prisma/client/sql'
|
|
867
|
+
import postgres from 'postgres'
|
|
868
|
+
|
|
869
|
+
const sql = postgres(DATABASE_URL)
|
|
870
|
+
const prisma = new PrismaClient().$extends(createExtension({ postgres: sql }))
|
|
871
|
+
|
|
872
|
+
const users = await prisma.user.findMany({ where: { status: 'ACTIVE' } })
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
**After (Runtime Mode):**
|
|
617
876
|
|
|
618
877
|
```typescript
|
|
619
878
|
import postgres from 'postgres'
|
|
@@ -663,6 +922,48 @@ const users = await prisma.user.findMany({
|
|
|
663
922
|
})
|
|
664
923
|
```
|
|
665
924
|
|
|
925
|
+
## Local Development
|
|
926
|
+
|
|
927
|
+
### Testing the Generator Locally
|
|
928
|
+
|
|
929
|
+
**1. Build the package:**
|
|
930
|
+
|
|
931
|
+
```bash
|
|
932
|
+
cd prisma-sql
|
|
933
|
+
npm install
|
|
934
|
+
npm run build
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
**2. Link globally:**
|
|
938
|
+
|
|
939
|
+
```bash
|
|
940
|
+
npm link
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
**3. Use in your project:**
|
|
944
|
+
|
|
945
|
+
```bash
|
|
946
|
+
cd your-project
|
|
947
|
+
npm link prisma-sql
|
|
948
|
+
npx prisma generate
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
**Alternative: Use file path directly in schema:**
|
|
952
|
+
|
|
953
|
+
```prisma
|
|
954
|
+
generator sql {
|
|
955
|
+
provider = "node ../path/to/prisma-sql/dist/generator.cjs"
|
|
956
|
+
}
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
**Unlink when done:**
|
|
960
|
+
|
|
961
|
+
```bash
|
|
962
|
+
npm unlink prisma-sql # In your project
|
|
963
|
+
cd prisma-sql
|
|
964
|
+
npm unlink # In prisma-sql directory
|
|
965
|
+
```
|
|
966
|
+
|
|
666
967
|
## Limitations
|
|
667
968
|
|
|
668
969
|
### Partially Supported
|
|
@@ -712,6 +1013,20 @@ const prisma = new PrismaClient().$extends(
|
|
|
712
1013
|
)
|
|
713
1014
|
```
|
|
714
1015
|
|
|
1016
|
+
### "Generator: Cannot find module"
|
|
1017
|
+
|
|
1018
|
+
The package hasn't been built or linked:
|
|
1019
|
+
|
|
1020
|
+
```bash
|
|
1021
|
+
# In prisma-sql directory
|
|
1022
|
+
npm run build
|
|
1023
|
+
npm link
|
|
1024
|
+
|
|
1025
|
+
# In your project
|
|
1026
|
+
npm link prisma-sql
|
|
1027
|
+
npx prisma generate
|
|
1028
|
+
```
|
|
1029
|
+
|
|
715
1030
|
### "Results don't match Prisma Client"
|
|
716
1031
|
|
|
717
1032
|
Enable debug mode to inspect generated SQL:
|
|
@@ -732,7 +1047,7 @@ Compare with Prisma's query log:
|
|
|
732
1047
|
new PrismaClient({ log: ['query'] })
|
|
733
1048
|
```
|
|
734
1049
|
|
|
735
|
-
File an issue if results differ: https://github.com/
|
|
1050
|
+
File an issue if results differ: https://github.com/multipliedtwice/prisma-sql/issues
|
|
736
1051
|
|
|
737
1052
|
### "Connection pool exhausted"
|
|
738
1053
|
|
|
@@ -799,7 +1114,7 @@ A: The extension runs after middlewares. If you need middleware to see the actua
|
|
|
799
1114
|
A: Yes. Those methods are unaffected. You also still have direct access to the postgres.js client.
|
|
800
1115
|
|
|
801
1116
|
**Q: What's the overhead of SQL generation?**
|
|
802
|
-
A: ~0.
|
|
1117
|
+
A: Generator mode: ~0.03ms (prebaked queries). Runtime mode: ~0.2ms. Even with this overhead, total time is 2-7x faster than Prisma.
|
|
803
1118
|
|
|
804
1119
|
**Q: How do I benchmark my own queries?**
|
|
805
1120
|
A: Use the `onQuery` callback to measure each query, or see the [Benchmarking](#benchmarking) section below.
|
|
@@ -807,8 +1122,12 @@ A: Use the `onQuery` callback to measure each query, or see the [Benchmarking](#
|
|
|
807
1122
|
**Q: How does performance compare to Prisma v7?**
|
|
808
1123
|
A: Prisma v7 introduced significant improvements (~39% faster than v6 on PostgreSQL, ~24% on SQLite), but this extension still provides 2-7x additional speedup over v7 depending on query complexity.
|
|
809
1124
|
|
|
1125
|
+
**Q: Should I use generator mode or runtime mode?**
|
|
1126
|
+
A: Generator mode is recommended for production (faster). Runtime mode is better for prototyping or fully dynamic queries.
|
|
1127
|
+
|
|
810
1128
|
## Examples
|
|
811
1129
|
|
|
1130
|
+
- [Generator Mode Example](./examples/generator-mode) - Complete working example
|
|
812
1131
|
- [PostgreSQL E2E Tests](./tests/e2e/postgres.test.ts) - Comprehensive query examples
|
|
813
1132
|
- [SQLite E2E Tests](./tests/e2e/sqlite.e2e.test.ts) - SQLite-specific queries
|
|
814
1133
|
- [Runtime API Tests](./tests/e2e/runtime-api.test.ts) - All three APIs
|
|
@@ -816,7 +1135,7 @@ A: Prisma v7 introduced significant improvements (~39% faster than v6 on Postgre
|
|
|
816
1135
|
To run examples locally:
|
|
817
1136
|
|
|
818
1137
|
```bash
|
|
819
|
-
git clone https://github.com/
|
|
1138
|
+
git clone https://github.com/multipliedtwice/prisma-sql
|
|
820
1139
|
cd prisma-sql
|
|
821
1140
|
npm install
|
|
822
1141
|
npm test
|
|
@@ -855,7 +1174,7 @@ console.table(queries)
|
|
|
855
1174
|
Or run the full test suite benchmarks:
|
|
856
1175
|
|
|
857
1176
|
```bash
|
|
858
|
-
git clone https://github.com/
|
|
1177
|
+
git clone https://github.com/multipliedtwice/prisma-sql
|
|
859
1178
|
cd prisma-sql
|
|
860
1179
|
npm install
|
|
861
1180
|
|
|
@@ -881,10 +1200,10 @@ PRs welcome! Priority areas:
|
|
|
881
1200
|
Setup:
|
|
882
1201
|
|
|
883
1202
|
```bash
|
|
884
|
-
git clone https://github.com/
|
|
1203
|
+
git clone https://github.com/multipliedtwice/prisma-sql
|
|
885
1204
|
cd prisma-sql
|
|
886
1205
|
npm install
|
|
887
|
-
npm run
|
|
1206
|
+
npm run build
|
|
888
1207
|
npm test
|
|
889
1208
|
```
|
|
890
1209
|
|
|
@@ -936,8 +1255,8 @@ MIT
|
|
|
936
1255
|
## Links
|
|
937
1256
|
|
|
938
1257
|
- [NPM Package](https://www.npmjs.com/package/prisma-sql)
|
|
939
|
-
- [GitHub Repository](https://github.com/
|
|
940
|
-
- [Issue Tracker](https://github.com/
|
|
1258
|
+
- [GitHub Repository](https://github.com/multipliedtwice/prisma-sql)
|
|
1259
|
+
- [Issue Tracker](https://github.com/multipliedtwice/prisma-sql/issues)
|
|
941
1260
|
|
|
942
1261
|
---
|
|
943
1262
|
|