prisma-sql 1.2.0 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-sql",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Convert Prisma queries to optimized SQL with type safety. 2-7x faster than Prisma Client.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
package/readme.md CHANGED
@@ -3,10 +3,15 @@
3
3
  Speed up Prisma reads **2-7x** by executing queries via postgres.js instead of Prisma's query engine.
4
4
 
5
5
  ```typescript
6
+ import { convertDMMFToModels } from 'prisma-sql'
7
+ import { Prisma } from '@prisma/client'
8
+
9
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
6
10
  const sql = postgres(DATABASE_URL)
7
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
11
+ const prisma = new PrismaClient().$extends(
12
+ speedExtension({ postgres: sql, models }),
13
+ )
8
14
 
9
- // Same Prisma API, 2-7x faster reads
10
15
  const users = await prisma.user.findMany({ where: { status: 'ACTIVE' } })
11
16
  ```
12
17
 
@@ -42,14 +47,16 @@ npm install prisma-sql better-sqlite3
42
47
  ### PostgreSQL
43
48
 
44
49
  ```typescript
45
- import { PrismaClient } from '@prisma/client'
46
- import { speedExtension } from 'prisma-sql'
50
+ import { PrismaClient, Prisma } from '@prisma/client'
51
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
47
52
  import postgres from 'postgres'
48
53
 
54
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
49
55
  const sql = postgres(process.env.DATABASE_URL)
50
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
56
+ const prisma = new PrismaClient().$extends(
57
+ speedExtension({ postgres: sql, models }),
58
+ )
51
59
 
52
- // All reads now execute via postgres.js
53
60
  const users = await prisma.user.findMany({
54
61
  where: { status: 'ACTIVE' },
55
62
  include: { posts: true },
@@ -59,32 +66,17 @@ const users = await prisma.user.findMany({
59
66
  ### SQLite
60
67
 
61
68
  ```typescript
62
- import { PrismaClient } from '@prisma/client'
63
- import { speedExtension } from 'prisma-sql'
69
+ import { PrismaClient, Prisma } from '@prisma/client'
70
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
64
71
  import Database from 'better-sqlite3'
65
72
 
73
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
66
74
  const db = new Database('./data.db')
67
- const prisma = new PrismaClient().$extends(speedExtension({ sqlite: db }))
68
-
69
- const users = await prisma.user.findMany({ where: { status: 'ACTIVE' } })
70
- ```
71
-
72
- ### Explicit DMMF (Edge Runtimes)
73
-
74
- In some environments (Cloudflare Workers, Vercel Edge, bundlers), Prisma's DMMF may not be auto-detectable. Provide it explicitly:
75
-
76
- ```typescript
77
- import { PrismaClient, Prisma } from '@prisma/client'
78
- import { speedExtension } from 'prisma-sql'
79
- import postgres from 'postgres'
80
-
81
- const sql = postgres(process.env.DATABASE_URL)
82
75
  const prisma = new PrismaClient().$extends(
83
- speedExtension({
84
- postgres: sql,
85
- dmmf: Prisma.dmmf, // Required in edge runtimes
86
- }),
76
+ speedExtension({ sqlite: db, models }),
87
77
  )
78
+
79
+ const users = await prisma.user.findMany({ where: { status: 'ACTIVE' } })
88
80
  ```
89
81
 
90
82
  ## What Gets Faster
@@ -271,22 +263,18 @@ Benchmarks from 137 E2E tests comparing identical queries against Prisma v6, Pri
271
263
 
272
264
  ```typescript
273
265
  import { Prisma } from '@prisma/client'
266
+ import { convertDMMFToModels } from 'prisma-sql'
274
267
 
