noormme 1.0.2 → 1.0.3

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.
Files changed (76) hide show
  1. package/README.md +291 -11
  2. package/dist/cjs/dialect/postgresql/postgresql-adapter.d.ts +81 -0
  3. package/dist/cjs/dialect/postgresql/postgresql-adapter.js +40 -0
  4. package/dist/cjs/dialect/postgresql/postgresql-dialect-config.d.ts +65 -0
  5. package/dist/cjs/dialect/postgresql/postgresql-dialect-config.js +2 -0
  6. package/dist/cjs/dialect/postgresql/postgresql-dialect.d.ts +80 -0
  7. package/dist/cjs/dialect/postgresql/postgresql-dialect.js +76 -0
  8. package/dist/cjs/dialect/postgresql/postgresql-driver.d.ts +51 -0
  9. package/dist/cjs/dialect/postgresql/postgresql-driver.js +148 -0
  10. package/dist/cjs/dialect/postgresql/postgresql-features.d.ts +377 -0
  11. package/dist/cjs/dialect/postgresql/postgresql-features.js +459 -0
  12. package/dist/cjs/dialect/postgresql/postgresql-introspector.d.ts +12 -0
  13. package/dist/cjs/dialect/postgresql/postgresql-introspector.js +232 -0
  14. package/dist/cjs/dialect/postgresql/postgresql-query-compiler.d.ts +11 -0
  15. package/dist/cjs/dialect/postgresql/postgresql-query-compiler.js +39 -0
  16. package/dist/cjs/helpers/postgresql.d.ts +96 -0
  17. package/dist/cjs/helpers/postgresql.js +147 -0
  18. package/dist/cjs/index.d.ts +8 -1
  19. package/dist/cjs/index.js +21 -2
  20. package/dist/cjs/migration/data_migrator.d.ts +40 -0
  21. package/dist/cjs/migration/data_migrator.js +222 -0
  22. package/dist/cjs/migration/database_migration_manager.d.ts +77 -0
  23. package/dist/cjs/migration/database_migration_manager.js +383 -0
  24. package/dist/cjs/migration/index.d.ts +19 -0
  25. package/dist/cjs/migration/index.js +53 -0
  26. package/dist/cjs/migration/migration-types.d.ts +157 -0
  27. package/dist/cjs/migration/migration-types.js +5 -0
  28. package/dist/cjs/migration/schema_differ.d.ts +24 -0
  29. package/dist/cjs/migration/schema_differ.js +323 -0
  30. package/dist/cjs/migration/schema_introspector.d.ts +13 -0
  31. package/dist/cjs/migration/schema_introspector.js +364 -0
  32. package/dist/cjs/migration/type_mapper.d.ts +23 -0
  33. package/dist/cjs/migration/type_mapper.js +263 -0
  34. package/dist/cjs/noormme.js +58 -1
  35. package/dist/cjs/operation-node/data-type-node.d.ts +1 -1
  36. package/dist/cjs/operation-node/data-type-node.js +26 -0
  37. package/dist/cjs/schema/core/utils/type-mapper.js +21 -0
  38. package/dist/cjs/types/type-generator.js +9 -0
  39. package/dist/esm/dialect/postgresql/postgresql-adapter.d.ts +81 -0
  40. package/dist/esm/dialect/postgresql/postgresql-adapter.js +37 -0
  41. package/dist/esm/dialect/postgresql/postgresql-dialect-config.d.ts +65 -0
  42. package/dist/esm/dialect/postgresql/postgresql-dialect-config.js +2 -0
  43. package/dist/esm/dialect/postgresql/postgresql-dialect.d.ts +80 -0
  44. package/dist/esm/dialect/postgresql/postgresql-dialect.js +73 -0
  45. package/dist/esm/dialect/postgresql/postgresql-driver.d.ts +51 -0
  46. package/dist/esm/dialect/postgresql/postgresql-driver.js +112 -0
  47. package/dist/esm/dialect/postgresql/postgresql-features.d.ts +377 -0
  48. package/dist/esm/dialect/postgresql/postgresql-features.js +457 -0
  49. package/dist/esm/dialect/postgresql/postgresql-introspector.d.ts +12 -0
  50. package/dist/esm/dialect/postgresql/postgresql-introspector.js +229 -0
  51. package/dist/esm/dialect/postgresql/postgresql-query-compiler.d.ts +11 -0
  52. package/dist/esm/dialect/postgresql/postgresql-query-compiler.js +36 -0
  53. package/dist/esm/helpers/postgresql.d.ts +96 -0
  54. package/dist/esm/helpers/postgresql.js +126 -0
  55. package/dist/esm/index.d.ts +8 -1
  56. package/dist/esm/index.js +9 -1
  57. package/dist/esm/migration/data_migrator.d.ts +40 -0
  58. package/dist/esm/migration/data_migrator.js +217 -0
  59. package/dist/esm/migration/database_migration_manager.d.ts +77 -0
  60. package/dist/esm/migration/database_migration_manager.js +379 -0
  61. package/dist/esm/migration/index.d.ts +19 -0
  62. package/dist/esm/migration/index.js +21 -0
  63. package/dist/esm/migration/migration-types.d.ts +157 -0
  64. package/dist/esm/migration/migration-types.js +5 -0
  65. package/dist/esm/migration/schema_differ.d.ts +24 -0
  66. package/dist/esm/migration/schema_differ.js +319 -0
  67. package/dist/esm/migration/schema_introspector.d.ts +13 -0
  68. package/dist/esm/migration/schema_introspector.js +361 -0
  69. package/dist/esm/migration/type_mapper.d.ts +23 -0
  70. package/dist/esm/migration/type_mapper.js +258 -0
  71. package/dist/esm/noormme.js +58 -1
  72. package/dist/esm/operation-node/data-type-node.d.ts +1 -1
  73. package/dist/esm/operation-node/data-type-node.js +26 -0
  74. package/dist/esm/schema/core/utils/type-mapper.js +21 -0
  75. package/dist/esm/types/type-generator.js +9 -0
  76. package/package.json +16 -5
