data-api-client 2.0.0 → 2.1.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/README.md CHANGED
@@ -3,16 +3,34 @@
3
3
  [![npm](https://img.shields.io/npm/v/data-api-client.svg)](https://www.npmjs.com/package/data-api-client)
4
4
  [![npm](https://img.shields.io/npm/l/data-api-client.svg)](https://www.npmjs.com/package/data-api-client)
5
5
 
6
- > **Note:** Version 2.0.0 is currently in active development. We welcome your feedback and bug reports! Please [open an issue](https://github.com/jeremydaly/data-api-client/issues) if you encounter any problems or have suggestions for improvement.
6
+ > **Note:** Version 2.1.0 introduces mysql2 and pg compatibility layers with full ORM support! We welcome your feedback and bug reports. Please [open an issue](https://github.com/jeremydaly/data-api-client/issues) if you encounter any problems or have suggestions for improvement.
7
7
  >
8
8
  > **Using v1.x?** See [README_v1.md](README_v1.md) for v1.x documentation.
9
9
 
10
- The **Data API Client** is a lightweight wrapper that simplifies working with the Amazon Aurora Serverless Data API by abstracting away the notion of field values. This abstraction annotates native JavaScript types supplied as input parameters, as well as converts annotated response data to native JavaScript types. It's basically a [DocumentClient](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html) for the Data API. It also dramatically simplifies **transactions** and uses modern async/await patterns with AWS SDK v3.
10
+ The **Data API Client** is a lightweight wrapper that simplifies working with the Amazon Aurora Serverless Data API by abstracting away the notion of field values. This abstraction annotates native JavaScript types supplied as input parameters, as well as converts annotated response data to native JavaScript types. It's basically a [DocumentClient](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html) for the Data API. It also dramatically simplifies **transactions**, provides **automatic retry logic** for scale-to-zero clusters, and includes **compatibility layers** for mysql2 and pg with full **ORM support**.
11
11
 
12
- **Version 2.0** introduces support for the new [RDS Data API for Aurora Serverless v2 and Aurora provisioned database instances](https://aws.amazon.com/about-aws/whats-new/2024/09/amazon-aurora-mysql-rds-data-api/), enhanced [Amazon Aurora PostgreSQL-Compatible Edition](https://aws.amazon.com/about-aws/whats-new/2023/12/amazon-aurora-postgresql-rds-data-api/) support, migration to AWS SDK v3, full TypeScript implementation, and comprehensive PostgreSQL data type coverage including **automatic array handling**.
12
+ **Version 2.1** adds mysql2 and pg compatibility layers, automatic retry logic for cluster wake-ups, and verified support for Drizzle ORM and Kysely query builder.
13
+
14
+ **Version 2.0** introduced support for the new [RDS Data API for Aurora Serverless v2 and Aurora provisioned database instances](https://aws.amazon.com/about-aws/whats-new/2024/09/amazon-aurora-mysql-rds-data-api/), enhanced [Amazon Aurora PostgreSQL-Compatible Edition](https://aws.amazon.com/about-aws/whats-new/2023/12/amazon-aurora-postgresql-rds-data-api/) support, migration to AWS SDK v3, full TypeScript implementation, and comprehensive PostgreSQL data type coverage including **automatic array handling**.
13
15
 
14
16
  For more information about the Aurora Serverless Data API, you can review the [official documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) or read [Aurora Serverless Data API: An (updated) First Look](https://www.jeremydaly.com/aurora-serverless-data-api-a-first-look/) for some more insights on performance.
15
17
 
18
+ ## What's New in v2.1
19
+
20
+ - **Automatic Retry Logic**: Built-in retry handling for Aurora Serverless scale-to-zero wake-ups
21
+ - Smart detection of `DatabaseResumingException` with optimized retry delays
22
+ - Automatic handling of connection errors with exponential backoff
23
+ - Configurable and enabled by default
24
+ - **mysql2 Compatibility Layer**: Drop-in replacement for the `mysql2/promise` library
25
+ - Full support for connection pools and transactions
26
+ - Works seamlessly with ORMs like Drizzle and Kysely
27
+ - **pg Compatibility Layer**: Drop-in replacement for the `pg` (node-postgres) library
28
+ - Promise-based and callback-based APIs
29
+ - Compatible with ORMs and query builders
30
+ - **ORM Support**: Tested and verified with popular ORMs:
31
+ - **Drizzle ORM**: Full support for both MySQL and PostgreSQL
32
+ - **Kysely**: Query builder support for both engines
33
+
16
34
  ## What's New in v2.0
17
35
 
18
36
  - **AWS SDK v3**: Migrated from AWS SDK v2 to v3 for smaller bundle sizes and better tree-shaking
@@ -188,6 +206,46 @@ Below is a table containing all of the possible configuration options for the `d
188
206
  | hydrateColumnNames | `boolean` | When `true`, results will be returned as objects with column names as keys. If `false`, results will be returned as an array of values. | `true` |
189
207
  | options | `object` | An _optional_ configuration object that is passed directly into the RDSDataClient constructor. See [AWS SDK docs](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-rds-data/classes/rdsdataclient.html) for available options. | `{}` |
190
208
  | formatOptions | `object` | Formatting options to auto parse dates and coerce native JavaScript date objects to supported date formats. Valid keys are `deserializeDate` and `treatAsLocalDate`. Both accept boolean values. | `deserializeDate: true, treatAsLocalDate: false` |
209
+ | retryOptions | `object` | Configuration for automatic retry logic. Valid keys are `enabled` (boolean), `maxRetries` (number), and `retryableErrors` (string array). | `enabled: true, maxRetries: 9` |
210
+
211
+ ### Automatic Retry Logic
212
+
213
+ Version 2.1 includes built-in retry logic to handle Aurora Serverless scale-to-zero cluster wake-ups automatically. When your cluster is paused and needs to resume, the client will automatically retry your queries with optimized delays.
214
+
215
+ **Features:**
216
+ - **Smart Error Detection**: Automatically detects `DatabaseResumingException` and connection errors
217
+ - **Strategy-Based Retries**: Different retry strategies based on error type:
218
+ - DatabaseResumingException: Up to 10 attempts with progressive delays (0s, 2s, 5s, 10s, 15s, 20s, 25s, 30s, 35s, 40s)
219
+ - Connection errors: 3 quick retries with exponential backoff (0s, 2s, 4s)
220
+ - **Enabled by Default**: Works automatically without any configuration
221
+ - **Configurable**: Customize retry behavior per your needs
222
+
223
+ **Configuration:**
224
+
225
+ ```javascript
226
+ const data = dataApiClient({
227
+ secretArn: 'arn:...',
228
+ resourceArn: 'arn:...',
229
+ database: 'myDatabase',
230
+ retryOptions: {
231
+ enabled: true, // Enable/disable retries (default: true)
232
+ maxRetries: 9, // Maximum retry attempts (default: 9 for up to 40s total)
233
+ retryableErrors: [] // Additional error patterns to retry (optional)
234
+ }
235
+ })
236
+ ```
237
+
238
+ **Disable retries** (not recommended for scale-to-zero clusters):
239
+
240
+ ```javascript
241
+ const data = dataApiClient({
242
+ secretArn: 'arn:...',
243
+ resourceArn: 'arn:...',
244
+ retryOptions: { enabled: false }
245
+ })
246
+ ```
247
+
248
+ The retry logic works seamlessly across all operations: queries, transactions, batch operations, and compatibility layer methods.
191
249
 
192
250
  ### Connection Reuse
193
251
 
@@ -455,6 +513,185 @@ const data = dataApiClient({
455
513
  })
456
514
  ```
457
515
 
516
+ ## mysql2 and pg Compatibility Layers
517
+
518
+ Version 2.1 introduces compatibility layers that allow you to use the Data API Client as a drop-in replacement for popular database libraries. This makes it easy to migrate existing applications or use ORMs without modification.
519
+
520
+ ### mysql2 Compatibility
521
+
522
+ Use the Data API Client as a replacement for `mysql2/promise`:
523
+
524
+ ```javascript
525
+ import { createMySQLConnection, createMySQLPool } from 'data-api-client/compat/mysql2'
526
+
527
+ // Create a connection
528
+ const connection = createMySQLConnection({
529
+ resourceArn: 'arn:aws:rds:us-east-1:XXXXXXXXXXXX:cluster:my-cluster',
530
+ secretArn: 'arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:mySecret',
531
+ database: 'myDatabase'
532
+ })
533
+
534
+ // Use like mysql2/promise
535
+ const [rows, fields] = await connection.query('SELECT * FROM users WHERE id = ?', [123])
536
+ await connection.execute('INSERT INTO users (name, email) VALUES (?, ?)', ['Alice', 'alice@example.com'])
537
+
538
+ // Note: connection.end() is optional - it's a no-op for Data API (no connection to close)
539
+
540
+ // Create a pool for connection pooling
541
+ const pool = createMySQLPool({
542
+ resourceArn: 'arn:...',
543
+ secretArn: 'arn:...',
544
+ database: 'myDatabase'
545
+ })
546
+
547
+ // Get connection from pool
548
+ pool.getConnection((err, connection) => {
549
+ if (err) throw err
550
+ connection.query('SELECT * FROM users', (err, results) => {
551
+ connection.release() // Optional - no-op for Data API
552
+ // Handle results
553
+ })
554
+ })
555
+
556
+ // Or use promises
557
+ const connection = await pool.getConnection()
558
+ const [rows] = await connection.query('SELECT * FROM users')
559
+ connection.release() // Optional - no-op for Data API
560
+ ```
561
+
562
+ ### pg Compatibility
563
+
564
+ Use the Data API Client as a replacement for `pg` (node-postgres):
565
+
566
+ ```javascript
567
+ import { createPgClient, createPgPool } from 'data-api-client/compat/pg'
568
+
569
+ // Create a client
570
+ const client = createPgClient({
571
+ resourceArn: 'arn:aws:rds:us-east-1:XXXXXXXXXXXX:cluster:my-cluster',
572
+ secretArn: 'arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:mySecret',
573
+ database: 'myDatabase'
574
+ })
575
+
576
+ // Note: client.connect() is optional - it's a no-op for Data API (no connection needed)
577
+ await client.connect() // Optional
578
+
579
+ // Use like pg
580
+ const result = await client.query('SELECT * FROM users WHERE id = $1', [123])
581
+ console.log(result.rows)
582
+
583
+ // With callback style
584
+ client.query('SELECT * FROM users', (err, result) => {
585
+ console.log(result.rows)
586
+ })
587
+
588
+ // Note: client.end() is optional - it's a no-op for Data API (no connection to close)
589
+ await client.end() // Optional
590
+
591
+ // Create a pool
592
+ const pool = createPgPool({
593
+ resourceArn: 'arn:...',
594
+ secretArn: 'arn:...',
595
+ database: 'myDatabase'
596
+ })
597
+
598
+ const result = await pool.query('SELECT * FROM users WHERE id = $1', [123])
599
+ ```
600
+
601
+ ### Using with ORMs
602
+
603
+ The compatibility layers work seamlessly with popular ORMs:
604
+
605
+ #### Drizzle ORM
606
+
607
+ **MySQL with Drizzle:**
608
+
609
+ ```typescript
610
+ import { drizzle } from 'drizzle-orm/mysql2'
611
+ import { createMySQLPool } from 'data-api-client/compat/mysql2'
612
+
613
+ const pool = createMySQLPool({
614
+ resourceArn: 'arn:...',
615
+ secretArn: 'arn:...',
616
+ database: 'myDatabase'
617
+ })
618
+
619
+ const db = drizzle(pool as any)
620
+
621
+ // Use Drizzle normally
622
+ const users = await db.select().from(usersTable).where(eq(usersTable.id, 123))
623
+ ```
624
+
625
+ **PostgreSQL with Drizzle:**
626
+
627
+ ```typescript
628
+ import { drizzle } from 'drizzle-orm/node-postgres'
629
+ import { createPgClient } from 'data-api-client/compat/pg'
630
+
631
+ const client = createPgClient({
632
+ resourceArn: 'arn:...',
633
+ secretArn: 'arn:...',
634
+ database: 'myDatabase'
635
+ })
636
+
637
+ // Note: client.connect() is optional (no-op for Data API)
638
+ await client.connect() // Optional - can be omitted
639
+ const db = drizzle(client as any)
640
+
641
+ // Use Drizzle normally
642
+ const users = await db.select().from(usersTable).where(eq(usersTable.id, 123))
643
+ ```
644
+
645
+ #### Kysely Query Builder
646
+
647
+ **MySQL with Kysely:**
648
+
649
+ ```typescript
650
+ import { Kysely, MysqlDialect } from 'kysely'
651
+ import { createMySQLPool } from 'data-api-client/compat/mysql2'
652
+
653
+ const pool = createMySQLPool({
654
+ resourceArn: 'arn:...',
655
+ secretArn: 'arn:...',
656
+ database: 'myDatabase'
657
+ })
658
+
659
+ const db = new Kysely<Database>({
660
+ dialect: new MysqlDialect({ pool: pool as any })
661
+ })
662
+
663
+ // Use Kysely normally
664
+ const users = await db.selectFrom('users').selectAll().where('id', '=', 123).execute()
665
+ ```
666
+
667
+ **PostgreSQL with Kysely:**
668
+
669
+ ```typescript
670
+ import { Kysely, PostgresDialect } from 'kysely'
671
+ import { createPgPool } from 'data-api-client/compat/pg'
672
+
673
+ const pool = createPgPool({
674
+ resourceArn: 'arn:...',
675
+ secretArn: 'arn:...',
676
+ database: 'myDatabase'
677
+ })
678
+
679
+ const db = new Kysely<Database>({
680
+ dialect: new PostgresDialect({ pool: pool as any })
681
+ })
682
+
683
+ // Use Kysely normally
684
+ const users = await db.selectFrom('users').selectAll().where('id', '=', 123).execute()
685
+ ```
686
+
687
+ **Benefits of Compatibility Layers:**
688
+ - **Zero code changes** when migrating from mysql2 or pg
689
+ - **Full ORM support** (Drizzle, Kysely)
690
+ - **Automatic retry logic** for cluster wake-ups
691
+ - **Connection pooling simulation** (getConnection, release)
692
+ - **Both Promise and callback APIs** supported
693
+ - **No-op connection management**: `connect()`, `end()`, and `release()` are optional since the Data API is connectionless - they're included only for backward compatibility with existing code
694
+
458
695
  ## PostgreSQL Array Support
459
696
 
460
697
  One of the most powerful features in v2.0 is automatic PostgreSQL array handling. While the Data API has limitations with array _parameters_, array _results_ are fully supported and automatically converted to native JavaScript arrays.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAkB,aAAa,EAA6B,MAAM,SAAS,CAAA;AAyB5G,eAAO,MAAM,IAAI,GAAI,QAAQ,mBAAmB,KAAG,aAkHlD,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAkB,aAAa,EAA6B,MAAM,SAAS,CAAA;AA0B5G,eAAO,MAAM,IAAI,GAAI,QAAQ,mBAAmB,KAAG,aAoJlD,CAAA"}
package/dist/client.js CHANGED
@@ -5,6 +5,7 @@ const client_rds_data_1 = require("@aws-sdk/client-rds-data");
5
5
  const utils_1 = require("./utils");
6
6
  const query_1 = require("./query");
7
7
  const transaction_1 = require("./transaction");
8
+ const retry_1 = require("./retry");
8
9
  const init = (params) => {
9
10
  const options = typeof params.options === 'object'
10
11
  ? params.options
@@ -31,39 +32,48 @@ const init = (params) => {
31
32
  deserializeDate: typeof params.formatOptions === 'object' && params.formatOptions.deserializeDate === false ? false : true,
32
33
  treatAsLocalDate: typeof params.formatOptions === 'object' && params.formatOptions.treatAsLocalDate ? true : false
33
34
  },
35
+ retryOptions: {
36
+ enabled: typeof params.retryOptions === 'object' && params.retryOptions.enabled === false ? false : true,
37
+ maxRetries: typeof params.retryOptions === 'object' && typeof params.retryOptions.maxRetries === 'number'
38
+ ? params.retryOptions.maxRetries
39
+ : 9,
40
+ retryableErrors: typeof params.retryOptions === 'object' && Array.isArray(params.retryOptions.retryableErrors)
41
+ ? params.retryOptions.retryableErrors
42
+ : []
43
+ },
34
44
  RDS: params.client ? params.client : new client_rds_data_1.RDSDataClient(options)
35
45
  };
36
46
  return {
37
47
  query: (...x) => query_1.query.call(undefined, config, ...x),
38
48
  transaction: (x) => (0, transaction_1.transaction)(config, x),
39
- batchExecuteStatement: async (args) => config.RDS.send(new client_rds_data_1.BatchExecuteStatementCommand({
49
+ batchExecuteStatement: async (args) => (0, retry_1.withRetry)(() => config.RDS.send(new client_rds_data_1.BatchExecuteStatementCommand({
40
50
  ...args,
41
51
  resourceArn: args.resourceArn || config.resourceArn,
42
52
  secretArn: args.secretArn || config.secretArn,
43
53
  database: args.database || config.database
44
- })),
45
- beginTransaction: async (args) => config.RDS.send(new client_rds_data_1.BeginTransactionCommand({
54
+ })), config.retryOptions),
55
+ beginTransaction: async (args) => (0, retry_1.withRetry)(() => config.RDS.send(new client_rds_data_1.BeginTransactionCommand({
46
56
  ...(args || {}),
47
57
  resourceArn: (args === null || args === void 0 ? void 0 : args.resourceArn) || config.resourceArn,
48
58
  secretArn: (args === null || args === void 0 ? void 0 : args.secretArn) || config.secretArn,
49
59
  database: (args === null || args === void 0 ? void 0 : args.database) || config.database
50
- })),
51
- commitTransaction: async (args) => config.RDS.send(new client_rds_data_1.CommitTransactionCommand({
60
+ })), config.retryOptions),
61
+ commitTransaction: async (args) => (0, retry_1.withRetry)(() => config.RDS.send(new client_rds_data_1.CommitTransactionCommand({
52
62
  ...args,
53
63
  resourceArn: args.resourceArn || config.resourceArn,
54
64
  secretArn: args.secretArn || config.secretArn
55
- })),
56
- executeStatement: async (args) => config.RDS.send(new client_rds_data_1.ExecuteStatementCommand({
65
+ })), config.retryOptions),
66
+ executeStatement: async (args) => (0, retry_1.withRetry)(() => config.RDS.send(new client_rds_data_1.ExecuteStatementCommand({
57
67
  ...args,
58
68
  resourceArn: args.resourceArn || config.resourceArn,
59
69
  secretArn: args.secretArn || config.secretArn,
60
70
  database: args.database || config.database
61
- })),
62
- rollbackTransaction: async (args) => config.RDS.send(new client_rds_data_1.RollbackTransactionCommand({
71
+ })), config.retryOptions),
72
+ rollbackTransaction: async (args) => (0, retry_1.withRetry)(() => config.RDS.send(new client_rds_data_1.RollbackTransactionCommand({
63
73
  ...args,
64
74
  resourceArn: args.resourceArn || config.resourceArn,
65
75
  secretArn: args.secretArn || config.secretArn
66
- }))
76
+ })), config.retryOptions)
67
77
  };
68
78
  };
69
79
  exports.init = init;
@@ -0,0 +1,28 @@
1
+ export interface PostgresError extends Error {
2
+ code?: string;
3
+ severity?: string;
4
+ detail?: string;
5
+ hint?: string;
6
+ position?: string;
7
+ internalPosition?: string;
8
+ internalQuery?: string;
9
+ where?: string;
10
+ schema?: string;
11
+ table?: string;
12
+ column?: string;
13
+ dataType?: string;
14
+ constraint?: string;
15
+ file?: string;
16
+ line?: string;
17
+ routine?: string;
18
+ }
19
+ export interface MySQLError extends Error {
20
+ code?: string;
21
+ errno?: number;
22
+ sqlState?: string;
23
+ sqlMessage?: string;
24
+ sql?: string;
25
+ }
26
+ export declare function mapToPostgresError(error: any): PostgresError;
27
+ export declare function mapToMySQLError(error: any): MySQLError;
28
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/compat/errors.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAc,SAAQ,KAAK;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAKD,MAAM,WAAW,UAAW,SAAQ,KAAK;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AA6BD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,aAAa,CAgE5D;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,UAAU,CA+GtD"}
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapToPostgresError = mapToPostgresError;
4
+ exports.mapToMySQLError = mapToMySQLError;
5
+ function extractConstraintName(message) {
6
+ const match = message.match(/constraint "([^"]+)"/);
7
+ return match ? match[1] : undefined;
8
+ }
9
+ function extractTableName(message) {
10
+ const match = message.match(/table "([^"]+)"/);
11
+ return match ? match[1] : undefined;
12
+ }
13
+ function extractColumnName(message) {
14
+ const match = message.match(/column "([^"]+)"/);
15
+ return match ? match[1] : undefined;
16
+ }
17
+ function mapToPostgresError(error) {
18
+ var _a, _b;
19
+ const pgError = new Error(error.message);
20
+ pgError.name = 'error';
21
+ pgError.severity = 'ERROR';
22
+ const message = error.message || '';
23
+ if (message.includes('duplicate key') || message.includes('already exists')) {
24
+ pgError.code = '23505';
25
+ pgError.constraint = extractConstraintName(message);
26
+ pgError.detail = (_a = message.match(/Detail: (.+)/)) === null || _a === void 0 ? void 0 : _a[1];
27
+ }
28
+ else if (message.includes('violates foreign key constraint')) {
29
+ pgError.code = '23503';
30
+ pgError.constraint = extractConstraintName(message);
31
+ pgError.table = extractTableName(message);
32
+ }
33
+ else if (message.includes('violates not-null constraint')) {
34
+ pgError.code = '23502';
35
+ pgError.column = extractColumnName(message);
36
+ pgError.table = extractTableName(message);
37
+ }
38
+ else if (message.includes('violates check constraint')) {
39
+ pgError.code = '23514';
40
+ pgError.constraint = extractConstraintName(message);
41
+ }
42
+ else if (message.includes('syntax error')) {
43
+ pgError.code = '42601';
44
+ pgError.position = (_b = message.match(/at or near "(.+?)"/)) === null || _b === void 0 ? void 0 : _b[1];
45
+ }
46
+ else if (message.includes('column') && message.includes('does not exist')) {
47
+ pgError.code = '42703';
48
+ pgError.column = extractColumnName(message);
49
+ }
50
+ else if (message.includes('relation') && message.includes('does not exist')) {
51
+ pgError.code = '42P01';
52
+ pgError.table = extractTableName(message);
53
+ }
54
+ else if (message.includes('function') && message.includes('does not exist')) {
55
+ pgError.code = '42883';
56
+ }
57
+ else if (message.includes('invalid input syntax')) {
58
+ pgError.code = '22P02';
59
+ }
60
+ else if (message.includes('division by zero')) {
61
+ pgError.code = '22012';
62
+ }
63
+ else if (message.includes('value too long')) {
64
+ pgError.code = '22001';
65
+ }
66
+ else if (message.includes('permission denied')) {
67
+ pgError.code = '42501';
68
+ }
69
+ else if (message.includes('connection') || message.includes('timeout')) {
70
+ pgError.code = '08006';
71
+ }
72
+ else {
73
+ pgError.code = 'EUNKNOWN';
74
+ }
75
+ return pgError;
76
+ }
77
+ function mapToMySQLError(error) {
78
+ const mysqlError = new Error(error.message);
79
+ mysqlError.sqlMessage = error.message || '';
80
+ const message = error.message || '';
81
+ if (message.includes('Duplicate entry') || message.includes('duplicate key')) {
82
+ mysqlError.code = 'ER_DUP_ENTRY';
83
+ mysqlError.errno = 1062;
84
+ mysqlError.sqlState = '23000';
85
+ }
86
+ else if (message.includes('foreign key constraint fails')) {
87
+ if (message.includes('Cannot delete or update a parent row')) {
88
+ mysqlError.code = 'ER_ROW_IS_REFERENCED_2';
89
+ mysqlError.errno = 1451;
90
+ }
91
+ else {
92
+ mysqlError.code = 'ER_NO_REFERENCED_ROW_2';
93
+ mysqlError.errno = 1452;
94
+ }
95
+ mysqlError.sqlState = '23000';
96
+ }
97
+ else if (message.includes('cannot be null') || message.includes('NOT NULL')) {
98
+ mysqlError.code = 'ER_BAD_NULL_ERROR';
99
+ mysqlError.errno = 1048;
100
+ mysqlError.sqlState = '23000';
101
+ }
102
+ else if (message.includes("Table") && message.includes("doesn't exist")) {
103
+ mysqlError.code = 'ER_NO_SUCH_TABLE';
104
+ mysqlError.errno = 1146;
105
+ mysqlError.sqlState = '42S02';
106
+ }
107
+ else if (message.includes('Unknown column')) {
108
+ mysqlError.code = 'ER_BAD_FIELD_ERROR';
109
+ mysqlError.errno = 1054;
110
+ mysqlError.sqlState = '42S22';
111
+ }
112
+ else if (message.includes('syntax') || message.includes('SQL syntax')) {
113
+ mysqlError.code = 'ER_PARSE_ERROR';
114
+ mysqlError.errno = 1064;
115
+ mysqlError.sqlState = '42000';
116
+ }
117
+ else if (message.includes('Data too long') || message.includes('too long')) {
118
+ mysqlError.code = 'ER_DATA_TOO_LONG';
119
+ mysqlError.errno = 1406;
120
+ mysqlError.sqlState = '22001';
121
+ }
122
+ else if (message.includes('Division by 0')) {
123
+ mysqlError.code = 'ER_DIVISION_BY_ZERO';
124
+ mysqlError.errno = 1365;
125
+ mysqlError.sqlState = '22012';
126
+ }
127
+ else if (message.includes('Access denied')) {
128
+ mysqlError.code = 'ER_ACCESS_DENIED_ERROR';
129
+ mysqlError.errno = 1045;
130
+ mysqlError.sqlState = '28000';
131
+ }
132
+ else if (message.includes('Deadlock')) {
133
+ mysqlError.code = 'ER_LOCK_DEADLOCK';
134
+ mysqlError.errno = 1213;
135
+ mysqlError.sqlState = '40001';
136
+ }
137
+ else if (message.includes('Lock wait timeout')) {
138
+ mysqlError.code = 'ER_LOCK_WAIT_TIMEOUT';
139
+ mysqlError.errno = 1205;
140
+ mysqlError.sqlState = 'HY000';
141
+ }
142
+ else if (message.includes("Can't connect")) {
143
+ mysqlError.code = 'ER_CONNECTION_ERROR';
144
+ mysqlError.errno = 2003;
145
+ mysqlError.sqlState = 'HY000';
146
+ }
147
+ else if (message.includes('server has gone away')) {
148
+ mysqlError.code = 'ER_SERVER_GONE_ERROR';
149
+ mysqlError.errno = 2006;
150
+ mysqlError.sqlState = 'HY000';
151
+ }
152
+ else if (message.includes('Lost connection')) {
153
+ mysqlError.code = 'ER_SERVER_LOST';
154
+ mysqlError.errno = 2013;
155
+ mysqlError.sqlState = 'HY000';
156
+ }
157
+ else {
158
+ mysqlError.code = 'EUNKNOWN';
159
+ mysqlError.errno = 0;
160
+ mysqlError.sqlState = 'HY000';
161
+ }
162
+ return mysqlError;
163
+ }
@@ -0,0 +1,7 @@
1
+ export { createPgClient, createPgPool } from './pg';
2
+ export type { PgCompatClient, PgCompatPool, PgQueryResult } from './pg';
3
+ export { createMySQLConnection, createMySQLPool } from './mysql2';
4
+ export type { Connection, Pool, PoolConnection, MySQL2QueryResult } from './mysql2';
5
+ export { mapToPostgresError, mapToMySQLError } from './errors';
6
+ export type { PostgresError, MySQLError } from './errors';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compat/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,MAAM,CAAA;AACnD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAEvE,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AACjE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAEnF,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC9D,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapToMySQLError = exports.mapToPostgresError = exports.createMySQLPool = exports.createMySQLConnection = exports.createPgPool = exports.createPgClient = void 0;
4
+ var pg_1 = require("./pg");
5
+ Object.defineProperty(exports, "createPgClient", { enumerable: true, get: function () { return pg_1.createPgClient; } });
6
+ Object.defineProperty(exports, "createPgPool", { enumerable: true, get: function () { return pg_1.createPgPool; } });
7
+ var mysql2_1 = require("./mysql2");
8
+ Object.defineProperty(exports, "createMySQLConnection", { enumerable: true, get: function () { return mysql2_1.createMySQLConnection; } });
9
+ Object.defineProperty(exports, "createMySQLPool", { enumerable: true, get: function () { return mysql2_1.createMySQLPool; } });
10
+ var errors_1 = require("./errors");
11
+ Object.defineProperty(exports, "mapToPostgresError", { enumerable: true, get: function () { return errors_1.mapToPostgresError; } });
12
+ Object.defineProperty(exports, "mapToMySQLError", { enumerable: true, get: function () { return errors_1.mapToMySQLError; } });
@@ -0,0 +1,86 @@
1
+ import { EventEmitter } from 'events';
2
+ import type { DataAPIClientConfig } from '../types';
3
+ export interface PoolConnection extends Connection {
4
+ release?: () => void;
5
+ }
6
+ export interface Connection extends EventEmitter {
7
+ connect(callback?: (err: Error | null) => void): Promise<void>;
8
+ end(callback?: (err?: Error) => void): Promise<void>;
9
+ query<R = any>(sql: string): Promise<[R[] | MySQL2QueryResult<R>, any]>;
10
+ query<R = any>(sql: string, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
11
+ query<R = any>(sql: string, params: any[]): Promise<[R[] | MySQL2QueryResult<R>, any]>;
12
+ query<R = any>(sql: string, params: any[], callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
13
+ query<R = any>(options: {
14
+ sql: string;
15
+ values?: any[];
16
+ }): Promise<[R[] | MySQL2QueryResult<R>, any]>;
17
+ query<R = any>(options: {
18
+ sql: string;
19
+ values?: any[];
20
+ }, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
21
+ execute<R = any>(sql: string): Promise<[R[] | MySQL2QueryResult<R>, any]>;
22
+ execute<R = any>(sql: string, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
23
+ execute<R = any>(sql: string, params: any[]): Promise<[R[] | MySQL2QueryResult<R>, any]>;
24
+ execute<R = any>(sql: string, params: any[], callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
25
+ execute<R = any>(options: {
26
+ sql: string;
27
+ values?: any[];
28
+ }): Promise<[R[] | MySQL2QueryResult<R>, any]>;
29
+ execute<R = any>(options: {
30
+ sql: string;
31
+ values?: any[];
32
+ }, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
33
+ beginTransaction(callback?: (err: Error | null) => void): Promise<void>;
34
+ commit(callback?: (err?: Error) => void): Promise<void>;
35
+ rollback(callback?: (err?: Error) => void): Promise<void>;
36
+ ping(callback?: (err?: Error) => void): Promise<void>;
37
+ }
38
+ export interface Pool extends EventEmitter {
39
+ getConnection(callback: (err: Error | null, connection: PoolConnection) => any): void;
40
+ getConnection(): Promise<PoolConnection>;
41
+ end(callback?: (err?: Error) => void): Promise<void>;
42
+ query<R = any>(sql: string): Promise<[R[] | MySQL2QueryResult<R>, any]>;
43
+ query<R = any>(sql: string, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
44
+ query<R = any>(sql: string, params: any[]): Promise<[R[] | MySQL2QueryResult<R>, any]>;
45
+ query<R = any>(sql: string, params: any[], callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
46
+ query<R = any>(options: {
47
+ sql: string;
48
+ values?: any[];
49
+ }): Promise<[R[] | MySQL2QueryResult<R>, any]>;
50
+ query<R = any>(options: {
51
+ sql: string;
52
+ values?: any[];
53
+ }, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
54
+ execute<R = any>(sql: string): Promise<[R[] | MySQL2QueryResult<R>, any]>;
55
+ execute<R = any>(sql: string, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
56
+ execute<R = any>(sql: string, params: any[]): Promise<[R[] | MySQL2QueryResult<R>, any]>;
57
+ execute<R = any>(sql: string, params: any[], callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
58
+ execute<R = any>(options: {
59
+ sql: string;
60
+ values?: any[];
61
+ }): Promise<[R[] | MySQL2QueryResult<R>, any]>;
62
+ execute<R = any>(options: {
63
+ sql: string;
64
+ values?: any[];
65
+ }, callback: (err: Error | null, results: R[] | MySQL2QueryResult<R>, fields: any) => void): Promise<void>;
66
+ releaseConnection(connection: PoolConnection): void;
67
+ promise(): Pool;
68
+ unprepare(sql: string): any;
69
+ config: DataAPIClientConfig;
70
+ }
71
+ export interface MySQL2QueryResult<R = any> {
72
+ rows?: R[];
73
+ fields?: Array<{
74
+ name: string;
75
+ type?: number;
76
+ table?: string;
77
+ database?: string;
78
+ }>;
79
+ insertId?: number;
80
+ affectedRows?: number;
81
+ changedRows?: number;
82
+ warningCount?: number;
83
+ }
84
+ export declare function createMySQLConnection(config: DataAPIClientConfig): Connection;
85
+ export declare function createMySQLPool(config: DataAPIClientConfig): Pool;
86
+ //# sourceMappingURL=mysql2.d.ts.map