275
- speedExtension({
276
- // Database client (required - choose one)
277
- postgres: sql, // For PostgreSQL via postgres.js
278
- sqlite: db, // For SQLite via better-sqlite3
268
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
279
269
 
280
- // DMMF (optional - auto-detected in most cases)
281
- dmmf: Prisma.dmmf, // Required in edge runtimes/bundled apps
270
+ speedExtension({
271
+ postgres: sql,
272
+ models,
282
273
 
283
- // Debug mode (optional)
284
- debug: true, // Log all generated SQL
274
+ debug: true,
285
275
 
286
- // Selective models (optional)
287
- models: ['User', 'Post'], // Only accelerate these models
276
+ allowedModels: ['User', 'Post'],
288
277
 
289
- // Performance monitoring (optional)
290
278
  onQuery: (info) => {
291
279
  console.log(`${info.model}.${info.method}: ${info.duration}ms`)
292
280
  },
@@ -298,15 +286,16 @@ speedExtension({
298
286
  See generated SQL for every query:
299
287
 
300
288
  ```typescript
289
+ import { convertDMMFToModels } from 'prisma-sql'
290
+ import { Prisma } from '@prisma/client'
291
+
292
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
293
+
301
294
  speedExtension({
302
295
  postgres: sql,
296
+ models,
303
297
  debug: true,
304
298
  })
305
-
306
- // Logs:
307
- // [postgres] User.findMany
308
- // SQL: SELECT ... FROM users WHERE status = $1
309
- // Params: ['ACTIVE']
310
299
  ```
311
300
 
312
301
  ### Selective Models
@@ -314,12 +303,13 @@ speedExtension({
314
303
  Only accelerate specific models:
315
304
 
316
305
  ```typescript
306
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
307
+
317
308
  speedExtension({
318
309
  postgres: sql,
319
- models: ['User', 'Post'], // Only User and Post get accelerated
310
+ models,
311
+ allowedModels: ['User', 'Post'],
320
312
  })
321
-
322
- // Order, Product, etc. still use Prisma
323
313
  ```
324
314
 
325
315
  ### Performance Monitoring
@@ -327,8 +317,11 @@ speedExtension({
327
317
  Track query performance:
328
318
 
329
319
  ```typescript
320
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
321
+
330
322
  speedExtension({
331
323
  postgres: sql,
324
+ models,
332
325
  onQuery: (info) => {
333
326
  console.log(`${info.model}.${info.method} completed in ${info.duration}ms`)
334
327
 
@@ -343,24 +336,6 @@ speedExtension({
343
336
  })
344
337
  ```
345
338
 
346
- ### When to Provide DMMF Explicitly
347
-
348
- Provide `dmmf: Prisma.dmmf` if:
349
-
350
- - Using Cloudflare Workers, Vercel Edge, or similar edge runtimes
351
- - Bundling with webpack, esbuild, or Rollup
352
- - In a monorepo with complex Prisma setup
353
- - You see "Cannot access Prisma DMMF" error
354
-
355
- ```typescript
356
- import { Prisma } from '@prisma/client'
357
-
358
- speedExtension({
359
- postgres: sql,
360
- dmmf: Prisma.dmmf, // Explicit DMMF
361
- })
362
- ```
363
-
364
339
  ## Advanced Usage
365
340
 
366
341
  ### Read Replicas
@@ -368,18 +343,20 @@ speedExtension({
368
343
  Send writes to primary, reads to replica:
369
344
 
370
345
  ```typescript
371
- // Primary database for writes
346
+ import { convertDMMFToModels } from 'prisma-sql'
347
+ import { Prisma } from '@prisma/client'
348
+
349
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
350
+
372
351
  const primary = new PrismaClient()
373
352
 
374
- // Replica for fast reads
375
353
  const replica = postgres(process.env.REPLICA_URL)
376
354
  const fastPrisma = new PrismaClient().$extends(
377
- speedExtension({ postgres: replica })
355
+ speedExtension({ postgres: replica, models })
378
356
  )
379
357
 
380
- // Use appropriately
381
- await primary.user.create({ data: { ... } }) // → Primary
382
- const users = await fastPrisma.user.findMany() // → Replica
358
+ await primary.user.create({ data: { ... } })
359
+ const users = await fastPrisma.user.findMany()
383
360
  ```
384
361
 
385
362
  ### Connection Pooling
@@ -387,14 +364,18 @@ const users = await fastPrisma.user.findMany() // → Replica
387
364
  Configure postgres.js connection pool:
388
365
 
389
366
  ```typescript
367
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
368
+
390
369
  const sql = postgres(process.env.DATABASE_URL, {
391
- max: 20, // Pool size
392
- idle_timeout: 20, // Close idle connections after 20s
393
- connect_timeout: 10, // Connection timeout
394
- ssl: 'require', // Force SSL
370
+ max: 20,
371
+ idle_timeout: 20,
372
+ connect_timeout: 10,
373
+ ssl: 'require',
395
374
  })
396
375
 
397
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
376
+ const prisma = new PrismaClient().$extends(
377
+ speedExtension({ postgres: sql, models }),
378
+ )
398
379
  ```
399
380
 
400
381
  ### Gradual Rollout
@@ -402,28 +383,27 @@ const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
402
383
  Feature-flag the extension for safe rollout:
403
384
 
404
385
  ```typescript
386
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
405
387
  const USE_FAST_READS = process.env.FAST_READS === 'true'
406
388
 
407
389
  const sql = postgres(DATABASE_URL)
408
390
  const prisma = new PrismaClient()
409
391
 
410
392
  const db = USE_FAST_READS
411
- ? prisma.$extends(speedExtension({ postgres: sql }))
393
+ ? prisma.$extends(speedExtension({ postgres: sql, models }))
412
394
  : prisma
413
-
414
- // Disable in production if issues arise:
415
- // FAST_READS=false pm2 restart app
416
395
  ```
417
396
 
418
397
  ### Access Original Prisma
419
398
 
420
399
  ```typescript
421
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
400
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
401
+ const prisma = new PrismaClient().$extends(
402
+ speedExtension({ postgres: sql, models }),
403
+ )
422
404
 
423
- // Use extension (fast)
424
405
  const fast = await prisma.user.findMany()
425
406
 
426
- // Bypass extension (original Prisma)
427
407
  const slow = await prisma.$original.user.findMany()
428
408
  ```
429
409
 
@@ -433,15 +413,13 @@ const slow = await prisma.$original.user.findMany()
433
413
 
434
414
  ```typescript
435
415
  import { PrismaClient, Prisma } from '@prisma/client'
436
- import { speedExtension } from 'prisma-sql'
416
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
437
417
  import postgres from 'postgres'
438
418
 
419
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
439
420
  const sql = postgres(process.env.DATABASE_URL)
440
421
  const prisma = new PrismaClient().$extends(
441
- speedExtension({
442
- postgres: sql,
443
- dmmf: Prisma.dmmf, // Explicit dmmf required in edge runtime
444
- }),
422
+ speedExtension({ postgres: sql, models }),
445
423
  )
446
424
 
447
425
  export const config = { runtime: 'edge' }
@@ -457,10 +435,11 @@ export default async function handler(req: Request) {
457
435
  For Cloudflare Workers, use the standalone SQL generation API instead of the extension:
458
436
 
459
437
  ```typescript
460
- import { createToSQL } from 'prisma-sql'
438
+ import { createToSQL, convertDMMFToModels } from 'prisma-sql'
461
439
  import { Prisma } from '@prisma/client'
462
440
 
463
- const toSQL = createToSQL(Prisma.dmmf, 'sqlite')
441
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
442
+ const toSQL = createToSQL(models, 'sqlite')
464
443
 
465
444
  export default {
466
445
  async fetch(request: Request, env: Env) {
@@ -483,23 +462,19 @@ export default {
483
462
  ### Filters
484
463
 
485
464
  ```typescript
486
- // Comparison operators
487
465
  { age: { gt: 18, lte: 65 } }
488
466
  { status: { in: ['ACTIVE', 'PENDING'] } }
489
467
  { status: { notIn: ['DELETED'] } }
490
468
 
491
- // String operations
492
469
  { email: { contains: '@example.com' } }
493
470
  { email: { startsWith: 'user' } }
494
471
  { email: { endsWith: '.com' } }
495
472
  { email: { contains: 'EXAMPLE', mode: 'insensitive' } }
496
473
 
497
- // Logical operators
498
474
  { AND: [{ status: 'ACTIVE' }, { verified: true }] }
499
475
  { OR: [{ role: 'ADMIN' }, { role: 'MODERATOR' }] }
500
476
  { NOT: { status: 'DELETED' } }
501
477
 
502
- // Null checks
503
478
  { deletedAt: null }
504
479
  { deletedAt: { not: null } }
505
480
  ```
@@ -507,7 +482,6 @@ export default {
507
482
  ### Relations
508
483
 
509
484
  ```typescript
510
- // Include relations
511
485
  {
512
486
  include: {
513
487
  posts: true,
@@ -515,7 +489,6 @@ export default {
515
489
  }
516
490
  }
517
491
 
518
- // Nested includes
519
492
  {
520
493
  include: {
521
494
  posts: {
@@ -527,7 +500,6 @@ export default {
527
500
  }
528
501
  }
529
502
 
530
- // Relation filters
531
503
  {
532
504
  where: {
533
505
  posts: {
@@ -556,22 +528,19 @@ export default {
556
528
  ### Pagination & Ordering
557
529
 
558
530
  ```typescript
559
- // Limit/offset
560
531
  {
561
532
  take: 10,
562
533
  skip: 20,
563
534
  orderBy: { createdAt: 'desc' }
564
535
  }
565
536
 
566
- // Cursor-based pagination
567
537
  {
568
538
  cursor: { id: 100 },
569
539
  take: 10,
570
- skip: 1, // Skip cursor itself
540
+ skip: 1,
571
541
  orderBy: { id: 'asc' }
572
542
  }
573
543
 
574
- // Multiple ordering
575
544
  {
576
545
  orderBy: [
577
546
  { status: 'asc' },
@@ -580,7 +549,6 @@ export default {
580
549
  ]
581
550
  }
582
551
 
583
- // Null positioning (PostgreSQL)
584
552
  {
585
553
  orderBy: {
586
554
  name: {
@@ -594,10 +562,8 @@ export default {
594
562
  ### Aggregations
595
563
 
596
564
  ```typescript
597
- // Count
598
565
  await prisma.user.count({ where: { status: 'ACTIVE' } })
599
566
 
600
- // Multiple aggregations
601
567
  await prisma.task.aggregate({
602
568
  where: { status: 'DONE' },
603
569
  _count: { _all: true },
@@ -607,7 +573,6 @@ await prisma.task.aggregate({
607
573
  _max: { completedAt: true },
608
574
  })
609
575
 
610
- // Group by
611
576
  await prisma.task.groupBy({
612
577
  by: ['status', 'priority'],
613
578
  _count: { _all: true },
@@ -623,13 +588,11 @@ await prisma.task.groupBy({
623
588
  ### Distinct
624
589
 
625
590
  ```typescript
626
- // Single field (PostgreSQL uses DISTINCT ON)
627
591
  {
628
592
  distinct: ['status'],
629
593
  orderBy: { status: 'asc' }
630
594
  }
631
595
 
632
- // Multiple fields (SQLite uses window functions)
633
596
  {
634
597
  distinct: ['status', 'priority'],
635
598
  orderBy: [
@@ -654,12 +617,16 @@ const users = await prisma.user.findMany()
654
617
 
655
618
  ```typescript
656
619
  import postgres from 'postgres'
657
- import { speedExtension } from 'prisma-sql'
620
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
621
+ import { Prisma } from '@prisma/client'
658
622
 
623
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
659
624
  const sql = postgres(DATABASE_URL)
660
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
625
+ const prisma = new PrismaClient().$extends(
626
+ speedExtension({ postgres: sql, models }),
627
+ )
661
628
 
662
- const users = await prisma.user.findMany() // Same code, 2-7x faster
629
+ const users = await prisma.user.findMany()
663
630
  ```
664
631
 
665
632
  ### From Drizzle
@@ -682,12 +649,15 @@ const users = await db
682
649
  **After:**
683
650
 
684
651
  ```typescript
685
- import { speedExtension } from 'prisma-sql'
652
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
653
+ import { Prisma } from '@prisma/client'
686
654
 
655
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
687
656
  const sql = postgres(DATABASE_URL)
688
- const prisma = new PrismaClient().$extends(speedExtension({ postgres: sql }))
657
+ const prisma = new PrismaClient().$extends(
658
+ speedExtension({ postgres: sql, models }),
659
+ )
689
660
 
690
- // Use Prisma's familiar API instead
691
661
  const users = await prisma.user.findMany({
692
662
  where: { status: 'ACTIVE' },
693
663
  })
@@ -724,13 +694,34 @@ If you encounter unsupported queries, enable `debug: true` to see which queries
724
694
 
725
695
  ## Troubleshooting
726
696
 
697
+ ### "speedExtension requires models parameter"
698
+
699
+ Convert DMMF at module level:
700
+
701
+ ```typescript
702
+ import { Prisma } from '@prisma/client'
703
+ import { convertDMMFToModels } from 'prisma-sql'
704
+
705
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
706
+
707
+ const prisma = new PrismaClient().$extends(
708
+ speedExtension({
709
+ postgres: sql,
710
+ models,
711
+ }),
712
+ )
713
+ ```
714
+
727
715
  ### "Results don't match Prisma Client"
728
716
 
729
717
  Enable debug mode to inspect generated SQL:
730
718
 
731
719
  ```typescript
720
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
721
+
732
722
  speedExtension({
733
723
  postgres: sql,
724
+ models,
734
725
  debug: true,
735
726
  })
736
727
  ```
@@ -749,38 +740,10 @@ Increase postgres.js pool size:
749
740
 
750
741
  ```typescript
751
742
  const sql = postgres(DATABASE_URL, {
752
- max: 50, // Increase from default 10
743
+ max: 50,
753
744
  })
754
745
  ```
755
746
 
756
- ### "Cannot access Prisma DMMF" Error
757
-
758
- If you see this error:
759
-
760
- ```
761
- Cannot access Prisma DMMF. Please provide dmmf in config
762
- ```
763
-
764
- Explicitly provide the DMMF:
765
-
766
- ```typescript
767
- import { Prisma } from '@prisma/client'
768
-
769
- const prisma = new PrismaClient().$extends(
770
- speedExtension({
771
- postgres: sql,
772
- dmmf: Prisma.dmmf, // Add this
773
- }),
774
- )
775
- ```
776
-
777
- This is required in:
778
-
779
- - Edge runtimes (Cloudflare Workers, Vercel Edge)
780
- - Bundled applications (webpack, esbuild)
781
- - Some monorepo setups
782
- - When using Prisma Client programmatically
783
-
784
747
  ### "Type errors after extending"
785
748
 
786
749
  Ensure `@prisma/client` is up to date:
@@ -801,8 +764,11 @@ Some queries won't see dramatic improvements:
801
764
  Use `onQuery` to measure actual speedup:
802
765
 
803
766
  ```typescript
767
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
768
+
804
769
  speedExtension({
805
770
  postgres: sql,
771
+ models,
806
772
  onQuery: (info) => {
807
773
  console.log(`${info.method} took ${info.duration}ms`)
808
774
  },
@@ -832,20 +798,6 @@ A: The extension runs after middlewares. If you need middleware to see the actua
832
798
  **Q: Can I still use `$queryRaw` and `$executeRaw`?**
833
799
  A: Yes. Those methods are unaffected. You also still have direct access to the postgres.js client.
834
800
 
835
- **Q: Do I need to provide `dmmf` in the config?**
836
- A: Usually no - it's auto-detected from Prisma Client. However, in edge runtimes (Cloudflare Workers, Vercel Edge) or bundled applications, you must provide it explicitly:
837
-
838
- ```typescript
839
- import { Prisma } from '@prisma/client'
840
-
841
- speedExtension({
842
- postgres: sql,
843
- dmmf: Prisma.dmmf, // Required in edge runtimes
844
- })
845
- ```
846
-
847
- If you see "Cannot access Prisma DMMF" error, add this parameter.
848
-
849
801
  **Q: What's the overhead of SQL generation?**
850
802
  A: ~0.03-0.04ms per query. Even with this overhead, total time is 2-7x faster than Prisma.
851
803
 
@@ -875,13 +827,16 @@ npm test
875
827
  Benchmark your own queries:
876
828
 
877
829
  ```typescript
878
- import { speedExtension } from 'prisma-sql'
830
+ import { speedExtension, convertDMMFToModels } from 'prisma-sql'
831
+ import { Prisma } from '@prisma/client'
879
832
 
880
833
  const queries: { name: string; duration: number }[] = []
834
+ const models = convertDMMFToModels(Prisma.dmmf.datamodel)
881
835
 
882
836
  const prisma = new PrismaClient().$extends(
883
837
  speedExtension({
884
838
  postgres: sql,
839
+ models,
885
840
  onQuery: (info) => {
886
841
  queries.push({
887
842
  name: `${info.model}.${info.method}`,
@@ -891,11 +846,9 @@ const prisma = new PrismaClient().$extends(
891
846
  }),
892
847
  )
893
848
 
894
- // Run your queries
895
849
  await prisma.user.findMany({ where: { status: 'ACTIVE' } })
896
850
  await prisma.post.findMany({ include: { author: true } })
897
851
 
898
- // Analyze
899
852
  console.table(queries)
900
853
  ```
901
854
 
@@ -906,13 +859,10 @@ git clone https://github.com/dee-see/prisma-sql
906
859
  cd prisma-sql
907
860
  npm install
908
861
 
909
- # Setup test database
910
862
  npx prisma db push
911
863
 
912
- # Run PostgreSQL benchmarks
913
864
  DATABASE_URL="postgresql://..." npm run test:e2e:postgres
914
865
 
915
- # Run SQLite benchmarks
916
866
  npm run test:e2e:sqlite
917
867
  ```
918
868