Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const CHARS_ESCAPE_MAP: Record<string, string> = {

const charCode = {
singleQuote: 39,
backtick: 96,
backslash: 92,
dash: 45,
slash: 47,
Expand Down Expand Up @@ -110,6 +111,23 @@ const skipSqlContext = (sql: string, position: number): number => {
return sql.length;
}

if (currentChar === charCode.backtick) {
const length = sql.length;

for (let cursor = position + 1; cursor < length; cursor++) {
if (sql.charCodeAt(cursor) !== charCode.backtick) continue;

if (sql.charCodeAt(cursor + 1) === charCode.backtick) {
cursor++;
continue;
}

return cursor + 1;
}

return length;
}

if (currentChar === charCode.dash && nextChar === charCode.dash) {
const lineBreak = sql.indexOf('\n', position + 2);
return lineBreak === -1 ? sql.length : lineBreak + 1;
Expand All @@ -132,6 +150,7 @@ const findNextPlaceholder = (sql: string, start: number): number => {

if (
code === charCode.singleQuote ||
code === charCode.backtick ||
code === charCode.dash ||
code === charCode.slash
) {
Expand All @@ -153,6 +172,7 @@ const findSetKeyword = (sql: string, startFrom = 0): number => {

if (
code === charCode.singleQuote ||
code === charCode.backtick ||
code === charCode.dash ||
code === charCode.slash
) {
Expand Down
72 changes: 72 additions & 0 deletions test/everyday-queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,75 @@ describe('Nice to have: Boolean in various contexts', () => {
assert.equal(sql, 'UPDATE t SET `active` = true, `archived` = false');
});
});

describe('Critical: Backtick-quoted identifiers with comment-like sequences', () => {
test('database/table names with double dashes', () => {
const sql = format(
'INSERT INTO `db--name`.`table`(`a`, `b`) VALUES (?, ?)',
[1, 'hello']
);
assert.equal(
sql,
"INSERT INTO `db--name`.`table`(`a`, `b`) VALUES (1, 'hello')"
);
});

test('column names with double dashes', () => {
const sql = format(
'INSERT INTO t (`col--1`, `col--2`) VALUES (?, ?)',
[1, 2]
);
assert.equal(sql, 'INSERT INTO t (`col--1`, `col--2`) VALUES (1, 2)');
});

test('backticks with block comment markers', () => {
const sql = format('INSERT INTO `table/*name*/` VALUES (?)', [1]);
assert.equal(sql, 'INSERT INTO `table/*name*/` VALUES (1)');
});

test('escaped backticks inside identifiers', () => {
const sql = format('INSERT INTO `table``name` VALUES (?)', [1]);
assert.equal(sql, 'INSERT INTO `table``name` VALUES (1)');
});

test('multiple backtick identifiers with mixed comment markers', () => {
const sql = format(
'SELECT * FROM `db--1`.`table/*test*/` WHERE `col--id` = ?',
[42]
);
assert.equal(
sql,
'SELECT * FROM `db--1`.`table/*test*/` WHERE `col--id` = 42'
);
});

test('UPDATE with backtick identifiers containing dashes', () => {
const sql = format('UPDATE `table--name` SET `col--1` = ? WHERE id = ?', [
'value',
1,
]);
assert.equal(
sql,
"UPDATE `table--name` SET `col--1` = 'value' WHERE id = 1"
);
});

test('SELECT with ?? and backtick-quoted values with dashes', () => {
const sql = format('SELECT ?? FROM `users--table` WHERE id = ?', [
['col--1', 'col--2'],
1,
]);
assert.equal(
sql,
'SELECT `col--1`, `col--2` FROM `users--table` WHERE id = 1'
);
});

test('SELECT with ?? without any backticks in query', () => {
const sql = format('SELECT ?? FROM users WHERE id = ?', [
['id', 'name'],
1,
]);
assert.equal(sql, 'SELECT `id`, `name` FROM users WHERE id = 1');
});
});
Loading