diff --git a/package.json b/package.json index df755ee3..1e76e648 100644 --- a/package.json +++ b/package.json @@ -21,17 +21,16 @@ "dependencies": { "@aws-sdk/client-dynamodb": "^3.823.0", "@aws-sdk/client-s3": "^3.823.0", - "@aws-sdk/client-secrets-manager": "^3.823.0", "@aws-sdk/client-sqs": "^3.823.0", "@aws-sdk/lib-dynamodb": "^3.823.0", "@aws-sdk/s3-request-presigner": "^3.859.0", + "@gcforms/connectors": "^2.2.17", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.21.0", "express-validator": "^7.2.0", "got": "^14.4.7", "jose": "^5.9.3", - "pg-promise": "^11.9.1", "pino": "^9.4.0", "rate-limiter-flexible": "^5.0.4", "redis": "^4.7.0" @@ -45,6 +44,7 @@ "@types/supertest": "^6.0.2", "aws-sdk-client-mock": "^4.0.2", "pino-pretty": "^11.2.2", + "postgres": "^3.4.8", "supertest": "^7.0.0", "tsc-alias": "^1.8.15", "tsx": "^4.19.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bcd2f0d4..da1ede67 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,6 @@ importers: '@aws-sdk/client-s3': specifier: ^3.823.0 version: 3.995.0 - '@aws-sdk/client-secrets-manager': - specifier: ^3.823.0 - version: 3.995.0 '@aws-sdk/client-sqs': specifier: ^3.823.0 version: 3.995.0 @@ -26,6 +23,9 @@ importers: '@aws-sdk/s3-request-presigner': specifier: ^3.859.0 version: 3.995.0 + '@gcforms/connectors': + specifier: ^2.2.17 + version: 2.2.17 cors: specifier: ^2.8.5 version: 2.8.6 @@ -44,9 +44,6 @@ importers: jose: specifier: ^5.9.3 version: 5.10.0 - pg-promise: - specifier: ^11.9.1 - version: 11.15.0(pg-query-stream@4.10.3(pg@8.16.3)) pino: specifier: ^9.4.0 version: 9.14.0 @@ -81,6 +78,9 @@ importers: pino-pretty: specifier: ^11.2.2 version: 11.3.0 + postgres: + specifier: ^3.4.8 + version: 3.4.8 supertest: specifier: ^7.0.0 version: 7.2.2 @@ -671,6 +671,9 @@ packages: cpu: [x64] os: [win32] + '@gcforms/connectors@2.2.17': + resolution: {integrity: sha512-cIa3gqLltMpiX9GXIorrp0+TRq6/GG2RYd65dRHpOr+UUSpt9uj3CRjmH8CG6Iceu4upiLKS1K5jb2+E0N5Xiw==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -1218,10 +1221,6 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - assert-options@0.8.3: - resolution: {integrity: sha512-s6v4HnA+vYSGO4eZX+F+I3gvF74wPk+m6Z1Q3w1Dsg4Pnv/R24vhKAasoMVZGvDpOOfTg1Qz4ptZnEbuy95XsQ==} - engines: {node: '>=14.0.0'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1236,6 +1235,9 @@ packages: aws-sdk-client-mock@4.1.0: resolution: {integrity: sha512-h/tOYTkXEsAcV3//6C1/7U4ifSpKyJvb6auveAepqqNJl6TdZaPFEtKjBQNf8UxQdDP850knB2i/whq4zlsxJw==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -1494,6 +1496,15 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + form-data-encoder@4.1.0: resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} engines: {node: '>= 18'} @@ -1782,60 +1793,6 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} - pg-cloudflare@1.3.0: - resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} - - pg-connection-string@2.11.0: - resolution: {integrity: sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==} - - pg-cursor@2.17.0: - resolution: {integrity: sha512-2Uio3Xfl5ldwJfls+RgGL+YbPcKQncWACWjYQFqlamvHZ4HJFjZhhZBbqd7jQ2LIkZYSvU90bm2dNW0rno+QFQ==} - peerDependencies: - pg: ^8 - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-minify@1.8.0: - resolution: {integrity: sha512-jO/oJOununpx8DzKgvSsWm61P8JjwXlaxSlbbfTBo1nvSWoo/+I6qZYaSN96jm/KDwa5d+JMQwPGgcP6HXDRow==} - engines: {node: '>=16.0.0'} - - pg-pool@3.11.0: - resolution: {integrity: sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==} - peerDependencies: - pg: '>=8.0' - - pg-promise@11.15.0: - resolution: {integrity: sha512-EUXpXn90yPVPKxQH4qqUAEVcApd2tp/JdR3wG6LzBUgaXTUYqwmuXG4vFhhZTCctzhfzRA20EbORb9H4aAgUHA==} - engines: {node: '>=16.0'} - peerDependencies: - pg-query-stream: 4.10.3 - - pg-protocol@1.11.0: - resolution: {integrity: sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g==} - - pg-query-stream@4.10.3: - resolution: {integrity: sha512-h2utrzpOIzeT9JfaqfvBbVuvCfBjH86jNfVrGGTbyepKAIOyTfDew0lAt8bbJjs9n/I5bGDl7S2sx6h5hPyJxw==} - peerDependencies: - pg: ^8 - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - pg@8.16.3: - resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} - engines: {node: '>= 16.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true - - pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1865,21 +1822,9 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.1: - resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} + postgres@3.4.8: + resolution: {integrity: sha512-d+JFcLM17njZaOLkv6SCev7uoLaBtfK86vMUXhW1Z4glPWh4jozno9APvW/XKFJ3CCxVoC7OL38BqRydtu5nGg==} + engines: {node: '>=12'} process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} @@ -1892,6 +1837,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -2022,10 +1970,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - spex@3.4.1: - resolution: {integrity: sha512-Br0Mu3S+c70kr4keXF+6K4B8ohR+aJjI9s7SbdsI3hliE1Riz4z+FQk7FQL+r7X1t90KPkpuKwQyITpCIQN9mg==} - engines: {node: '>=14.0.0'} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -2234,10 +2178,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -3120,6 +3060,18 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true + '@gcforms/connectors@2.2.17': + dependencies: + '@aws-sdk/client-dynamodb': 3.995.0 + '@aws-sdk/client-secrets-manager': 3.995.0 + '@aws-sdk/client-sqs': 3.995.0 + '@aws-sdk/lib-dynamodb': 3.995.0(@aws-sdk/client-dynamodb@3.995.0) + axios: 1.13.5 + postgres: 3.4.8 + transitivePeerDependencies: + - aws-crt + - debug + '@jridgewell/sourcemap-codec@1.5.5': {} '@keyv/serialize@1.1.1': {} @@ -3746,8 +3698,6 @@ snapshots: asap@2.0.6: {} - assert-options@0.8.3: {} - assertion-error@2.0.1: {} asynckit@0.4.0: {} @@ -3760,6 +3710,14 @@ snapshots: sinon: 18.0.1 tslib: 2.8.1 + axios@1.13.5: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + base64-js@1.5.1: {} binary-extensions@2.3.0: {} @@ -4085,6 +4043,8 @@ snapshots: transitivePeerDependencies: - supports-color + follow-redirects@1.15.11: {} + form-data-encoder@4.1.0: {} form-data@4.0.5: @@ -4331,62 +4291,6 @@ snapshots: pathval@2.0.1: {} - pg-cloudflare@1.3.0: - optional: true - - pg-connection-string@2.11.0: {} - - pg-cursor@2.17.0(pg@8.16.3): - dependencies: - pg: 8.16.3 - - pg-int8@1.0.1: {} - - pg-minify@1.8.0: {} - - pg-pool@3.11.0(pg@8.16.3): - dependencies: - pg: 8.16.3 - - pg-promise@11.15.0(pg-query-stream@4.10.3(pg@8.16.3)): - dependencies: - assert-options: 0.8.3 - pg: 8.16.3 - pg-minify: 1.8.0 - pg-query-stream: 4.10.3(pg@8.16.3) - spex: 3.4.1 - transitivePeerDependencies: - - pg-native - - pg-protocol@1.11.0: {} - - pg-query-stream@4.10.3(pg@8.16.3): - dependencies: - pg: 8.16.3 - pg-cursor: 2.17.0(pg@8.16.3) - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.1 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - pg@8.16.3: - dependencies: - pg-connection-string: 2.11.0 - pg-pool: 3.11.0(pg@8.16.3) - pg-protocol: 1.11.0 - pg-types: 2.2.0 - pgpass: 1.0.5 - optionalDependencies: - pg-cloudflare: 1.3.0 - - pgpass@1.0.5: - dependencies: - split2: 4.2.0 - picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -4438,15 +4342,7 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: {} - - postgres-bytea@1.0.1: {} - - postgres-date@1.0.7: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 + postgres@3.4.8: {} process-warning@5.0.0: {} @@ -4457,6 +4353,8 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} + pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -4641,8 +4539,6 @@ snapshots: source-map-js@1.2.1: {} - spex@3.4.1: {} - split2@4.2.0: {} stackback@0.0.2: {} @@ -4835,6 +4731,4 @@ snapshots: wrappy@1.0.2: {} - xtend@4.0.2: {} - yallist@4.0.0: {} diff --git a/src/lib/formsClient/getFormTemplate.ts b/src/lib/formsClient/getFormTemplate.ts index 5235d51e..76041a02 100644 --- a/src/lib/formsClient/getFormTemplate.ts +++ b/src/lib/formsClient/getFormTemplate.ts @@ -1,35 +1,26 @@ -import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js"; +import { databaseConnector } from "@lib/integration/databaseConnector.js"; import type { FormTemplate } from "@lib/formsClient/types/formTemplate.js"; import { logMessage } from "@lib/logging/logger.js"; -export function getFormTemplate( +export async function getFormTemplate( formId: string, ): Promise { - return DatabaseConnectorClient.oneOrNone>( - 'SELECT "jsonConfig" FROM "Template" WHERE id = $1', - [formId], - ) - .then((result) => { - if (result === null) { - return undefined; - } + try { + const results = await databaseConnector.executeSqlStatement()< + FormTemplate[] + >`SELECT "jsonConfig" FROM "Template" WHERE id = ${formId}`; - return formTemplateFromPostgreSqlResult(result); - }) - .catch((error) => { - logMessage.error( - error, - `[formsClient] Failed to retrieve form template. FormId: ${formId}`, - ); + if (results.length !== 1) { + return undefined; + } - throw error; - }); -} + return results[0]; + } catch (error) { + logMessage.error( + error, + `[formsClient] Failed to retrieve form template. FormId: ${formId}`, + ); -function formTemplateFromPostgreSqlResult( - response: Record, -): FormTemplate { - return { - jsonConfig: response.jsonConfig as Record, - }; + throw error; + } } diff --git a/src/lib/formsClient/getPublicKey.ts b/src/lib/formsClient/getPublicKey.ts index 5ca896bf..2283f913 100644 --- a/src/lib/formsClient/getPublicKey.ts +++ b/src/lib/formsClient/getPublicKey.ts @@ -1,4 +1,4 @@ -import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js"; +import { databaseConnector } from "@lib/integration/databaseConnector.js"; import { getValueFromRedis, setValueInRedis, @@ -37,19 +37,18 @@ export async function getPublicKey(serviceAccountId: string): Promise { } } -function retrievePublicKeyFromDatabase( +async function retrievePublicKeyFromDatabase( serviceAccountId: string, ): Promise { - return DatabaseConnectorClient.oneOrNone>( - 'SELECT "publicKey" FROM "ApiServiceAccount" WHERE id = $1', - [serviceAccountId], - ).then((result) => { - if (result === null) { - return undefined; - } + const results = await databaseConnector.executeSqlStatement()< + { publicKey: string }[] + >`SELECT "publicKey" FROM "ApiServiceAccount" WHERE id = ${serviceAccountId}`; + + if (results.length !== 1) { + return undefined; + } - return result.publicKey as string; - }); + return results[0].publicKey; } function getPublicKeyFromCache( diff --git a/src/lib/integration/awsServicesConnector.ts b/src/lib/integration/awsServicesConnector.ts index 56b5464e..024e3ceb 100644 --- a/src/lib/integration/awsServicesConnector.ts +++ b/src/lib/integration/awsServicesConnector.ts @@ -1,7 +1,6 @@ import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; import { SQSClient } from "@aws-sdk/client-sqs"; -import { SecretsManagerClient } from "@aws-sdk/client-secrets-manager"; import { AWS_REGION } from "@config"; import { S3Client } from "@aws-sdk/client-s3"; @@ -14,8 +13,6 @@ export class AwsServicesConnector { public dynamodbClient: DynamoDBDocumentClient; - public secretsClient: SecretsManagerClient; - public sqsClient: SQSClient; public s3Client: S3Client; @@ -27,10 +24,6 @@ export class AwsServicesConnector { }), ); - this.secretsClient = new SecretsManagerClient({ - ...globalConfig, - }); - this.sqsClient = new SQSClient({ ...globalConfig, }); diff --git a/src/lib/integration/databaseConnector.ts b/src/lib/integration/databaseConnector.ts index a89c4f11..f9e9bb96 100644 --- a/src/lib/integration/databaseConnector.ts +++ b/src/lib/integration/databaseConnector.ts @@ -1,49 +1,13 @@ -import pgp, { type IDatabase } from "pg-promise"; -import type { IClient } from "pg-promise/typescript/pg-subset.js"; -import { GetSecretValueCommand } from "@aws-sdk/client-secrets-manager"; -import { AwsServicesConnector } from "@lib/integration/awsServicesConnector.js"; +import { PostgresConnector } from "@gcforms/connectors"; import { logMessage } from "@lib/logging/logger.js"; -const getConnectionString = async (): Promise => { - try { - const response = - await AwsServicesConnector.getInstance().secretsClient.send( - new GetSecretValueCommand({ - SecretId: "server-database-url", - }), - ); +const createDatabaseConnector = (): Promise => { + logMessage.info("[database-connector] Creating database connector"); - if (response.SecretString === undefined) { - throw new Error( - "[database-connector] Database Connection URL not found in SecretsManager", - ); - } - - return response.SecretString; - } catch (error) { - logMessage.error( - error, - "[database-connector] Failed to retrieve server-database-url", - ); - - throw error; - } -}; - -const createDatabaseConnector = (): Promise< - IDatabase, IClient> -> => { - logMessage.debug("[database-connector] Creating new database connector"); - - return getConnectionString().then((connectionString) => - pgp()({ - connectionString, - ssl: true, - }), + return PostgresConnector.defaultUsingPostgresConnectionUrlFromAwsSecret( + "server-database-url", ); }; -export const DatabaseConnectorClient: IDatabase< - Record, - IClient -> = await createDatabaseConnector(); +export const databaseConnector: PostgresConnector = + await createDatabaseConnector(); diff --git a/test/lib/formsClient/getFormTemplate.test.ts b/test/lib/formsClient/getFormTemplate.test.ts index 2045c4bb..7fa06597 100644 --- a/test/lib/formsClient/getFormTemplate.test.ts +++ b/test/lib/formsClient/getFormTemplate.test.ts @@ -1,15 +1,17 @@ -import { vi, describe, it, expect, beforeEach } from "vitest"; +import { vi, describe, it, expect, beforeEach, type Mock } from "vitest"; import { getFormTemplate } from "@lib/formsClient/getFormTemplate.js"; -import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js"; +import { databaseConnector } from "@lib/integration/databaseConnector.js"; import { logMessage } from "@lib/logging/logger.js"; +const sqlMock = databaseConnector.executeSqlStatement() as unknown as Mock; + describe("getFormTemplate should", () => { beforeEach(() => { vi.clearAllMocks(); }); it("return an undefined form template if database was not able to find it", async () => { - vi.spyOn(DatabaseConnectorClient, "oneOrNone").mockResolvedValueOnce(null); + sqlMock.mockResolvedValueOnce([]); const formTemplate = await getFormTemplate("clzamy5qv0000115huc4bh90m"); @@ -17,16 +19,18 @@ describe("getFormTemplate should", () => { }); it("return a form template if database was able to find it", async () => { - vi.spyOn(DatabaseConnectorClient, "oneOrNone").mockResolvedValueOnce({ - jsonConfig: { - elements: [ - { - id: 1, - type: "textField", - }, - ], + sqlMock.mockResolvedValueOnce([ + { + jsonConfig: { + elements: [ + { + id: 1, + type: "textField", + }, + ], + }, }, - }); + ]); const formTemplate = await getFormTemplate("clzamy5qv0000115huc4bh90m"); @@ -44,9 +48,7 @@ describe("getFormTemplate should", () => { it("throw an error if database has an internal failure", async () => { const customError = new Error("custom error"); - vi.spyOn(DatabaseConnectorClient, "oneOrNone").mockRejectedValueOnce( - customError, - ); + sqlMock.mockRejectedValueOnce(customError); const logMessageSpy = vi.spyOn(logMessage, "error"); await expect(() => diff --git a/test/lib/formsClient/getPublicKey.test.ts b/test/lib/formsClient/getPublicKey.test.ts index eae17a51..d65a2686 100644 --- a/test/lib/formsClient/getPublicKey.test.ts +++ b/test/lib/formsClient/getPublicKey.test.ts @@ -1,5 +1,5 @@ -import { vi, describe, it, expect, beforeEach } from "vitest"; -import { DatabaseConnectorClient } from "@lib/integration/databaseConnector.js"; +import { vi, describe, it, expect, beforeEach, type Mock } from "vitest"; +import { databaseConnector } from "@lib/integration/databaseConnector.js"; import { getPublicKey } from "@lib/formsClient/getPublicKey.js"; import { getValueFromRedis, @@ -11,6 +11,8 @@ vi.mock("@lib/integration/redis/redisClientAdapter"); const getValueFromRedisMock = vi.mocked(getValueFromRedis); const setValueInRedisMock = vi.mocked(setValueInRedis); +const sqlMock = databaseConnector.executeSqlStatement() as unknown as Mock; + describe("getPublicKey should", () => { beforeEach(() => { vi.clearAllMocks(); @@ -28,9 +30,9 @@ describe("getPublicKey should", () => { }); it("when it does not exist in cache", async () => { - vi.spyOn(DatabaseConnectorClient, "oneOrNone").mockResolvedValueOnce({ - publicKey: "RkS8hzu0MtwL+Qs2lK7KX9CLK7v6lxYpqs7ns5MwuOs=", - }); + sqlMock.mockResolvedValueOnce([ + { publicKey: "RkS8hzu0MtwL+Qs2lK7KX9CLK7v6lxYpqs7ns5MwuOs=" }, + ]); const publicKey = await getPublicKey("254354365464565461"); @@ -45,9 +47,7 @@ describe("getPublicKey should", () => { it("throw an error if database has an internal failure", async () => { const customError = new Error("custom error"); - vi.spyOn(DatabaseConnectorClient, "oneOrNone").mockRejectedValueOnce( - customError, - ); + sqlMock.mockRejectedValueOnce(customError); const logMessageSpy = vi.spyOn(logMessage, "info"); await expect(() => getPublicKey("254354365464565461")).rejects.toThrowError( diff --git a/vitest-setup.ts b/vitest-setup.ts index 9f2397ca..31bf5864 100644 --- a/vitest-setup.ts +++ b/vitest-setup.ts @@ -1,4 +1,5 @@ import { vi } from "vitest"; +import type { Sql } from "postgres"; process.env = { ...process.env, @@ -15,11 +16,28 @@ process.env = { }), }; -vi.mock("./src/lib/integration/databaseConnector", () => ({ - DatabaseConnectorClient: { - oneOrNone: vi.fn(), - }, -})); +// biome-ignore lint/suspicious/noExplicitAny: +const mockSql: Sql = vi.fn().mockResolvedValue([]) as unknown as Sql; + +class PostgresConnectorMock { + executeSqlStatement() { + return mockSql; + } +} + +vi.mock("@gcforms/connectors", async () => { + // biome-ignore lint/suspicious/noExplicitAny: + const actual: any = await vi.importActual("@gcforms/connectors"); + + return { + ...actual, + PostgresConnector: { + defaultUsingPostgresConnectionUrlFromAwsSecret: vi.fn( + async () => new PostgresConnectorMock(), + ), + }, + }; +}); vi.mock("./src/lib/logging/auditLogs", () => ({ auditLog: vi.fn(),