From ef43a6e917683f293e4abf1551da0d776b4de969 Mon Sep 17 00:00:00 2001 From: AlexanderGeere Date: Fri, 2 Oct 2026 10:39:16 +0200 Subject: [PATCH 1/4] Pass the request to the dbs connection as options.req from the query module. The dbs module ignores options.req. A composing host which replaces a dbs connection can read the request context from it. Co-Authored-By: Claude Opus 5.5 --- apps/xyz/mod/query.js | 7 +++++-- apps/xyz/tests/mod/query.test.mjs | 26 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/apps/xyz/mod/query.js b/apps/xyz/mod/query.js index 7b890b06d..9a3cb54aa 100644 --- a/apps/xyz/mod/query.js +++ b/apps/xyz/mod/query.js @@ -34,6 +34,8 @@ A query string must returned from the getQueryFromTemplate() method. The query and SQL params to be substituted in the database process are send to the dbs_connection. +The request is passed as options.req so that a dbs_connection replaced by a composing host can read the request context. + The rows returned from the dbs_connection are then passed to the sendRows() method. @param {req} req HTTP request. @@ -134,7 +136,7 @@ export default async function query(req, res) { query, req.params.SQL, template.statement_timeout, - { nonblocking: true }, + { nonblocking: true, req }, ); if (connected instanceof Error) { @@ -149,11 +151,12 @@ export default async function query(req, res) { .send(`Non blocking request sent at ${new Date().toISOString()}.`); } - // Run the query + // The dbs module ignores options.req, which a connection replaced by the host may read. const rows = await dbs_connections[template.dbs]( query, req.params.SQL, template.statement_timeout, + { req }, ); sendRows(res, template, rows); diff --git a/apps/xyz/tests/mod/query.test.mjs b/apps/xyz/tests/mod/query.test.mjs index 16b440550..3c1c55e13 100644 --- a/apps/xyz/tests/mod/query.test.mjs +++ b/apps/xyz/tests/mod/query.test.mjs @@ -207,6 +207,30 @@ describe('Query: Testing Query API', () => { expect(mockLayerDb).toHaveBeenCalled(); expect(mockWorkspaceDb).not.toHaveBeenCalled(); }); + + it('passes the request to the dbs connection as options.req', async () => { + const { req, res } = createMocks({ + params: { + template: 'mock_template', + user: { roles: ['admin'], admin: true }, + }, + }); + + checkWorkspaceCache.mockResolvedValueOnce({ dbs: undefined }); + getTemplate.mockResolvedValueOnce({ + template: 'SELECT * FROM mock_table', + dbs: 'template_db', + }); + + await query(req, res); + + expect(mockTemplateDb).toHaveBeenCalledWith( + 'SELECT * FROM mock_table', + [], + undefined, + { req }, + ); + }); }); describe('Template resolution', () => { @@ -470,7 +494,7 @@ describe('Query: Testing Query API', () => { expect.any(String), expect.anything(), undefined, - { nonblocking: true }, + { nonblocking: true, req }, ); }); From b07b235b270614e7ec3feb9472df538411943b8c Mon Sep 17 00:00:00 2001 From: AlexanderGeere Date: Fri, 2 Oct 2026 11:21:35 +0200 Subject: [PATCH 2/4] Pass res.locals.dbs as options.context instead of the request. Only the values a host sets for its dbs connections are passed, not the whole request. Clients cannot write to res.locals. Co-Authored-By: Claude Opus 5.5 --- apps/xyz/mod/query.js | 8 +++---- apps/xyz/tests/mod/query.test.mjs | 35 ++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/apps/xyz/mod/query.js b/apps/xyz/mod/query.js index 9a3cb54aa..59fdc66a2 100644 --- a/apps/xyz/mod/query.js +++ b/apps/xyz/mod/query.js @@ -34,7 +34,7 @@ A query string must returned from the getQueryFromTemplate() method. The query and SQL params to be substituted in the database process are send to the dbs_connection. -The request is passed as options.req so that a dbs_connection replaced by a composing host can read the request context. +The res.locals.dbs object is passed as options.context, so that a composing host can hand values set by its middleware to a dbs_connection it replaced. Clients cannot write to res.locals. The rows returned from the dbs_connection are then passed to the sendRows() method. @@ -136,7 +136,7 @@ export default async function query(req, res) { query, req.params.SQL, template.statement_timeout, - { nonblocking: true, req }, + { context: res.locals?.dbs, nonblocking: true }, ); if (connected instanceof Error) { @@ -151,12 +151,12 @@ export default async function query(req, res) { .send(`Non blocking request sent at ${new Date().toISOString()}.`); } - // The dbs module ignores options.req, which a connection replaced by the host may read. + // The dbs module ignores options.context, which a connection replaced by the host may read. const rows = await dbs_connections[template.dbs]( query, req.params.SQL, template.statement_timeout, - { req }, + { context: res.locals?.dbs }, ); sendRows(res, template, rows); diff --git a/apps/xyz/tests/mod/query.test.mjs b/apps/xyz/tests/mod/query.test.mjs index 3c1c55e13..6d72fd69b 100644 --- a/apps/xyz/tests/mod/query.test.mjs +++ b/apps/xyz/tests/mod/query.test.mjs @@ -208,7 +208,7 @@ describe('Query: Testing Query API', () => { expect(mockWorkspaceDb).not.toHaveBeenCalled(); }); - it('passes the request to the dbs connection as options.req', async () => { + it('passes res.locals.dbs to the dbs connection as options.context', async () => { const { req, res } = createMocks({ params: { template: 'mock_template', @@ -216,6 +216,8 @@ describe('Query: Testing Query API', () => { }, }); + res.locals.dbs = { foo: 'bar' }; + checkWorkspaceCache.mockResolvedValueOnce({ dbs: undefined }); getTemplate.mockResolvedValueOnce({ template: 'SELECT * FROM mock_table', @@ -224,12 +226,27 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockTemplateDb).toHaveBeenCalledWith( - 'SELECT * FROM mock_table', - [], - undefined, - { req }, - ); + expect(mockTemplateDb.mock.calls[0][3].context).toBe(res.locals.dbs); + }); + + it('passes no context without res.locals.dbs', async () => { + const { req, res } = createMocks({ + params: { + template: 'mock_template', + user: { roles: ['admin'], admin: true }, + }, + }); + + checkWorkspaceCache.mockResolvedValueOnce({ dbs: undefined }); + getTemplate.mockResolvedValueOnce({ + template: 'SELECT * FROM mock_table', + dbs: 'template_db', + }); + + await query(req, res); + + expect(mockTemplateDb.mock.calls[0][3]).toEqual({ context: undefined }); + expect(Object.values(mockTemplateDb.mock.calls[0][3])).not.toContain(req); }); }); @@ -487,6 +504,8 @@ describe('Query: Testing Query API', () => { }, }); + res.locals.dbs = { foo: 'bar' }; + await query(req, res); expect(res.statusCode).toBe(202); @@ -494,7 +513,7 @@ describe('Query: Testing Query API', () => { expect.any(String), expect.anything(), undefined, - { nonblocking: true, req }, + { context: res.locals.dbs, nonblocking: true }, ); }); From 14771fef37351be7dd1d2adef2df80052c20eac6 Mon Sep 17 00:00:00 2001 From: AlexanderGeere Date: Fri, 2 Oct 2026 11:52:34 +0200 Subject: [PATCH 3/4] use locals instead of context --- apps/xyz/mod/query.js | 8 ++++---- apps/xyz/tests/mod/query.test.mjs | 15 ++++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/xyz/mod/query.js b/apps/xyz/mod/query.js index 59fdc66a2..157009206 100644 --- a/apps/xyz/mod/query.js +++ b/apps/xyz/mod/query.js @@ -34,7 +34,7 @@ A query string must returned from the getQueryFromTemplate() method. The query and SQL params to be substituted in the database process are send to the dbs_connection. -The res.locals.dbs object is passed as options.context, so that a composing host can hand values set by its middleware to a dbs_connection it replaced. Clients cannot write to res.locals. +The res.locals object is passed as options.locals, so that a composing host can hand values set by its middleware to a dbs_connection it replaced. Clients cannot write to res.locals. The rows returned from the dbs_connection are then passed to the sendRows() method. @@ -136,7 +136,7 @@ export default async function query(req, res) { query, req.params.SQL, template.statement_timeout, - { context: res.locals?.dbs, nonblocking: true }, + { locals: res.locals, nonblocking: true }, ); if (connected instanceof Error) { @@ -151,12 +151,12 @@ export default async function query(req, res) { .send(`Non blocking request sent at ${new Date().toISOString()}.`); } - // The dbs module ignores options.context, which a connection replaced by the host may read. + // The dbs module ignores options.locals, which a connection replaced by the host may read. const rows = await dbs_connections[template.dbs]( query, req.params.SQL, template.statement_timeout, - { context: res.locals?.dbs }, + { locals: res.locals }, ); sendRows(res, template, rows); diff --git a/apps/xyz/tests/mod/query.test.mjs b/apps/xyz/tests/mod/query.test.mjs index 6d72fd69b..0bba5f3ca 100644 --- a/apps/xyz/tests/mod/query.test.mjs +++ b/apps/xyz/tests/mod/query.test.mjs @@ -208,7 +208,7 @@ describe('Query: Testing Query API', () => { expect(mockWorkspaceDb).not.toHaveBeenCalled(); }); - it('passes res.locals.dbs to the dbs connection as options.context', async () => { + it('passes res.locals to the dbs connection as options.locals', async () => { const { req, res } = createMocks({ params: { template: 'mock_template', @@ -216,7 +216,7 @@ describe('Query: Testing Query API', () => { }, }); - res.locals.dbs = { foo: 'bar' }; + res.locals.foo = 'bar'; checkWorkspaceCache.mockResolvedValueOnce({ dbs: undefined }); getTemplate.mockResolvedValueOnce({ @@ -226,10 +226,11 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockTemplateDb.mock.calls[0][3].context).toBe(res.locals.dbs); + expect(mockTemplateDb.mock.calls[0][3]).toEqual({ locals: res.locals }); + expect(mockTemplateDb.mock.calls[0][3].locals).toBe(res.locals); }); - it('passes no context without res.locals.dbs', async () => { + it('does not pass the request to the dbs connection', async () => { const { req, res } = createMocks({ params: { template: 'mock_template', @@ -245,7 +246,7 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockTemplateDb.mock.calls[0][3]).toEqual({ context: undefined }); + expect(mockTemplateDb.mock.calls[0]).not.toContain(req); expect(Object.values(mockTemplateDb.mock.calls[0][3])).not.toContain(req); }); }); @@ -504,7 +505,7 @@ describe('Query: Testing Query API', () => { }, }); - res.locals.dbs = { foo: 'bar' }; + res.locals.foo = 'bar'; await query(req, res); @@ -513,7 +514,7 @@ describe('Query: Testing Query API', () => { expect.any(String), expect.anything(), undefined, - { context: res.locals.dbs, nonblocking: true }, + { locals: res.locals, nonblocking: true }, ); }); From 330cb3fee3b8910fffdbdb9245171240f49a6a9a Mon Sep 17 00:00:00 2001 From: Dennis Bauszus Date: Fri, 2 Oct 2026 11:37:39 +0100 Subject: [PATCH 4/4] consolidate params and options param into a params object. --- apps/xyz/mod/query.js | 26 ++++++------ apps/xyz/mod/utils/dbs.js | 20 +++++---- apps/xyz/mod/utils/logger.js | 12 +++--- apps/xyz/tests/mod/query.test.mjs | 31 ++++++++------ apps/xyz/tests/mod/utils/dbs.test.mjs | 54 +++++++++++++----------- apps/xyz/tests/mod/utils/logger.test.mjs | 9 ++-- 6 files changed, 82 insertions(+), 70 deletions(-) diff --git a/apps/xyz/mod/query.js b/apps/xyz/mod/query.js index 157009206..f16701c74 100644 --- a/apps/xyz/mod/query.js +++ b/apps/xyz/mod/query.js @@ -34,7 +34,7 @@ A query string must returned from the getQueryFromTemplate() method. The query and SQL params to be substituted in the database process are send to the dbs_connection. -The res.locals object is passed as options.locals, so that a composing host can hand values set by its middleware to a dbs_connection it replaced. Clients cannot write to res.locals. +The dbs_connection is called with a params object holding the query, variables, statement timeout, and nonblocking flag. The res.locals object is assigned as params.locals, so that a composing host can hand values set by its middleware to a dbs_connection it replaced. Clients cannot write to res.locals. The rows returned from the dbs_connection are then passed to the sendRows() method. @@ -130,14 +130,18 @@ export default async function query(req, res) { logger(query, 'query'); + // The dbs module ignores params.locals, which a connection replaced by the host may read. + const params = { + locals: res.locals, + nonblocking: template.nonblocking, + query, + timeout: template.statement_timeout, + variables: req.params.SQL, + }; + // Nonblocking queries will not wait for results but return once the query is sent. if (template.nonblocking) { - const connected = await dbs_connections[template.dbs]( - query, - req.params.SQL, - template.statement_timeout, - { locals: res.locals, nonblocking: true }, - ); + const connected = await dbs_connections[template.dbs](params); if (connected instanceof Error) { return res @@ -151,13 +155,7 @@ export default async function query(req, res) { .send(`Non blocking request sent at ${new Date().toISOString()}.`); } - // The dbs module ignores options.locals, which a connection replaced by the host may read. - const rows = await dbs_connections[template.dbs]( - query, - req.params.SQL, - template.statement_timeout, - { locals: res.locals }, - ); + const rows = await dbs_connections[template.dbs](params); sendRows(res, template, rows); } diff --git a/apps/xyz/mod/utils/dbs.js b/apps/xyz/mod/utils/dbs.js index e3f1deeec..f1daff8c1 100644 --- a/apps/xyz/mod/utils/dbs.js +++ b/apps/xyz/mod/utils/dbs.js @@ -70,18 +70,22 @@ Blocking queries are passed to the executeQuery method, which retries queries th Nonblocking queries are attempted once without retry. The returned promise resolves true once the query has been sent to the database, without waiting for the query to complete. The query is sent before the caller can respond, so the database will execute the query even if a serverless process is frozen after the response. The promise resolves with the error if the client fails to connect or the statement timeout cannot be set. Errors from the query after it has been sent are logged, since the query result is not awaited. +The params object may be extended with additional properties. These are ignored by the clientQuery method but can be read by a dbs connection method replaced by a composing host. + @this {Pool} The connection pool to use for the query. -@param {string} query SQL query to execute -@param {Array} [variables] Parameters for the SQL query -@param {number} [timeout] Statement timeout in milliseconds. Defaults to xyzEnv.STATEMENT_TIMEOUT. -@param {Object} [options] -@property {boolean} [options.nonblocking] Resolve once the query is sent without waiting for the query result. +@param {Object} params +@property {string} params.query SQL query to execute +@property {Array} [params.variables] Parameters for the SQL query +@property {number} [params.timeout] Statement timeout in milliseconds. Defaults to xyzEnv.STATEMENT_TIMEOUT. +@property {boolean} [params.nonblocking] Resolve once the query is sent without waiting for the query result. @returns {Promise} Query rows, true for a sent nonblocking query, or an error. */ -async function clientQuery(query, variables, timeout, options = {}) { - timeout ??= xyzEnv.STATEMENT_TIMEOUT; +async function clientQuery(params) { + const { query, variables } = params; + + const timeout = params.timeout ?? xyzEnv.STATEMENT_TIMEOUT; - if (!options.nonblocking) { + if (!params.nonblocking) { return executeQuery(this, query, variables, timeout); } diff --git a/apps/xyz/mod/utils/logger.js b/apps/xyz/mod/utils/logger.js index 3ea930e09..085e54213 100644 --- a/apps/xyz/mod/utils/logger.js +++ b/apps/xyz/mod/utils/logger.js @@ -171,19 +171,19 @@ function postgresql() { // Nonblocking log inserts are not retried. // A retried insert would log dbs_retry, which would insert another log into the failing dbs. - dbs[params.dbs]( - `INSERT INTO ${table} + dbs[params.dbs]({ + nonblocking: true, + query: `INSERT INTO ${table} (process, datetime, key, log, message) VALUES ($1, $2, $3, $4, $5)`, - [ + timeout: 3000, + variables: [ process_id, Number.parseInt(Date.now() / 1000), key, logstring, errorMessage, ], - 3000, - { nonblocking: true }, - ); + }); }; } diff --git a/apps/xyz/tests/mod/query.test.mjs b/apps/xyz/tests/mod/query.test.mjs index 0bba5f3ca..7fc3d2329 100644 --- a/apps/xyz/tests/mod/query.test.mjs +++ b/apps/xyz/tests/mod/query.test.mjs @@ -208,7 +208,7 @@ describe('Query: Testing Query API', () => { expect(mockWorkspaceDb).not.toHaveBeenCalled(); }); - it('passes res.locals to the dbs connection as options.locals', async () => { + it('passes res.locals to the dbs connection as params.locals', async () => { const { req, res } = createMocks({ params: { template: 'mock_template', @@ -226,8 +226,8 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockTemplateDb.mock.calls[0][3]).toEqual({ locals: res.locals }); - expect(mockTemplateDb.mock.calls[0][3].locals).toBe(res.locals); + expect(mockTemplateDb.mock.calls[0]).toHaveLength(1); + expect(mockTemplateDb.mock.calls[0][0].locals).toBe(res.locals); }); it('does not pass the request to the dbs connection', async () => { @@ -246,8 +246,8 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockTemplateDb.mock.calls[0]).not.toContain(req); - expect(Object.values(mockTemplateDb.mock.calls[0][3])).not.toContain(req); + expect(mockTemplateDb.mock.calls[0]).toHaveLength(1); + expect(Object.values(mockTemplateDb.mock.calls[0][0])).not.toContain(req); }); }); @@ -425,7 +425,8 @@ describe('Query: Testing Query API', () => { await query(req, res); expect(mockDbQuery).toHaveBeenCalled(); - const [queryStr, sqlParams] = mockDbQuery.mock.calls[0]; + const { query: queryStr, variables: sqlParams } = + mockDbQuery.mock.calls[0][0]; // ${field} and ${table} are replaced inline. expect(queryStr).toContain('SELECT age FROM users'); @@ -475,7 +476,7 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockDbQuery.mock.calls[0][2]).toBe(9000); + expect(mockDbQuery.mock.calls[0][0].timeout).toBe(9000); }); it('should ignore the statement_timeout request param', async () => { @@ -490,7 +491,7 @@ describe('Query: Testing Query API', () => { await query(req, res); - expect(mockDbQuery.mock.calls[0][2]).toBeUndefined(); + expect(mockDbQuery.mock.calls[0][0].timeout).toBeUndefined(); }); }); @@ -511,10 +512,12 @@ describe('Query: Testing Query API', () => { expect(res.statusCode).toBe(202); expect(mockDbQuery).toHaveBeenCalledWith( - expect.any(String), - expect.anything(), - undefined, - { locals: res.locals, nonblocking: true }, + expect.objectContaining({ + locals: res.locals, + nonblocking: true, + query: expect.any(String), + variables: expect.any(Array), + }), ); }); @@ -552,7 +555,7 @@ describe('Query: Testing Query API', () => { await query(req, res); expect(mockDbQuery).toHaveBeenCalled(); - const [queryStr] = mockDbQuery.mock.calls[0]; + const { query: queryStr } = mockDbQuery.mock.calls[0][0]; expect(queryStr).toContain('SELECT distinct(name)'); expect(queryStr).toContain('FROM users'); expect(queryStr).toContain('ORDER BY name'); @@ -572,7 +575,7 @@ describe('Query: Testing Query API', () => { await query(req, res); expect(mockDbQuery).toHaveBeenCalled(); - const [queryStr] = mockDbQuery.mock.calls[0]; + const { query: queryStr } = mockDbQuery.mock.calls[0][0]; expect(queryStr).toContain('max(price)'); expect(queryStr).toContain('FROM products'); }); diff --git a/apps/xyz/tests/mod/utils/dbs.test.mjs b/apps/xyz/tests/mod/utils/dbs.test.mjs index 6c3f4060f..7250086ee 100644 --- a/apps/xyz/tests/mod/utils/dbs.test.mjs +++ b/apps/xyz/tests/mod/utils/dbs.test.mjs @@ -80,7 +80,7 @@ describe('dbs Module', () => { const client = mockClient([{ id: 1 }]); pools[0].connect.mockResolvedValueOnce(client); - const rows = await dbs.TEST('SELECT 1', [1]); + const rows = await dbs.TEST({ query: 'SELECT 1', variables: [1] }); expect(rows).toEqual([{ id: 1 }]); expect(client.query).toHaveBeenCalledWith('SELECT 1', [1]); @@ -95,8 +95,8 @@ describe('dbs Module', () => { .mockResolvedValueOnce(defaultClient) .mockResolvedValueOnce(argClient); - await dbs.TEST('SELECT 1'); - await dbs.TEST('SELECT 1', [], 3000); + await dbs.TEST({ query: 'SELECT 1' }); + await dbs.TEST({ query: 'SELECT 1', timeout: 3000 }); expect(defaultClient.query).toHaveBeenCalledWith( 'SET statement_timeout = 1000', @@ -111,7 +111,7 @@ describe('dbs Module', () => { const client = mockClient([]); pools[0].connect.mockResolvedValueOnce(client); - await dbs.TEST('SELECT 1'); + await dbs.TEST({ query: 'SELECT 1' }); expect(client.query).toHaveBeenCalledTimes(1); }); @@ -122,7 +122,7 @@ describe('dbs Module', () => { const client = mockClient(error); pools[0].connect.mockResolvedValueOnce(client); - const result = await dbs.TEST('SELECT * FROM missing'); + const result = await dbs.TEST({ query: 'SELECT * FROM missing' }); expect(result).toBe(error); expect(pools[0].connect).toHaveBeenCalledTimes(1); @@ -134,7 +134,7 @@ describe('dbs Module', () => { const error = new Error('timeout exceeded when trying to connect'); pools[0].connect.mockRejectedValueOnce(error); - const result = await dbs.TEST('SELECT 1'); + const result = await dbs.TEST({ query: 'SELECT 1' }); expect(result).toBe(error); }); @@ -151,7 +151,7 @@ describe('dbs Module', () => { pools[0].connect.mockResolvedValueOnce(client), ); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.advanceTimersByTimeAsync(0); expect(pools[0].connect).toHaveBeenCalledTimes(1); @@ -182,7 +182,7 @@ describe('dbs Module', () => { .mockResolvedValueOnce(mockClient(pgError('53300'))) .mockResolvedValueOnce(mockClient(lastError)); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.runAllTimersAsync(); await expect(promise).resolves.toBe(lastError); @@ -198,7 +198,7 @@ describe('dbs Module', () => { .mockResolvedValueOnce(client) .mockRejectedValueOnce(connectError); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.runAllTimersAsync(); await expect(promise).resolves.toBe(connectError); @@ -210,7 +210,7 @@ describe('dbs Module', () => { const error = pgError('53300'); pools[0].connect.mockResolvedValueOnce(mockClient(error)); - await expect(dbs.TEST('SELECT 1')).resolves.toBe(error); + await expect(dbs.TEST({ query: 'SELECT 1' })).resolves.toBe(error); expect(pools[0].connect).toHaveBeenCalledTimes(1); }); }); @@ -236,7 +236,7 @@ describe('dbs Module', () => { ) .mockResolvedValueOnce(mockClient([{ id: 1 }])); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.runAllTimersAsync(); await promise; @@ -274,7 +274,7 @@ describe('dbs Module', () => { .mockResolvedValueOnce(mockClient(pgError('53300'))) .mockResolvedValueOnce(mockClient([{ id: 1 }])); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.advanceTimersByTimeAsync(0); expect(logger).toHaveBeenCalledTimes(1); @@ -295,7 +295,7 @@ describe('dbs Module', () => { mockClient(pgError('57P03', 'cannot connect now')), ); - const promise = dbs.TEST('SELECT 1'); + const promise = dbs.TEST({ query: 'SELECT 1' }); await vi.runAllTimersAsync(); await promise; @@ -317,7 +317,7 @@ describe('dbs Module', () => { const logger = await importLogger(); pools[0].connect.mockResolvedValueOnce(mockClient(pgError('42P01'))); - await dbs.TEST('SELECT 1'); + await dbs.TEST({ query: 'SELECT 1' }); expect(logger).not.toHaveBeenCalled(); }); @@ -328,7 +328,7 @@ describe('dbs Module', () => { const client = mockClient(pgError('53300')); pools[0].connect.mockResolvedValueOnce(client); - await dbs.TEST('SELECT 1', [], undefined, { nonblocking: true }); + await dbs.TEST({ nonblocking: true, query: 'SELECT 1' }); await vi.waitFor(() => expect(client.release).toHaveBeenCalled()); expect(logger).not.toHaveBeenCalled(); @@ -350,8 +350,11 @@ describe('dbs Module', () => { }; pools[0].connect.mockResolvedValueOnce(client); - const result = await dbs.TEST('INSERT INTO log', [], 3000, { + const result = await dbs.TEST({ nonblocking: true, + query: 'INSERT INTO log', + timeout: 3000, + variables: [], }); expect(result).toBe(true); @@ -385,7 +388,12 @@ describe('dbs Module', () => { const onResolved = vi.fn(); const promise = dbs - .TEST('INSERT INTO log', [], 3000, { nonblocking: true }) + .TEST({ + nonblocking: true, + query: 'INSERT INTO log', + timeout: 3000, + variables: [], + }) .then(onResolved); await vi.waitFor(() => expect(client.query).toHaveBeenCalledTimes(1)); @@ -407,8 +415,10 @@ describe('dbs Module', () => { }; pools[0].connect.mockResolvedValueOnce(client); - const result = await dbs.TEST('INSERT INTO log', [], 3000, { + const result = await dbs.TEST({ nonblocking: true, + query: 'INSERT INTO log', + timeout: 3000, }); expect(result).toBe(error); @@ -422,9 +432,7 @@ describe('dbs Module', () => { const error = pgError('53300'); pools[0].connect.mockRejectedValueOnce(error); - const result = await dbs.TEST('SELECT 1', [], undefined, { - nonblocking: true, - }); + const result = await dbs.TEST({ nonblocking: true, query: 'SELECT 1' }); expect(result).toBe(error); expect(pools[0].connect).toHaveBeenCalledTimes(1); @@ -437,9 +445,7 @@ describe('dbs Module', () => { const client = mockClient(error); pools[0].connect.mockResolvedValueOnce(client); - const result = await dbs.TEST('SELECT 1', [], undefined, { - nonblocking: true, - }); + const result = await dbs.TEST({ nonblocking: true, query: 'SELECT 1' }); expect(result).toBe(true); await vi.waitFor(() => expect(console.error).toHaveBeenCalledWith(error)); diff --git a/apps/xyz/tests/mod/utils/logger.test.mjs b/apps/xyz/tests/mod/utils/logger.test.mjs index 419aa851f..6b6e7725d 100644 --- a/apps/xyz/tests/mod/utils/logger.test.mjs +++ b/apps/xyz/tests/mod/utils/logger.test.mjs @@ -80,11 +80,12 @@ describe('logger Module', () => { await vi.waitFor(() => expect(dbsQuery).toHaveBeenCalled()); - const [sql, values, timeout, options] = dbsQuery.mock.calls[0]; - expect(sql).toContain('INSERT INTO public.logs'); - expect(values[2]).toBe('dbs_retry'); + const { nonblocking, query, timeout, variables } = + dbsQuery.mock.calls[0][0]; + expect(query).toContain('INSERT INTO public.logs'); + expect(variables[2]).toBe('dbs_retry'); expect(timeout).toBe(3000); - expect(options).toEqual({ nonblocking: true }); + expect(nonblocking).toBe(true); vi.doUnmock('../../../mod/utils/dbs.js'); });