diff --git a/packages/backend/package.json b/packages/backend/package.json index 04402d6d..f8a811b1 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -33,6 +33,7 @@ "sql-formatter": "^15.0.2" }, "devDependencies": { + "@types/express": "^4.17.21", "@types/node": "^20.10.5", "@types/pg": "^8.10.9", "@vitest/coverage-v8": "^1.2.2", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 749b3026..affd6aad 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -1,4 +1,10 @@ export { collectLast } from './util/generators/collectLast'; +export { + type ExpressSynthqlHandler, + type ExpressSynthqlHandlerRequest, + type ExpressSynthqlHandlerResponse, + createExpressSynthqlHandler, +} from './util/handlers/createExpressSynthqlHandler'; export type * from './types/QueryPlan'; export * from './QueryEngine'; diff --git a/packages/backend/src/util/handlers/createExpressSynthqlHandler.test.ts b/packages/backend/src/util/handlers/createExpressSynthqlHandler.test.ts new file mode 100644 index 00000000..73fb50ed --- /dev/null +++ b/packages/backend/src/util/handlers/createExpressSynthqlHandler.test.ts @@ -0,0 +1,23 @@ +import { describe, test } from 'vitest'; +import { query } from '@synthql/queries'; + +import { DB } from '../../tests/db'; +const from = query().from; + +describe('createExpressSynthqlHandler', () => { + test(`Query execution is successful`, async () => { + const q = from('actor') + .columns('actor_id', 'first_name', 'last_name') + .groupingId('actor_id') + .where({ actor_id: { in: [1] } }) + .one(); + }); + + test(`Query execution is successful with returnLastOnly passed`, async () => { + const q = from('actor') + .columns('actor_id', 'first_name', 'last_name') + .groupingId('actor_id') + .where({ actor_id: { in: [1] } }) + .maybe(); + }); +}); diff --git a/packages/backend/src/util/handlers/createExpressSynthqlHandler.ts b/packages/backend/src/util/handlers/createExpressSynthqlHandler.ts new file mode 100644 index 00000000..18caa072 --- /dev/null +++ b/packages/backend/src/util/handlers/createExpressSynthqlHandler.ts @@ -0,0 +1,63 @@ +import { QueryEngine, collectLast } from '../..'; +import type { Request, Response } from 'express'; + +export type ExpressSynthqlHandlerRequest = Pick; + +export type ExpressSynthqlHandlerResponse = Pick< + Response, + 'statusCode' | 'write' | 'setHeader' | 'end' +>; + +export type ExpressSynthqlHandler = ( + req: ExpressSynthqlHandlerRequest, + res: ExpressSynthqlHandlerResponse, +) => void; + +export function createExpressSynthqlHandler( + queryEngine: QueryEngine, +): ExpressSynthqlHandler { + return async (req, res) => { + try { + const headers = req.headers; + const query = await JSON.parse(req.body); + const returnLastOnly = headers['x-return-last-only'] === 'true'; + + if (returnLastOnly) { + try { + const result = await collectLast( + queryEngine.execute(query, { + returnLastOnly, + }), + ); + + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.write(JSON.stringify(result)); + res.end(); + } catch (error) { + res.statusCode = 500; + res.setHeader('Content-Type', 'application/json'); + res.write(JSON.stringify({ error: String(error) })); + res.end(); + } + } else { + res.statusCode = 200; + res.setHeader('Content-Type', 'application/x-ndjson'); + + for await (const intermediateResult of queryEngine.execute( + query, + )) { + res.write(JSON.stringify(intermediateResult)); + res.write('\n'); + } + + res.end(); + } + } catch (error) { + res.statusCode = 400; + res.setHeader('Content-Type', 'application/json'); + res.write(JSON.stringify({ error: 'Invalid JSON body' })); + res.end(); + } + }; +} diff --git a/packages/docs/static/reference/assets/navigation.js b/packages/docs/static/reference/assets/navigation.js index 04087d20..cbe18164 100644 --- a/packages/docs/static/reference/assets/navigation.js +++ b/packages/docs/static/reference/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5XUTU8CMRAG4P/SM4qgoO6VeFETEU08EGJKd3AbhnZpu8SN4b8byuJ+lXa90rdPhs7Mzn+IgW9DIrKkbA0i7mvFSI+k1CQkIhsZZwi6Xxx+asUuE7NB0iNrLmISDXuEJRxjBYJE8z/sNQOVP4gvLqDEGFKtG1glWIcHw7t9z+VNlUx1iXJhQK0oO+/aC42qR+MmPkUquqmHpI9jEhGYeabalOAqE8xwKepeJVoXxzf7RZVE7u4LQ+7oSeXmNgPFQbtvF4eduzqhKuaCIjd5iZk8bVCVWIO9ur8djKrlTSRmG+HFbCLkPEouXlKfc0yEHNtgH2MDnZQZ6AxN0DrGQuIMVv6/ZwMh5Z0uEXyKDYSUjwSUV7GBTsoEaabD1jEWEplE175VNSaxtWclwHXjmd1IEfNA2/oUuRkbuhh4914BZca9u/ao8+a+5cIkW5xIYX9wfedKsB72feqKpB3kJ2gtTos8BUOt1GfK3VHFDyNapevZ5oNeD9vlTpXc8RiUq0Otkk9h79ycfQcX3Ip7aP0fuBF2zFYJZxqKKvxmmeuEtTrmN50jZndg8QvhsX/bmQgAAA==" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE52VXU/bMBSG/4uvC6zlY9DbCgnBpJUyiQuEJuOcLhaunfrYiGraf59wA3Fsxw7cxs95jmOfN3n4Swy8GjInT5Q9g6yOUDMyIQ01NZmTjaqsADxqF3+jZoe12QgyIc9cVmQ+mxBWc1FpkGT+8CG7taB3l/IPl9DJmKCIgcwD++Lp7PzfJOVbatVgJ+XSgF5TNux1BcGuT89C+VJQOc76RuZ0l6+NBsS7nTT1VlxRWQnQndrsmsCaLAg6fLv4Pj2dlbqsYGsBzaebtXVf7ImNkghfaLovLHVlSghg5gf1X2xtJTNcyX4fD+1bz058oQZqoHBNAw2GS6OGj35LwdPBYoInQuVVbi1oDpiubhdHx3JBdcUlFdzswuvyVR5WupyFEnYjszJHlDzXisufTc6zJ0oel9CcxgGjLCtAK6IsRa49VjKuYJ1/PQeULL/ok4iC5lscULLc16CzFgeMsiwEtXH0I9ceGxH0VP58G1MiE2yOwTGnJS2WEW37U5TWOOhgms29BspMOrtuaXRy22/NQkn3IPWj6oR9OPevakk3yDcQBSdSvoOlq8SB7b5Qzd9G1Ff32fBAj2fxdpdavfAq/bWOtvwOZ+dm8BxS4gjPqPEz4gBOzFYntgjtLvLOjhsli24s70yOmMvA438NQ9SXWgoAAA==" \ No newline at end of file diff --git a/packages/docs/static/reference/assets/search.js b/packages/docs/static/reference/assets/search.js index e4bc3525..ac37ffab 100644 --- a/packages/docs/static/reference/assets/search.js +++ b/packages/docs/static/reference/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/packages/react/src/test/appendBody.ts b/packages/react/src/test/appendBody.ts new file mode 100644 index 00000000..04a3cde5 --- /dev/null +++ b/packages/react/src/test/appendBody.ts @@ -0,0 +1,46 @@ +import { IncomingMessage, ServerResponse } from 'http'; +import { + ExpressSynthqlHandler, + ExpressSynthqlHandlerRequest, + ExpressSynthqlHandlerResponse, +} from '@synthql/backend'; + +function readBody(req: IncomingMessage): Promise { + return new Promise((resolve, reject) => { + let body = ''; + + req.on('data', (chunk) => { + body += chunk; + }); + + req.on('end', () => { + resolve(body); + }); + + req.on('error', (e) => { + reject(e); + }); + }); +} + +export type IncomingMessageWithBody = IncomingMessage & + ExpressSynthqlHandlerRequest; + +export type ServerResponseWithEnd = ServerResponse & + ExpressSynthqlHandlerResponse; + +export function appendBody(expressHandler: ExpressSynthqlHandler) { + return async (req: IncomingMessage, res: ServerResponse) => { + const body = await readBody(req); + + const newReq = { + ...req, + headers: req.headers, + body: body, + } as IncomingMessageWithBody; + + const newRes = res as ServerResponseWithEnd; + + expressHandler(newReq, newRes); + }; +} diff --git a/packages/react/src/test/createPagilaServer.ts b/packages/react/src/test/createPagilaServer.ts index 27cb7725..59b62bb6 100644 --- a/packages/react/src/test/createPagilaServer.ts +++ b/packages/react/src/test/createPagilaServer.ts @@ -1,7 +1,9 @@ -import { QueryEngine } from '@synthql/backend'; -import { DB } from './db'; +import { QueryEngine, createExpressSynthqlHandler } from '@synthql/backend'; import http from 'http'; +import { DB } from './db'; +import { appendBody } from './appendBody'; + export interface PagilaServer { url: string; server: http.Server; @@ -13,42 +15,15 @@ export function createPagilaServer({ queryEngine: QueryEngine; }): Promise { return new Promise((resolve, reject) => { - const server = http.createServer((req, res) => { - let body = ''; - - req.on('data', (chunk) => { - body += chunk; - }); - - req.on('end', async () => { - const headers = req.headers; + const handler = createExpressSynthqlHandler(queryEngine); - const json = JSON.parse(body); + const nodeHandler = appendBody(handler); - res.writeHead(200, { 'Content-Type': 'application/json' }); - - try { - for await (const intermediateResult of queryEngine.execute( - json, - { - returnLastOnly: - headers['x-return-last-only'] === 'true', - }, - )) { - res.write(JSON.stringify(intermediateResult) + '\n'); - } - - res.end(); - } catch (error) { - res.write(JSON.stringify({ error: String(error) }) + '\n'); - - res.end(); - } - }); - }); + const server = http.createServer(nodeHandler); server.listen(() => { const address = server.address(); + if (typeof address === 'string' || address === null) { reject('Failed to get server address: ' + address); } else { diff --git a/yarn.lock b/yarn.lock index 30a663e0..4515297e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2833,9 +2833,9 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@^4.17.13": +"@types/express@*", "@types/express@^4.17.13", "@types/express@^4.17.21": version "4.17.21" - resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== dependencies: "@types/body-parser" "*"