package/README.md CHANGED
@@ -32,27 +32,46 @@ We fixed all that nonsense:
32
32
 
33
33
  ### **Real Benefits (The Stuff That Actually Matters):**
34
34
  - 🚀 **Feel like a coding wizard** - AI that understands your project
35
- - 💰 **Save money** - No expensive database servers to maintain
36
- - 🔧 **Deploy easily** - One file instead of a server farm
37
- - **Go fast** - Direct file access beats network calls every time
38
- - 🛡️ **Stay secure** - No network = no network attacks
35
+ - 🗄️ **Multi-database support** - SQLite for simplicity, PostgreSQL for power
36
+ - 💰 **Save money** - SQLite for dev/small apps, PostgreSQL when you need it
37
+ - 🔧 **Deploy easily** - SQLite = one file, PostgreSQL = full production ready
38
+ - **Go fast** - Optimized performance for both SQLite and PostgreSQL
39
+ - 🛡️ **Stay secure** - Built-in connection pooling and security best practices
39
40
  - 😊 **Have fun** - Finally, coding that doesn't make you cry
40
41
 
41
- **Bottom line:** You get enterprise-grade superpowers with the simplicity of a single file.
42
+ **Bottom line:** You get enterprise-grade superpowers with your choice of database.
42
43
 
43
44
  ## 🚀 What's the Big Deal? (Spoiler: It's Actually Pretty Big)
44
45
 
45
46
  **Before NOORMME:** You spend 8 hours setting up a database, 4 hours organizing your project, and 2 hours fighting with AI tools that suggest code from 2019.
46
47
 
47
48
  **With NOORMME:** Your development environment becomes AI-ready in 5 minutes:
48
- - ✅ **SQLite that acts like PostgreSQL** - All the power, none of the pain
49
+ - ✅ **SQLite & PostgreSQL support** - Start simple, scale when needed
49
50
  - ✅ **Organized architecture** - Patterns that actually make sense
50
51
  - ✅ **AI context rules** - Cursor IDE integration that works
51
52
  - ✅ **Type safety** - TypeScript that doesn't make you want to throw things
52
- - ✅ **Production features** - WAL mode, caching, and performance optimization
53
+ - ✅ **Production features** - WAL mode, connection pooling, caching, and performance optimization
53
54
 
54
55
  **It's literally a development environment that makes AI assistance useful.** 🤯
55
56
 
