Skip to content

Commit 75d91cb

Browse files
authored
Merge pull request #23 from planetscale/named-parameters
Support named parameter replacement
2 parents 6ed66f1 + 820a47d commit 75d91cb

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ const results = await conn.execute('select 1 from dual where 1=?', [42])
8484
console.log(results)
8585
```
8686

87+
Named replacement parameters are supported with a colon prefix.
88+
89+
```ts
90+
const results = await conn.execute('select 1 from dual where 1=:id', { id: 42 })
91+
```
92+
8793
## Development
8894

8995
```

__tests__/sanitization.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,24 @@ import { format } from '../src/sanitization'
22

33
describe('sanitization', () => {
44
describe('format', () => {
5-
test('does nothing with empty values', () => {
5+
test('does no replacement for missing object key', () => {
6+
const query = 'select 1 from user where id=:id'
7+
expect(format(query, {})).toEqual(query)
8+
})
9+
10+
test('replaces named parameters', () => {
11+
const query = 'select 1 from user where state in (:state) and deleted_at=:deleted_at'
12+
const expected = "select 1 from user where state in ('active', 'inactive') and deleted_at=true"
13+
expect(format(query, { state: ['active', 'inactive'], deleted_at: true })).toEqual(expected)
14+
})
15+
16+
test('replaces duplicate named parameters', () => {
17+
const query = 'select 1 from user where id=:id or actor_id=:id'
18+
const expected = 'select 1 from user where id=42 or actor_id=42'
19+
expect(format(query, { id: 42 })).toEqual(expected)
20+
})
21+
22+
test('does nothing with empty values list', () => {
623
const query = 'select 1 from user where id=?'
724
expect(format(query, [])).toEqual(query)
825
})

src/sanitization.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
type Stringable = { toString: () => string }
22
type Value = null | undefined | number | boolean | string | Array<Value> | Date | Stringable
33

4-
export function format(query: string, values: Value[]): string {
4+
export function format(query: string, values: Value[] | Record<string, Value>): string {
5+
return Array.isArray(values) ? replacePosition(query, values) : replaceNamed(query, values)
6+
}
7+
8+
function replacePosition(query: string, values: Value[]): string {
59
let index = 0
610
return query.replace(/\?/g, (match) => {
711
return index < values.length ? sanitize(values[index++]) : match
812
})
913
}
1014

15+
function replaceNamed(query: string, values: Record<string, Value>): string {
16+
const names = new Set(Object.keys(values))
17+
return query.replace(/:(\w+)/g, (match, name) => {
18+
return names.has(name) ? sanitize(values[name]) : match
19+
})
20+
}
21+
1122
function sanitize(value: Value): string {
1223
if (value == null) {
1324
return 'null'

0 commit comments

Comments
 (0)