Skip to content

v2.1.1 - Named Placeholders Support for mysql2 Compatibility Layer

Choose a tag to compare

@jeremydaly jeremydaly released this 12 Oct 14:27
· 49 commits to main since this release

New Features

Named Placeholders Support

We're excited to announce full support for named placeholders (:name syntax) in the mysql2 compatibility layer! This feature brings the popular mysql2 library's namedPlaceholders option to the Data API Client, making your queries more readable and maintainable.

Why Named Placeholders?

Instead of positional placeholders:

await connection.query(
  'SELECT * FROM users WHERE name = ? AND age > ? AND email = ?',
  ['Alice', 25, 'alice@example.com']
)

Use descriptive named placeholders:

await connection.query(
  'SELECT * FROM users WHERE name = :name AND age > :age AND email = :email',
  { name: 'Alice', age: 25, email: 'alice@example.com' }
)

Key Features

Connection-Level Configuration

Enable named placeholders globally for a connection or pool:

import { createMySQLConnection } from 'data-api-client/compat/mysql2'

const connection = createMySQLConnection({
  resourceArn: 'arn:aws:rds:us-east-1:xxx:cluster:my-cluster',
  secretArn: 'arn:aws:secretsmanager:us-east-1:xxx:secret:mySecret',
  database: 'myDatabase',
  namedPlaceholders: true  // Enable named placeholders
})

// All queries can now use named placeholders
await connection.query(
  'INSERT INTO users (name, email, age) VALUES (:name, :email, :age)',
  { name: 'Bob', email: 'bob@example.com', age: 30 }
)

Query-Level Override

Enable or disable named placeholders per query, overriding the connection setting:

// Connection without namedPlaceholders
const connection = createMySQLConnection({ /* ... */ })

// Enable for specific query
await connection.query(
  {
    sql: 'SELECT * FROM users WHERE username = :username AND age > :minAge',
    namedPlaceholders: true  // Enable for this query only
  },
  { username: 'john_doe', minAge: 25 }
)

// Or disable for a specific query (when connection has it enabled)
await connection.query(
  {
    sql: 'SELECT * FROM users WHERE id = ?',
    namedPlaceholders: false  // Use positional placeholders
  },
  [123]
)

Full Feature Support

All Query Types - Works with SELECT, INSERT, UPDATE, DELETE
Duplicate References - Same parameter can be used multiple times in a query
Transactions - Full support for beginTransaction(), commit(), rollback()
Connection Pools - Works with both direct pool queries and getConnection()
Callback Style - Compatible with both Promise and callback APIs
Numeric Parameters - Supports numeric parameter names like :1, :2
NULL Values - Proper handling of null parameter values

Usage Examples

Basic Usage

import { createMySQLConnection } from 'data-api-client/compat/mysql2'

const connection = createMySQLConnection({
  resourceArn: 'arn:...',
  secretArn: 'arn:...',
  database: 'myDatabase',
  namedPlaceholders: true
})

// SELECT
const [users] = await connection.query(
  'SELECT * FROM users WHERE age > :minAge AND active = :active',
  { minAge: 25, active: true }
)

// INSERT
await connection.query(
  'INSERT INTO users (name, email) VALUES (:name, :email)',
  { name: 'Alice', email: 'alice@example.com' }
)

// UPDATE
await connection.query(
  'UPDATE users SET age = :newAge WHERE id = :id',
  { id: 123, newAge: 31 }
)

// DELETE
await connection.query(
  'DELETE FROM users WHERE id = :id',
  { id: 456 }
)

With Transactions

await connection.beginTransaction()
try {
  await connection.query(
    'INSERT INTO orders (user_id, total) VALUES (:userId, :total)',
    { userId: 123, total: 99.99 }
  )
  await connection.query(
    'UPDATE users SET last_order = NOW() WHERE id = :userId',
    { userId: 123 }
  )
  await connection.commit()
} catch (err) {
  await connection.rollback()
  throw err
}

With Connection Pools

import { createMySQLPool } from 'data-api-client/compat/mysql2'

const pool = createMySQLPool({
  resourceArn: 'arn:...',
  secretArn: 'arn:...',
  database: 'myDatabase',
  namedPlaceholders: true
})

// Direct pool query
const [products] = await pool.query(
  'SELECT * FROM products WHERE category = :category AND price < :maxPrice',
  { category: 'electronics', maxPrice: 500 }
)

// Get connection from pool
const connection = await pool.getConnection()
const [orders] = await connection.query(
  'SELECT * FROM orders WHERE user_id = :userId',
  { userId: 123 }
)
connection.release()

Duplicate Parameter References

// Same parameter used multiple times
await connection.query(
  'SELECT * FROM users WHERE name = :name OR email = :name',
  { name: 'alice' }
)
// SQL: SELECT * FROM users WHERE name = ? OR email = ?
// Values: ['alice', 'alice']

Mixed Usage (Query-Level Override)

// Connection defaults to positional placeholders
const connection = createMySQLConnection({ /* ... */ })

// Use positional placeholders (default)
await connection.query('SELECT * FROM users WHERE id = ?', [123])

// Enable named placeholders for specific query
await connection.query(
  { sql: 'SELECT * FROM users WHERE name = :name', namedPlaceholders: true },
  { name: 'Alice' }
)

Configuration

Add the namedPlaceholders option to your connection or pool configuration:

Option Type Default Description
namedPlaceholders boolean false Enable named placeholders (:name syntax) for mysql2 compatibility layer. When true, parameters use object format.

You can also set namedPlaceholders per query in the query options object to override the connection-level setting.

Testing

This release includes comprehensive testing:

  • 118 unit tests passing
  • 49 integration tests passing (20 new tests for named placeholders)
  • Verified with Aurora Serverless MySQL clusters
  • Tested with transactions, pools, and callback styles

Documentation

See the Named Placeholders Support section in the README for complete documentation and examples.

Backward Compatibility

This feature is 100% backward compatible:

  • namedPlaceholders defaults to false
  • Existing code using positional ? placeholders continues to work unchanged
  • No breaking changes
  • Opt-in feature

Bug Fixes

No bug fixes in this release.

What's Changed

  • feat(mysql2): add namedPlaceholders configuration option in 6785281
  • feat(mysql2): implement namedPlaceholders support in 7172f3c
  • test(mysql2): add namedPlaceholders integration tests in cf604d7
  • docs(mysql2): document namedPlaceholders feature in 06de888

Full Changelog: v2.1.0...v2.1.1

Credits

Feature implemented to resolve issue #142 - Support for namedPlaceholders in mysql2 compatibility layer.

Installation

npm install data-api-client@2.1.1

Or update your package.json:

{
  "dependencies": {
    "data-api-client": "^2.1.1"
  }
}

🔗 Links


Note: This release maintains full compatibility with Aurora Serverless v1, Aurora Serverless v2, and Aurora provisioned clusters. The feature works seamlessly with ORMs like Drizzle and Kysely.