57
+ ## 🗄️ Database Support
58
+
59
+ NOORMME supports multiple database systems with the same API:
60
+
61
+ ### SQLite - Perfect for:
62
+ - 🚀 **Prototyping & MVPs** - Get started in seconds
63
+ - 📱 **Edge deployments** - Cloudflare Workers, Vercel Edge, etc.
64
+ - 💻 **Local-first apps** - Embedded databases in desktop/mobile apps
65
+ - 🧪 **Testing** - Fast, isolated test environments
66
+ - 💰 **Small to medium apps** - No database server needed
67
+
68
+ ### PostgreSQL - Perfect for:
69
+ - 🏢 **Production applications** - Battle-tested reliability
70
+ - 📊 **Complex queries** - Advanced SQL features
71
+ - 🔒 **Multi-user systems** - Robust concurrency handling
72
+ - 📈 **Scaling** - Handle millions of records
73
+ - 🌐 **Traditional deployments** - Client-server architecture
74
+
56
75
  ## ⚡ Get Started in 60 Seconds (No, Really)
57
76
 
58
77
  ### 1. Install It (The Easy Part)
@@ -66,19 +85,55 @@ npx noormme init
66
85
  ```
67
86
 
68
87
  ### 3. Point at Your Database (The "Wait, That's It?" Part)
88
+
89
+ #### Option A: SQLite (Simplest)
69
90
  ```typescript
70
91
  import { NOORMME } from 'noormme'
71
92
 
72
93
  const db = new NOORMME({
73
94
  dialect: 'sqlite',
74
95
  connection: {
75
- database: './your-database.sqlite' // Point to your existing database
96
+ database: './your-database.sqlite'
97
+ }
98
+ })
99
+
100
+ await db.initialize()
101
+ ```
102
+
103
+ #### Option B: PostgreSQL (Production-Ready)
104
+ ```typescript
105
+ import { NOORMME } from 'noormme'
106
+
107
+ const db = new NOORMME({
108
+ dialect: 'postgresql',
109
+ connection: {
110
+ host: 'localhost',
111
+ port: 5432,
112
+ database: 'your_database',
113
+ username: 'postgres',
114
+ password: 'your_password'
76
115
  }
77
116
  })
78
117
 
79
118
  await db.initialize()
80
119
  ```
81
120
 
121
+ #### Option C: Connection String (Easiest)
122
+ ```typescript
123
+ import { NOORMME } from 'noormme'
124
+
125
+ // SQLite
126
+ const db = new NOORMME('sqlite:./your-database.sqlite')
127
+
128
+ // PostgreSQL
129
+ // const db = new NOORMME('postgresql://user:password@localhost:5432/database')
130
+
131
+ // Or use DATABASE_URL environment variable
132
+ // const db = new NOORMME() // Reads from process.env.DATABASE_URL
133
+
134
+ await db.initialize()
135
+ ```
136
+
82
137
  ### 4. Start Building with AI Assistance (The "I'm a Genius Now" Part)
83
138
  ```typescript
84
139
  // NOORMME automatically finds your 'users' table and creates methods
@@ -247,10 +302,50 @@ const featuredProducts = await productRepo.findManyByFeatured(true)
247
302
  const pendingOrders = await orderRepo.findManyByStatus('pending')
248
303
  ```
249
304
 
305
+ ### Production App with PostgreSQL (The "I'm Going Big" Example)
306
+ ```typescript
307
+ // Connect to PostgreSQL for production-grade performance
308
+ const db = new NOORMME({
309
+ dialect: 'postgresql',
310
+ connection: {
311
+ host: process.env.DB_HOST || 'localhost',
312
+ port: parseInt(process.env.DB_PORT || '5432'),
313
+ database: process.env.DB_NAME || 'myapp',
314
+ username: process.env.DB_USER || 'postgres',
315
+ password: process.env.DB_PASSWORD,
316
+ ssl: process.env.NODE_ENV === 'production',
317
+ pool: {
318
+ max: 20, // Maximum connections
319
+ min: 5, // Minimum connections
320
+ idleTimeoutMillis: 30000,
321
+ }
322
+ }
323
+ })
324
+
325
+ await db.initialize()
326
+
327
+ // Same API as SQLite - just more powerful!
328
+ const userRepo = db.getRepository('users')
329
+ const users = await userRepo.findAll()
330
+
331
+ // Advanced PostgreSQL features work seamlessly
332
+ const analytics = await db.getKysely()
333
+ .selectFrom('orders')
334
+ .select(({ fn }) => [
335
+ fn.count('id').as('total_orders'),
336
+ fn.sum('amount').as('total_revenue'),
337
+ fn.avg('amount').as('avg_order_value'),
338
+ ])
339
+ .where('created_at', '>=', new Date('2024-01-01'))
340
+ .groupBy('user_id')
341
+ .execute()
342
+ ```
343
+
250
344
  ## 🔧 Configuration (Optional, Because We're Not Dictators)
251
345
 
252
346
  For most people, the default settings work perfectly. But if you want to customize (because you're a special snowflake):
253
347
 
348
+ ### SQLite Configuration
254
349
  ```typescript
