Skip to content
Open
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
5 changes: 4 additions & 1 deletion src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ const builders = Object.entries({
return '(' + escapeIdentifiers(columns, options) + ')values' +
valuesBuilder(Array.isArray(first) ? first : [first], parameters, types, columns, options)
}
}).map(([x, fn]) => ([new RegExp('((?:^|[\\s(])' + x + '(?:$|[\\s(]))(?![\\s\\S]*\\1)', 'i'), fn]))
}).map(([x, fn]) => {
const keyword = '(?:^|[\\s(])' + x + '(?:$|[\\s(])'
return [new RegExp(keyword + '(?![\\s\\S]*' + keyword + ')', 'i'), fn]
})

function notTagged() {
throw Errors.generic('NOT_TAGGED_CALL', 'Query not called as a tagged template literal')
Expand Down
99 changes: 99 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,105 @@ t('Last keyword used even with duplicate keywords', async() => {
return [x, true, await sql`drop table test`]
})

t('Last keyword used even when an earlier keyword is followed by (', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in(select x from test where x in ${ sql([1, 2]) })`

return [1, x, await sql`drop table test`]
})

t('Last keyword used even when it ends the string', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in (select x from test where x in${ sql([1, 2]) })`

return [1, x, await sql`drop table test`]
})

t('Last keyword used when nested keywords are all spaced', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in (select x from test where x in ${ sql([1, 2]) })`

return [1, x, await sql`drop table test`]
})

t('Single keyword followed by ( is still used', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where (x,x) in(${ sql([[1, 1]]) })`

return [1, x, await sql`drop table test`]
})

t('Last keyword used for keywords other than in', async() => {
await sql`create table test (x int)`
const [{ x }] = await sql`with a as (insert into test values(2) returning(x)) insert into test values(3) returning ${ sql(['x']) }`

return [3, x, await sql`drop table test`]
})

t('Last keyword used when the spaced keyword comes first', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in (select x from test where x in(select x from test where x in ${ sql([1, 2]) }))`

return [1, x, await sql`drop table test`]
})

t('Last keyword used with three occurrences and three delimiters', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in(select x from test where x in (select x from test where x in${ sql([1, 2]) }))`

return [1, x, await sql`drop table test`]
})

t('Last keyword used case insensitively', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`SELECT x FROM test WHERE x IN(SELECT x FROM test WHERE x IN ${ sql([1, 2]) })`

return [1, x, await sql`drop table test`]
})

t('Last keyword used when the earlier keyword is in a nested fragment', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x ${ sql`in(select x from test where x in ${ sql([1, 2]) })` }`

return [1, x, await sql`drop table test`]
})

t('Last keyword used when an earlier keyword is newline delimited', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x
in(select x from test where x in ${ sql([1, 2]) })`

return [1, x, await sql`drop table test`]
})

// Control: identical `(` delimiters were never affected by the backreference,
// so this passes with and without the fix. It pins that the repeated-pattern
// lookahead does not regress the same-delimiter case.
t('Repeated keyword with identical ( delimiters is unchanged (control)', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const [{ x }] = await sql`select x from test where x in(select x from test where (x,x) in(${ sql([[1, 1]]) }))`

return [1, x, await sql`drop table test`]
})

t('Last keyword used with an empty array', async() => {
await sql`create table test (x int)`
await sql`insert into test values(1)`
const rows = await sql`select x from test where x in(select x from test where x in ${ sql([]) })`

return [0, rows.length, await sql`drop table test`]
})

t('Insert array with null', async() => {
await sql`create table test (x int[])`
await sql`insert into test ${ sql({ x: [1, null, 3] }) }`
Expand Down