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: 5 additions & 0 deletions .changeset/hungry-donkeys-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@electric-sql/pglite': patch
---

Expose the fields node-postgres derives from the CommandComplete command tag on `Results`: `command` (e.g. `SELECT`, `INSERT`, `CREATE`), and `rowCount` (the per-statement count from the tag). The tag was already received and parsed internally to compute `affectedRows`, but these values were not surfaced. Matching node-postgres' `command`/`rowCount` result fields lets pg-compatible adapters report them without re-parsing SQL.
6 changes: 6 additions & 0 deletions docs/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,12 @@ Result objects have the following properties:
- `affectedRows?: number` <br />
Count of the rows affected by the query. Note, this is _not_ the count of rows returned, it is the number or rows in the database changed by the query.

- `command?: string` <br />
The command of the query that was run, taken from the command tag reported by Postgres, e.g. `SELECT`, `INSERT` or `CREATE`. Matches the `command` field of node-postgres query results.

- `rowCount?: number` <br />
The number of rows reported by the command tag, e.g. the rows returned by a `SELECT` or changed by an `UPDATE`. Not set when the tag carries no count (e.g. `CREATE TABLE`). Unlike `affectedRows` this is per statement and not cumulative; it matches the `rowCount` field of node-postgres query results.

- `fields: { name: string; dataTypeID: number }[]`<br />
Field name and Postgres data type ID for each field returned.

Expand Down
4 changes: 4 additions & 0 deletions packages/pglite-pgmq/tests/pgmq.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ describe(`pgmq`, () => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])

Expand All @@ -79,6 +81,8 @@ SELECT * from pgmq.send(
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])

Expand Down
2 changes: 2 additions & 0 deletions packages/pglite-pgvector/tests/pgvector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ describe(`pgvector`, () => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 3,
},
])
})
Expand Down
8 changes: 8 additions & 0 deletions packages/pglite-postgis/tests/postgis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ WHERE ST_Within(c.location, s.geom);`)
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])

Expand Down Expand Up @@ -133,6 +135,8 @@ WHERE ST_Within(c.location, s.geom);`)
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])

Expand Down Expand Up @@ -172,6 +176,8 @@ WHERE ST_Within(c.location, s.geom);`)
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])
})
Expand Down Expand Up @@ -208,6 +214,8 @@ WHERE ST_Within(c.location, s.geom);`)
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
},
])
})
Expand Down
10 changes: 10 additions & 0 deletions packages/pglite/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ export type Row<T = { [key: string]: any }> = T
export type Results<T = { [key: string]: any }> = {
rows: Row<T>[]
affectedRows?: number
/**
* The command of the query that was run, e.g. "SELECT", "INSERT", "CREATE".
*/
command?: string
/**
* The number of rows reported by the command tag, e.g. the rows returned
* by a SELECT or changed by an UPDATE. Unlike `affectedRows` this is per statement
* and not cumulative across a multi-statement query.
*/
rowCount?: number
fields: { name: string; dataTypeID: number }[]
blob?: Blob // Only set when a file is returned, such as from a COPY command
}
Expand Down
49 changes: 30 additions & 19 deletions packages/pglite/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,39 @@ export function parseResults(
}
case 'commandComplete': {
const msg = message as CommandCompleteMessage
affectedRows += retrieveRowCount(msg)

resultSets.push({
// A command tag that carries a row count ends in it ("SELECT 2",
// "UPDATE 3", "INSERT 0 5"); all other tags end in a word
// ("CREATE TABLE").
const parts = msg.text.split(' ')
const command = parts[0]
const rowCount = parseInt(parts[parts.length - 1], 10)

switch (command) {
case 'INSERT':
case 'UPDATE':
case 'DELETE':
case 'COPY':
case 'MERGE':
affectedRows += rowCount
break
}

const result = {
...currentResultSet,
command,
affectedRows,
...(blob ? { blob } : {}),
})
}

if (!Number.isNaN(rowCount)) {
result.rowCount = rowCount
}

if (blob) {
result.blob = blob
}

resultSets.push(result)

currentResultSet = { rows: [], fields: [] }
break
Expand All @@ -86,21 +112,6 @@ export function parseResults(
return resultSets
}

function retrieveRowCount(msg: CommandCompleteMessage): number {
const parts = msg.text.split(' ')
switch (parts[0]) {
case 'INSERT':
return parseInt(parts[2], 10)
case 'UPDATE':
case 'DELETE':
case 'COPY':
case 'MERGE':
return parseInt(parts[1], 10)
default:
return 0
}
}

/** Get the dataTypeIDs from a list of messages, if it's available. */
export function parseDescribeStatementResults(
messages: Array<BackendMessage>,
Expand Down
2 changes: 2 additions & 0 deletions packages/pglite/tests/array-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ describe('array types', () => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})

Expand Down
30 changes: 30 additions & 0 deletions packages/pglite/tests/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ await testEsmCjsAndDTC(async (importType) => {
expect(multiStatementResult).toEqual([
{
affectedRows: 1,
command: 'INSERT',
rowCount: 1,
rows: [],
fields: [],
},
{
affectedRows: 2,
command: 'UPDATE',
rowCount: 1,
rows: [],
fields: [],
},
Expand All @@ -64,6 +68,8 @@ await testEsmCjsAndDTC(async (importType) => {
{ name: 'name', dataTypeID: 25 },
],
affectedRows: 2,
command: 'SELECT',
rowCount: 1,
},
])
})
Expand Down Expand Up @@ -98,13 +104,17 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})

