@digitraffic/common 2025.2.4-3 → 2025.2.28-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  import { type DTDatabase } from "../database/database.js";
2
2
  export declare function assertCount(db: DTDatabase, sql: string, count: number): Promise<void>;
3
- export declare function dbTestBase(fn: (db: DTDatabase) => void, truncateFn: (db: DTDatabase) => Promise<void>, dbUser: string, dbPass: string, dbUri: string): () => void;
3
+ export declare function dbTestBase(fn: (db: DTDatabase) => void, truncateFn: (db: DTDatabase) => Promise<void>, dbUser: string, dbPass: string, dbUri: string, convertNullsToUndefined?: boolean): () => void;
@@ -3,11 +3,11 @@ import { getEnvVariableOrElse } from "../utils/utils.js";
3
3
  export async function assertCount(db, sql, count) {
4
4
  await db.one(sql).then((x) => expect(x.count).toEqual(count));
5
5
  }
6
- export function dbTestBase(fn, truncateFn, dbUser, dbPass, dbUri) {
6
+ export function dbTestBase(fn, truncateFn, dbUser, dbPass, dbUri, convertNullsToUndefined = false) {
7
7
  const theDbUri = getEnvVariableOrElse("DB_URI", dbUri);
8
- console.log(`Test database URI: ${theDbUri}`);
8
+ console.log(`Test database URI: ${theDbUri}, convertNullsToUndefined: ${convertNullsToUndefined}`);
9
9
  return () => {
10
- const db = initDbConnection(dbUser, dbPass, "test", theDbUri, {
10
+ const db = initDbConnection(dbUser, dbPass, "test", theDbUri, convertNullsToUndefined, {
11
11
  noWarnings: true, // ignore duplicate connection warning for tests
12
12
  });
13
13
  beforeAll(async () => {
@@ -18,9 +18,10 @@ export type DTTransaction = ITask<unknown>;
18
18
  * @param password Password
19
19
  * @param applicationName name of application
20
20
  * @param url Connection URL
21
+ * @param convertNullsToUndefined if true null values in query results will be converted to undefined, Default false.
21
22
  * @param options pg-promise options
22
23
  */
23
- export declare function initDbConnection(username: string, password: string, applicationName: string, url: string, options?: object): DTDatabase;
24
- export declare function inTransaction<T>(fn: (db: DTTransaction) => Promise<T>): Promise<T>;
25
- export declare function inDatabase<T>(fn: (db: DTDatabase) => Promise<T>): Promise<T>;
26
- export declare function inDatabaseReadonly<T>(fn: (db: DTDatabase) => Promise<T>): Promise<T>;
24
+ export declare function initDbConnection(username: string, password: string, applicationName: string, url: string, convertNullsToUndefined: boolean, options?: object): DTDatabase;
25
+ export declare function inTransaction<T>(fn: (db: DTTransaction) => Promise<T>, convertNullsToUndefined?: boolean): Promise<T>;
26
+ export declare function inDatabase<T>(fn: (db: DTDatabase) => Promise<T>, convertNullsToUndefined?: boolean): Promise<T>;
27
+ export declare function inDatabaseReadonly<T>(fn: (db: DTDatabase) => Promise<T>, convertNullsToUndefined?: boolean): Promise<T>;
@@ -1,7 +1,7 @@
1
- import {} from "pg-promise";
2
- import { getEnvVariable, getEnvVariableOrElse } from "../utils/utils.js";
1
+ import pgpImport, {} from "pg-promise";
3
2
  import { logger } from "../aws/runtime/dt-logger-default.js";
4
3
  import { logException } from "../utils/logging.js";
4
+ import { getEnvVariable, getEnvVariableOrElse } from "../utils/utils.js";
5
5
  export var DatabaseEnvironmentKeys;
6
6
  (function (DatabaseEnvironmentKeys) {
7
7
  DatabaseEnvironmentKeys["DB_USER"] = "DB_USER";
@@ -10,18 +10,32 @@ export var DatabaseEnvironmentKeys;
10
10
  DatabaseEnvironmentKeys["DB_RO_URI"] = "DB_RO_URI";
11
11
  DatabaseEnvironmentKeys["DB_APPLICATION"] = "DB_APPLICATION";
12
12
  })(DatabaseEnvironmentKeys || (DatabaseEnvironmentKeys = {}));
13
- import pgpImport from "pg-promise";
14
- const pgp = pgpImport();
15
- // convert numeric types to number instead of string
16
- pgp.pg.types.setTypeParser(pgp.pg.types.builtins.INT8, (value) => {
17
- return parseInt(value);
18
- });
19
- pgp.pg.types.setTypeParser(pgp.pg.types.builtins.FLOAT8, (value) => {
20
- return parseFloat(value);
21
- });
22
- pgp.pg.types.setTypeParser(pgp.pg.types.builtins.NUMERIC, (value) => {
23
- return parseFloat(value);
24
- });
13
+ // pg-promise initialization options
14
+ // https://vitaly-t.github.io/pg-promise/global.html#event:receive
15
+ const pgpPromiseInitOptions = {
16
+ // eslint-disable-next-line
17
+ receive(e) {
18
+ if (e.data) {
19
+ convertNullColumnsToUndefined(e.data);
20
+ }
21
+ },
22
+ };
23
+ function initPgp(pgpPromiseInitOptions) {
24
+ const pgp = pgpPromiseInitOptions
25
+ ? pgpImport(pgpPromiseInitOptions)
26
+ : pgpImport();
27
+ // convert numeric types to number instead of string
28
+ pgp.pg.types.setTypeParser(pgp.pg.types.builtins.INT8, (value) => {
29
+ return parseInt(value);
30
+ });
31
+ pgp.pg.types.setTypeParser(pgp.pg.types.builtins.FLOAT8, (value) => {
32
+ return parseFloat(value);
33
+ });
34
+ pgp.pg.types.setTypeParser(pgp.pg.types.builtins.NUMERIC, (value) => {
35
+ return parseFloat(value);
36
+ });
37
+ return pgp;
38
+ }
25
39
  /**
26
40
  * Creates a non-pooling database connection primarily used by Lambdas.
27
41
  *
@@ -32,27 +46,28 @@ pgp.pg.types.setTypeParser(pgp.pg.types.builtins.NUMERIC, (value) => {
32
46
  * @param password Password
33
47
  * @param applicationName name of application
34
48
  * @param url Connection URL
49
+ * @param convertNullsToUndefined if true null values in query results will be converted to undefined, Default false.
35
50
  * @param options pg-promise options
36
51
  */
37
- export function initDbConnection(username, password, applicationName, url, options) {
52
+ export function initDbConnection(username, password, applicationName, url, convertNullsToUndefined, options) {
38
53
  const finalUrl = `postgresql://${username}:${password}@${url}?application_name=${applicationName}`;
39
- return pgp(finalUrl, options);
54
+ return initPgp(convertNullsToUndefined ? pgpPromiseInitOptions : undefined)(finalUrl, options);
40
55
  }
41
- export function inTransaction(fn) {
42
- return inDatabase((db) => db.tx((t) => fn(t)));
56
+ export function inTransaction(fn, convertNullsToUndefined = false) {
57
+ return inDatabase((db) => db.tx((t) => fn(t)), convertNullsToUndefined);
43
58
  }
44
- export function inDatabase(fn) {
45
- return doInDatabase(false, fn);
59
+ export function inDatabase(fn, convertNullsToUndefined = false) {
60
+ return doInDatabase(false, fn, convertNullsToUndefined);
46
61
  }
47
- export function inDatabaseReadonly(fn) {
48
- return doInDatabase(true, fn);
62
+ export function inDatabaseReadonly(fn, convertNullsToUndefined = false) {
63
+ return doInDatabase(true, fn, convertNullsToUndefined);
49
64
  }
50
- async function doInDatabase(readonly, fn) {
65
+ async function doInDatabase(readonly, fn, convertNullsToUndefined) {
51
66
  const db_application = getEnvVariableOrElse(DatabaseEnvironmentKeys.DB_APPLICATION, "unknown-cdk-application");
52
67
  const db_uri = readonly
53
68
  ? getEnvVariable(DatabaseEnvironmentKeys.DB_RO_URI)
54
69
  : getEnvVariable(DatabaseEnvironmentKeys.DB_URI);
55
- const db = initDbConnection(getEnvVariable(DatabaseEnvironmentKeys.DB_USER), getEnvVariable(DatabaseEnvironmentKeys.DB_PASS), db_application, db_uri);
70
+ const db = initDbConnection(getEnvVariable(DatabaseEnvironmentKeys.DB_USER), getEnvVariable(DatabaseEnvironmentKeys.DB_PASS), db_application, db_uri, convertNullsToUndefined);
56
71
  try {
57
72
  // deallocate all prepared statements to allow for connection pooling
58
73
  // DISCARD instead of DEALLOCATE as it didn't always clean all prepared statements
@@ -67,4 +82,18 @@ async function doInDatabase(readonly, fn) {
67
82
  await db.$pool.end();
68
83
  }
69
84
  }
85
+ // eslint-disable-next-line
86
+ function convertNullColumnsToUndefined(rows) {
87
+ rows.forEach((row) => {
88
+ // eslint-disable-next-line guard-for-in
89
+ for (const column in row) {
90
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
91
+ const columnValue = row[column];
92
+ if (columnValue === null) {
93
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
94
+ row[column] = undefined;
95
+ }
96
+ }
97
+ });
98
+ }
70
99
  //# sourceMappingURL=database.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitraffic/common",
3
- "version": "2025.2.4-3",
3
+ "version": "2025.2.28-1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "repository": {
@@ -126,32 +126,32 @@
126
126
  "zod": "^3.24.1"
127
127
  },
128
128
  "devDependencies": {
129
- "@aws-sdk/client-api-gateway": "^3.738.0",
130
- "@aws-sdk/client-s3": "^3.738.0",
131
- "@aws-sdk/client-secrets-manager": "^3.738.0",
132
- "@aws-sdk/client-sns": "^3.738.0",
133
- "@aws-sdk/lib-storage": "^3.738.0",
129
+ "@aws-sdk/client-api-gateway": "^3.758.0",
130
+ "@aws-sdk/client-s3": "^3.758.0",
131
+ "@aws-sdk/client-secrets-manager": "^3.758.0",
132
+ "@aws-sdk/client-sns": "^3.758.0",
133
+ "@aws-sdk/lib-storage": "^3.758.0",
134
134
  "@date-fns/tz": "1.2.0",
135
135
  "@digitraffic/eslint-config": "^3.1.1",
136
136
  "@jest/globals": "^29.7.0",
137
137
  "@rushstack/eslint-config": "^3.7.1",
138
- "@rushstack/heft": "^0.68.15",
139
- "@rushstack/heft-jest-plugin": "^0.14.5",
140
- "@rushstack/heft-lint-plugin": "^0.5.14",
141
- "@rushstack/heft-typescript-plugin": "^0.6.8",
142
- "@smithy/fetch-http-handler": "4.1.3",
143
- "@smithy/types": "^3.7.2",
138
+ "@rushstack/heft": "^0.69.1",
139
+ "@rushstack/heft-jest-plugin": "^0.14.11",
140
+ "@rushstack/heft-lint-plugin": "^0.5.20",
141
+ "@rushstack/heft-typescript-plugin": "^0.6.13",
142
+ "@smithy/fetch-http-handler": "5.0.1",
143
+ "@smithy/types": "^4.1.0",
144
144
  "@types/aws-lambda": "8.10.147",
145
145
  "@types/etag": "^1.8.3",
146
- "@types/geojson": "7946.0.15",
146
+ "@types/geojson": "7946.0.16",
147
147
  "@types/geojson-validation": "^1.0.3",
148
148
  "@types/jest": "29.5.14",
149
149
  "@types/lodash-es": "4.17.12",
150
150
  "@types/madge": "5.0.3",
151
- "@types/node": "20.17.6",
151
+ "@types/node": "22.13.5",
152
152
  "@typescript-eslint/eslint-plugin": "~7.14.1",
153
- "@typescript-eslint/parser": "^7.18.0",
154
- "aws-cdk-lib": "^2.177.0",
153
+ "@typescript-eslint/parser": "^7.0.0",
154
+ "aws-cdk-lib": "^2.181.1",
155
155
  "aws-sdk": "^2.1692.0",
156
156
  "change-case": "^5.4.4",
157
157
  "constructs": "~10.4.2",
@@ -163,20 +163,20 @@
163
163
  "geojson-validation": "^1.0.2",
164
164
  "jest": "^29.7.0",
165
165
  "jest-junit": "^16.0.0",
166
- "ky": "^1.7.4",
167
- "lefthook": "^1.10.10",
166
+ "ky": "^1.7.5",
167
+ "lefthook": "^1.11.2",
168
168
  "lodash": "^4.17.21",
169
169
  "lodash-es": "~4.17.21",
170
170
  "madge": "^8.0.0",
171
171
  "node-ttl": "^0.2.0",
172
- "pg-native": "^3.2.0",
172
+ "pg-native": "^3.2.2",
173
173
  "pg-promise": "^11.10.2",
174
174
  "pg-query-stream": "4.7.1",
175
175
  "rimraf": "^6.0.1",
176
- "ts-jest": "^29.2.5",
176
+ "ts-jest": "^29.2.6",
177
177
  "typescript": "~5.6.3",
178
178
  "velocityjs": "^2.0.6",
179
- "zod": "~3.24.1"
179
+ "zod": "~3.24.2"
180
180
  },
181
181
  "scripts": {
182
182
  "build": "heft build --clean",