255
350
  const db = new NOORMME({
256
351
  dialect: 'sqlite',
@@ -269,6 +364,183 @@ const db = new NOORMME({
269
364
  })
270
365
  ```
271
366
 
367
+ ### PostgreSQL Configuration
368
+ ```typescript
369
+ const db = new NOORMME({
370
+ dialect: 'postgresql',
371
+ connection: {
372
+ host: 'localhost',
373
+ port: 5432,
374
+ database: 'myapp',
375
+ username: 'postgres',
376
+ password: 'secret',
377
+ ssl: true, // Enable SSL
378
+ pool: {
379
+ max: 20, // Maximum pool size
380
+ min: 5, // Minimum pool size
381
+ idleTimeoutMillis: 30000, // Close idle connections after 30s
382
+ connectionTimeoutMillis: 2000, // Timeout for acquiring connection
383
+ }
384
+ },
385
+ automation: {
386
+ enableAutoOptimization: true,
387
+ enableIndexRecommendations: true,
388
+ enableQueryAnalysis: true,
389
+ },
390
+ performance: {
391
+ enableCaching: true,
392
+ maxCacheSize: 1000
393
+ }
394
+ })
395
+ ```
396
+
397
+ ### PostgreSQL-Specific Features (The Power Tools)
398
+
399
+ NOORMME provides comprehensive support for PostgreSQL-specific features:
400
+
401
+ #### Array Types
402
+ ```typescript
403
+ import { PostgresArrayHelpers } from 'noormme/helpers/postgresql'
404
+
405
+ // Create table with array columns
406
+ await db.kysely.schema
407
+ .createTable('posts')
408
+ .addColumn('tags', 'text[]')
409
+ .addColumn('scores', 'integer[]')
410
+ .execute()
411
+
412
+ // Query with array operations
413
+ const posts = await db.kysely
414
+ .selectFrom('posts')
415
+ .where(PostgresArrayHelpers.contains('tags', ['typescript']))
416
+ .execute()
417
+ ```
418
+
419
+ #### JSON/JSONB Operations
420
+ ```typescript
421
+ import { PostgresJSONHelpers } from 'noormme/helpers/postgresql'
422
+
423
+ // Extract and query JSON fields
424
+ const users = await db.kysely
425
+ .selectFrom('users')
426
+ .select(PostgresJSONHelpers.extract('metadata', 'email').as('email'))
427
+ .where(PostgresJSONHelpers.hasKey('metadata', 'phone'))
428
+ .execute()
429
+ ```
430
+
431
+ #### Full-Text Search
432
+ ```typescript
433
+ import { PostgresFullTextHelpers } from 'noormme/helpers/postgresql'
434
+
435
+ // Add full-text search
436
+ await PostgresFullTextHelpers.addGeneratedTSVectorColumn(
437
+ db.kysely, 'articles', 'search_vector', ['title', 'content']
438
+ )
439
+
440
+ // Search with ranking
441
+ const results = await db.kysely
442
+ .selectFrom('articles')
443
+ .select(PostgresFullTextHelpers.rank('search_vector', 'typescript').as('rank'))
444
+ .where(PostgresFullTextHelpers.match('search_vector', 'typescript'))
445
+ .orderBy('rank', 'desc')
446
+ .execute()
447
+ ```
448
+
449
+ #### Materialized Views
450
+ ```typescript
451
+ import { PostgresMaterializedViewHelpers } from 'noormme/helpers/postgresql'
452
+
453
+ // Create and manage materialized views
454
+ await PostgresMaterializedViewHelpers.create(
455
+ db.kysely, 'user_stats',
456
+ sql`SELECT user_id, COUNT(*) as post_count FROM posts GROUP BY user_id`
457
+ )
458
+
459
+ await PostgresMaterializedViewHelpers.refresh(db.kysely, 'user_stats', {
460
+ concurrently: true
461
+ })
462
+ ```
463
+
464
+ **📚 Learn More:**
465
+ - [PostgreSQL Features Documentation](docs/postgresql-features.md) for detailed feature guides
466
+ - [PostgreSQL Support Documentation](docs/postgresql/POSTGRESQL_SUPPORT.md) for comprehensive overview
467
+
468
+ ### Database Migration Tools (The "Time to Move" Feature)
469
+
470
+ NOORMME provides powerful tools for migrating databases between SQLite and PostgreSQL:
471
+
472
+ #### Automated Migration
473
+
474
+ ```typescript
475
+ import { createMigrationManager } from 'noormme/helpers/postgresql'
476
+
477
+ // Source database (SQLite)
478
+ const sourceDb = new NOORMME('sqlite:./source.sqlite')
479
+
480
+ // Target database (PostgreSQL)
481
+ const targetDb = new NOORMME('postgresql://user:pass@localhost/target')
482
+
483
+ await sourceDb.initialize()
484
+ await targetDb.initialize()
485
+
486
+ // Create migration manager
487
+ const migrationManager = createMigrationManager(
488
+ sourceDb.getKysely(),
489
+ targetDb.getKysely(),
490
+ {
491
+ source: {
492
+ dialect: 'sqlite',
493
+ database: './source.sqlite',
494
+ },
495
+ target: {
496
+ dialect: 'postgresql',
497
+ database: 'target',
498
+ host: 'localhost',
499
+ port: 5432,
500
+ username: 'user',
501
+ password: 'pass',
502
+ },
503
+ options: {
504
+ batchSize: 1000,
505
+ verbose: true,
506
+ },
507
+ }
508
+ )
509
+
510
+ // Perform complete migration (schema + data)
511
+ const result = await migrationManager.migrate()
512
+ console.log(`Migrated ${result.rowsMigrated} rows in ${(result.duration / 1000).toFixed(2)}s`)
513
+ ```
514
+
515
+ #### Schema Comparison & Sync
516
+
517
+ ```typescript
518
+ // Compare schemas
519
+ const comparison = await migrationManager.compareSchemas()
520
+ console.log(`Differences: ${comparison.differences.length}`)
521
+
522
+ // Generate sync SQL
523
+ const syncResult = await migrationManager.syncSchema({
524
+ generateSQL: true,
525
+ apply: false, // Preview changes without applying
526
+ })
527
+
528
+ syncResult.sqlStatements.forEach(sql => console.log(sql))
529
+ ```
530
+
531
+ #### Key Migration Features
532
+
533
+ - ✅ **Bidirectional Migration** - SQLite ↔ PostgreSQL
534
+ - ✅ **Automatic Type Conversion** - Smart mapping between database types
535
+ - ✅ **Value Transformation** - Handle booleans, arrays, JSON, and dates
536
+ - ✅ **Batch Processing** - Efficient large dataset migration
537
+ - ✅ **Parallel Migration** - Multi-table concurrent processing
538
+ - ✅ **Progress Tracking** - Real-time migration progress
539
+ - ✅ **Schema Diff** - Detect schema differences
540
+ - ✅ **Verification** - Automated post-migration checks
541
+
542
+ **📚 Learn More:** See [Migration Tools Documentation](docs/migration-tools.md) for detailed guides and examples.
543
+
272
544
  ## 🚀 Production Ready (Because We're Not Playing Around)
273
545
 
274
546
  NOORMME is already running in production applications with real-world success stories. It includes:
@@ -294,10 +566,15 @@ The DreamBeesArt application successfully migrated from Drizzle ORM to NOORMME w
294
566
  A: Nope! NOORMME handles most things automatically. You only need SQL for complex queries (and even then, we'll help you).
295
567
 
296
568
  **Q: Can I use my existing database?**
297
- A: Yes! Just point NOORMME at your existing SQLite file and it figures everything out (because we're not picky).
569
+ A: Yes! Just point NOORMME at your existing SQLite or PostgreSQL database and it figures everything out (because we're not picky).
570
+
571
+ **Q: Should I use SQLite or PostgreSQL?**
572
+ A: Start with SQLite for prototyping and small apps (it's faster to set up). Switch to PostgreSQL when you need multi-user support, complex queries, or scaling. The API is identical, so switching is easy!
298
573
 
299
574
  **Q: Is this really production-ready?**
300
- A: Absolutely. Real applications are using it right now with better performance than PostgreSQL (because we're not lying).
575
+ A: Absolutely. Real applications are using it right now:
576
+ - SQLite with WAL mode for edge deployments and local-first apps
577
+ - PostgreSQL for traditional production deployments with millions of records
301
578
 
302
579
  **Q: What if I'm already using another ORM?**
303
580
  A: NOORMME works alongside other tools. You can migrate gradually or use both (because we're not territorial).
@@ -309,7 +586,10 @@ A: NOORMME works with JavaScript too, but TypeScript gives you the best experien
309
586
  A: NOORMME includes Cursor IDE context rules that make AI assistance actually useful. The AI understands your project structure and generates code that follows your conventions (because we're not savages).
310
587
 
311
588
  **Q: What makes this different from other toolkits?**
312
- A: NOORMME combines database automation, organized architecture, and AI-ready patterns in one integrated toolkit. It's not just an ORM - it's a complete development environment (because we're ambitious).
589
+ A: NOORMME combines database automation, organized architecture, and AI-ready patterns in one integrated toolkit. It's not just an ORM - it's a complete development environment that supports both SQLite and PostgreSQL with the same API (because we're ambitious).
590
+
591
+ **Q: Can I migrate from SQLite to PostgreSQL later?**
592
+ A: Yes! Since NOORMME uses the same API for both databases, migrating is as simple as changing the connection config. Your application code stays the same!
313
593
 
314
594
  **Q: Will this make me a better developer?**
315
595
  A: Probably not, but it will make you feel like one (which is half the battle).
@@ -0,0 +1,81 @@
1
+ import { Kysely } from '../../kysely.js';
2
+ import { DialectAdapterBase } from '../dialect-adapter-base.js';
3
+ import { MigrationLockOptions } from '../dialect-adapter.js';
4
+ export declare class PostgresAdapter extends DialectAdapterBase {
5
+ #private;
6
+ /**
7
+ * Whether or not this dialect supports transactional DDL.
8
+ *
9
+ * If this is true, migrations are executed inside a transaction.
10
+ */
11
+ get supportsTransactionalDdl(): boolean;
12
+ /**
13
+ * Whether or not this dialect supports the `returning` in inserts
14
+ * updates and deletes.
15
+ */
16
+ get supportsReturning(): boolean;
17
+ /**
18
+ * This method is used to acquire a lock for the migrations so that
19
+ * it's not possible for two migration operations to run in parallel.
20
+ *
21
+ * Most dialects have explicit locks that can be used, like advisory locks
22
+ * in PostgreSQL and the get_lock function in MySQL.
23
+ *
24
+ * If the dialect doesn't have explicit locks the {@link MigrationLockOptions.lockTable}
25
+ * created by Kysely can be used instead. You can access it through the `options` object.
26
+ * The lock table has two columns `id` and `is_locked` and there's only one row in the table
27
+ * whose id is {@link MigrationLockOptions.lockRowId}. `is_locked` is an integer. Kysely
28
+ * takes care of creating the lock table and inserting the one single row to it before this
29
+ * method is executed. If the dialect supports schemas and the user has specified a custom
30
+ * schema in their migration settings, the options object also contains the schema name in
31
+ * {@link MigrationLockOptions.lockTableSchema}.
32
+ *
33
+ * Here's an example of how you might implement this method for a dialect that doesn't
34
+ * have explicit locks but supports `FOR UPDATE` row locks and transactional DDL:
35
+ *
36
+ * ```ts
37
+ * import { DialectAdapterBase, type MigrationLockOptions, Kysely } from 'kysely'
38
+ *
39
+ * export class MyAdapter extends DialectAdapterBase {
40
+ * override async acquireMigrationLock(
41
+ * db: Kysely<any>,
42
+ * options: MigrationLockOptions
43
+ * ): Promise<void> {
44
+ * const queryDb = options.lockTableSchema
45
+ * ? db.withSchema(options.lockTableSchema)
46
+ * : db
47
+ *
48
+ * // Since our imaginary dialect supports transactional DDL and has
49
+ * // row locks, we can simply take a row lock here and it will guarantee
50
+ * // all subsequent calls to this method from other transactions will
51
+ * // wait until this transaction finishes.
52
+ * await queryDb
53
+ * .selectFrom(options.lockTable)
54
+ * .selectAll()
55
+ * .where('id', '=', options.lockRowId)
56
+ * .forUpdate()
57
+ * .execute()
58
+ * }
59
+ *
60
+ * override async releaseMigrationLock() {
61
+ * // noop
62
+ * }
63
+ * }
64
+ * ```
65
+ *
66
+ * If `supportsTransactionalDdl` is `true` then the `db` passed to this method
67
+ * is a transaction inside which the migrations will be executed. Otherwise
68
+ * `db` is a single connection (session) that will be used to execute the
69
+ * migrations.
70
+ */
71
+ acquireMigrationLock(db: Kysely<any>, opt: MigrationLockOptions): Promise<void>;
72
+ /**
73
+ * Releases the migration lock. See {@link acquireMigrationLock}.
74
+ *
75
+ * If `supportsTransactionalDdl` is `true` then the `db` passed to this method
76
+ * is a transaction inside which the migrations were executed. Otherwise `db`
77
+ * is a single connection (session) that was used to execute the migrations
78
+ * and the `acquireMigrationLock` call.
79
+ */
80
+ releaseMigrationLock(_db: Kysely<any>, _opt: MigrationLockOptions): Promise<void>;
81
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PostgresAdapter = void 0;
4
+ const dialect_adapter_base_js_1 = require("../dialect-adapter-base.js");
5
+ // Random id for our migration lock
6
+ const MIGRATION_LOCK_ID = '0.0.1';
7
+ class PostgresAdapter extends dialect_adapter_base_js_1.DialectAdapterBase {
8
+ get supportsTransactionalDdl() {
9
+ return true;
10
+ }
11
+ get supportsReturning() {
12
+ return true;
13
+ }
14
+ async acquireMigrationLock(db, opt) {
15
+ const lockTable = opt.lockTable ?? 'kysely_migration_lock';
16
+ // Postgres uses advisory locks. We need to create a unique lock id
17
+ // from the lock table name. We use a simple hash function for that.
18
+ const lockId = this.#hashString(lockTable);
19
+ await db
20
+ .selectFrom(lockTable)
21
+ .selectAll()
22
+ .where('id', '=', MIGRATION_LOCK_ID)
23
+ .forUpdate()
24
+ .execute();
25
+ }
26
+ async releaseMigrationLock(_db, _opt) {
27
+ // Nothing to do here. The migration lock is automatically released
28
+ // when the transaction is committed/rolled back.
29
+ }
30
+ #hashString(str) {
31
+ let hash = 0;
32
+ for (let i = 0; i < str.length; i++) {
33
+ const chr = str.charCodeAt(i);
34
+ hash = (hash << 5) - hash + chr;
35
+ hash |= 0; // Convert to 32bit integer
36
+ }
37
+ return hash;
38
+ }
39
+ }
40
+ exports.PostgresAdapter = PostgresAdapter;
@@ -0,0 +1,65 @@
1
+ import { DatabaseConnection } from '../../driver/database-connection.js';
2
+ import type { PoolConfig } from 'pg';
3
+ /**
4
+ * Config for the PostgreSQL dialect.
5
+ */
6
+ export interface PostgresDialectConfig {
7
+ /**
8
+ * A postgres Pool instance or a function that returns one.
9
+ *
10
+ * If a function is provided, it's called once when the first query is executed.
11
+ *
12
+ * https://node-postgres.com/apis/pool
13
+ */
14
+ pool?: PostgresPool | (() => Promise<PostgresPool>);
15
+ /**
16
+ * Pool configuration for PostgreSQL
17
+ *
18
+ * https://node-postgres.com/apis/pool
19
+ */
20
+ poolConfig?: PoolConfig;
21
+ /**
22
+ * Called once for each created connection.
23
+ *
24
+ * This is a NOORMME specific feature and does not come from the `pg` module.
25
+ */
26
+ onCreateConnection?: (connection: DatabaseConnection) => Promise<void>;
27
+ /**
28
+ * Cursor constructor for streaming queries.
29
+ */
30
+ cursor?: PostgresCursorConstructor;
31
+ }
32
+ /**
33
+ * This interface is the subset of pg Pool that NOORMME needs.
34
+ *
35
+ * We don't use the type from `pg` here to not have a dependency to it.
36
+ *
37
+ * https://node-postgres.com/apis/pool
38
+ */
39
+ export interface PostgresPool {
40
+ connect(): Promise<PostgresPoolClient>;
41
+ end(): Promise<void>;
42
+ query<R = any>(sql: string, parameters?: ReadonlyArray<unknown>): Promise<PostgresQueryResult<R>>;
43
+ }
44
+ export interface PostgresPoolClient {
45
+ query<R = any>(sql: string, parameters?: ReadonlyArray<unknown>): Promise<PostgresQueryResult<R>>;
46
+ release(): void;
47
+ }
48
+ export interface PostgresQueryResult<R = any> {
49
+ command: string;
50
+ rowCount: number | null;
51
+ rows: R[];
52
+ }
53
+ /**
54
+ * https://github.com/brianc/node-pg-cursor
55
+ */
56
+ export interface PostgresCursorConstructor {
57
+ new (text: string, values: unknown[], config?: unknown): PostgresCursor;
58
+ }
59
+ /**
60
+ * https://github.com/brianc/node-pg-cursor
61
+ */
62
+ export interface PostgresCursor extends AsyncIterableIterator<any> {
63
+ read(rowCount: number): Promise<any[]>;
64
+ close(): Promise<void>;
65
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,80 @@
1
+ import { Driver } from '../../driver/driver.js';
2
+ import { Kysely } from '../../kysely.js';
3
+ import { QueryCompiler } from '../../query-compiler/query-compiler.js';
4
+ import { Dialect } from '../dialect.js';
5
+ import { DatabaseIntrospector } from '../database-introspector.js';
6
+ import { DialectAdapter } from '../dialect-adapter.js';
7
+ import { PostgresDialectConfig } from './postgresql-dialect-config.js';
8
+ /**
9
+ * PostgreSQL dialect that uses the [pg](https://github.com/brianc/node-postgres) library.
10
+ *
11
+ * The constructor takes an instance of {@link PostgresDialectConfig}.
12
+ *
13
+ * ```ts
14
+ * import { Pool } from 'pg'
15
+ *
16
+ * new PostgresDialect({
17
+ * pool: new Pool({
18
+ * host: 'localhost',
19
+ * database: 'my_database',
20
+ * user: 'postgres',
21
+ * password: 'postgres',
22
+ * port: 5432,
23
+ * max: 10,
24
+ * })
25
+ * })
26
+ * ```
27
+ *
28
+ * Alternatively, you can use poolConfig:
29
+ *
30
+ * ```ts
31
+ * new PostgresDialect({
32
+ * poolConfig: {
33
+ * host: 'localhost',
34
+ * database: 'my_database',
35
+ * user: 'postgres',
36
+ * password: 'postgres',
37
+ * port: 5432,
38
+ * max: 10,
39
+ * }
40
+ * })
41
+ * ```
42
+ *
43
+ * If you want the pool to only be created once it's first used, `pool`
44
+ * can be a function:
45
+ *
46
+ * ```ts
47
+ * import { Pool } from 'pg'
48
+ *
49
+ * new PostgresDialect({
50
+ * pool: async () => new Pool({
51
+ * host: 'localhost',
52
+ * database: 'my_database',
53
+ * })
54
+ * })
55
+ * ```
56
+ */
57
+ export declare class PostgresDialect implements Dialect {
58
+ #private;
59
+ constructor(config: PostgresDialectConfig);
60
+ /**
61
+ * Creates a driver for the dialect.
62
+ */
63
+ createDriver(): Driver;
64
+ /**
65
+ * Creates a query compiler for the dialect.
66
+ */
67
+ createQueryCompiler(): QueryCompiler;
68
+ /**
69
+ * Creates an adapter for the dialect.
70
+ */
71
+ createAdapter(): DialectAdapter;
72
+ /**
73
+ * Creates a database introspector that can be used to get database metadata
74
+ * such as the table names and column names of those tables.
75
+ *
76
+ * `db` never has any plugins installed. It's created using
77
+ * {@link Kysely.withoutPlugins}.
78
+ */
79
+ createIntrospector(db: Kysely<any>): DatabaseIntrospector;
80
+ }