const updateResult = await db.query("UPDATE test SET name = 'test2';")
expect(updateResult).toEqual({
rows: [],
fields: [],
affectedRows: 1,
command: 'UPDATE',
rowCount: 1,
})
})

Expand Down Expand Up @@ -137,6 +147,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})

const updateResult =
Expand All @@ -145,6 +157,8 @@ await testEsmCjsAndDTC(async (importType) => {
rows: [],
fields: [],
affectedRows: 1,
command: 'UPDATE',
rowCount: 1,
})
})

Expand Down Expand Up @@ -343,6 +357,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})

Expand Down Expand Up @@ -376,6 +392,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})

Expand Down Expand Up @@ -428,6 +446,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})

Expand Down Expand Up @@ -472,6 +492,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 2,
})
await tx.rollback()
})
Expand All @@ -496,6 +518,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})
it('merge delete', async () => {
Expand Down Expand Up @@ -594,6 +618,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 2,
})
})

Expand Down Expand Up @@ -634,6 +660,8 @@ await testEsmCjsAndDTC(async (importType) => {
{ name: 'last_name', dataTypeID: 25 },
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})
it('timezone', async () => {
Expand Down Expand Up @@ -821,6 +849,8 @@ await testEsmCjsAndDTC(async (importType) => {
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
})
})
Expand Down
20 changes: 20 additions & 0 deletions packages/pglite/tests/targets/deno/basic.test.deno.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@ Deno.test({
assertEquals(multiStatementResult, [
{
affectedRows: 1,
command: 'INSERT',
rowCount: 1,
rows: [],
fields: [],
},
{
affectedRows: 2,
command: 'UPDATE',
rowCount: 1,
rows: [],
fields: [],
},
Expand All @@ -41,6 +45,8 @@ Deno.test({
{ name: 'name', dataTypeID: 25 },
],
affectedRows: 2,
command: 'SELECT',
rowCount: 1,
},
])
},
Expand Down Expand Up @@ -80,13 +86,17 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})

const updateResult = await db.query("UPDATE test SET name = 'test2';")
assertEquals(updateResult, {
rows: [],
fields: [],
affectedRows: 1,
command: 'UPDATE',
rowCount: 1,
})
},
})
Expand Down Expand Up @@ -232,6 +242,8 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})

// standardize timestamp comparison to UTC milliseconds to ensure predictable test runs on machines in different timezones.
Expand Down Expand Up @@ -276,6 +288,8 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
},
})
Expand Down Expand Up @@ -334,6 +348,8 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 2,
})
await tx.rollback()
})
Expand All @@ -358,6 +374,8 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 1,
})
},
})
Expand Down Expand Up @@ -416,6 +434,8 @@ Deno.test({
},
],
affectedRows: 0,
command: 'SELECT',
rowCount: 2,
})
},
})
Expand Down
Loading