Skip to content

Commit 65306b4

Browse files
committed
Usability improvements for Pongo shell
Added: - PostgreSQL connection check, - an option to set the prettifying and log level through shell params
1 parent 5c95c90 commit 65306b4

File tree

11 files changed

+287
-88
lines changed

11 files changed

+287
-88
lines changed

src/package-lock.json

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@event-driven-io/pongo-core",
3-
"version": "0.15.3",
3+
"version": "0.16.0-alpha.6",
44
"description": "Pongo - Mongo with strong consistency on top of Postgres",
55
"type": "module",
66
"engines": {

src/packages/dumbo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@event-driven-io/dumbo",
3-
"version": "0.11.1",
3+
"version": "0.12.0-alpha.6",
44
"description": "Dumbo - tools for dealing with PostgreSQL",
55
"type": "module",
66
"scripts": {

src/packages/dumbo/src/core/schema/migrations.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
rawSql,
44
singleOrNull,
55
sql,
6+
tracer,
67
type SchemaComponent,
78
type SQLExecutor,
89
} from '..';
@@ -101,7 +102,10 @@ const runSQLMigration = async (
101102
await recordMigration(execute, newMigration);
102103
// console.log(`Migration "${newMigration.name}" applied successfully.`);
103104
} catch (error) {
104-
console.error(`Failed to apply migration "${migration.name}":`, error);
105+
tracer.error('migration-error', {
106+
migationName: migration.name,
107+
error: error,
108+
});
105109
throw error;
106110
}
107111
};

src/packages/dumbo/src/core/tracing/index.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import { JSONSerializer } from '../serializer';
2-
import { prettyPrintJson } from './printing';
2+
import { prettyJson } from './printing';
33

44
export const tracer = () => {};
55

66
export type LogLevel = 'DISABLED' | 'INFO' | 'LOG' | 'WARN' | 'ERROR';
77

8-
export type LogType = 'CONSOLE';
9-
10-
export type LogStyle = 'RAW' | 'PRETTY';
11-
128
export const LogLevel = {
139
DISABLED: 'DISABLED' as LogLevel,
1410
INFO: 'INFO' as LogLevel,
@@ -17,6 +13,15 @@ export const LogLevel = {
1713
ERROR: 'ERROR' as LogLevel,
1814
};
1915

16+
export type LogType = 'CONSOLE';
17+
18+
export type LogStyle = 'RAW' | 'PRETTY';
19+
20+
export const LogStyle = {
21+
RAW: 'RAW' as LogStyle,
22+
PRETTY: 'PRETTY' as LogStyle,
23+
};
24+
2025
const shouldLog = (logLevel: LogLevel): boolean => {
2126
const definedLogLevel = process.env.DUMBO_LOG_LEVEL ?? LogLevel.DISABLED;
2227

@@ -37,7 +42,9 @@ const shouldLog = (logLevel: LogLevel): boolean => {
3742

3843
if (
3944
definedLogLevel === LogLevel.INFO &&
40-
[LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO].includes(logLevel)
45+
[LogLevel.ERROR, LogLevel.WARN, LogLevel.LOG, LogLevel.INFO].includes(
46+
logLevel,
47+
)
4148
)
4249
return true;
4350

@@ -59,7 +66,7 @@ const getTraceEventFormatter =
5966
case 'RAW':
6067
return JSONSerializer.serialize(event);
6168
case 'PRETTY':
62-
return prettyPrintJson(event, true);
69+
return prettyJson(event, { handleMultiline: true });
6370
}
6471
};
6572

src/packages/dumbo/src/core/tracing/printing/pretty.ts

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ const TWO_SPACES = ' ';
44

55
const COLOR_STRING = chalk.hex('#98c379'); // Soft green for strings
66
const COLOR_KEY = chalk.hex('#61afef'); // Muted cyan for keys
7-
const COLOR_NUMBER = chalk.hex('#d19a66'); // Light orange for numbers
7+
const COLOR_NUMBER_OR_DATE = chalk.hex('#d19a66'); // Light orange for numbers
88
const COLOR_BOOLEAN = chalk.hex('#c678dd'); // Light purple for booleans
9-
const COLOR_NULL = chalk.hex('#c678dd'); // Light purple for null
9+
const COLOR_NULL_OR_UNDEFINED = chalk.hex('#c678dd'); // Light purple for null
1010
const COLOR_BRACKETS = chalk.hex('#abb2bf'); // Soft white for object and array brackets
1111

1212
const processString = (
@@ -31,7 +31,10 @@ const processString = (
3131
return COLOR_STRING(`"${str}"`);
3232
};
3333

34-
// Function to format and colorize JSON by traversing it
34+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35+
const shouldPrint = (obj: any): boolean =>
36+
typeof obj !== 'function' && typeof obj !== 'symbol';
37+
3538
const formatJson = (
3639
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3740
obj: any,
@@ -40,13 +43,34 @@ const formatJson = (
4043
): string => {
4144
const indent = TWO_SPACES.repeat(indentLevel);
4245

43-
if (obj === null) return COLOR_NULL('null');
46+
if (obj === null) return COLOR_NULL_OR_UNDEFINED('null');
47+
48+
if (obj === undefined) return COLOR_NULL_OR_UNDEFINED('undefined');
49+
4450
if (typeof obj === 'string')
4551
return processString(obj, indent, handleMultiline);
46-
if (typeof obj === 'number') return COLOR_NUMBER(String(obj));
52+
if (typeof obj === 'number' || typeof obj === 'bigint' || obj instanceof Date)
53+
return COLOR_NUMBER_OR_DATE(String(obj));
4754
if (typeof obj === 'boolean') return COLOR_BOOLEAN(String(obj));
4855

49-
// Handle arrays
56+
if (obj instanceof Error) {
57+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
58+
const errorObj: Record<string, any> = {};
59+
60+
const propNames = Object.getOwnPropertyNames(obj);
61+
62+
propNames.forEach((key) => {
63+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
64+
errorObj[key] = (obj as any)[key];
65+
});
66+
67+
return formatJson(errorObj, indentLevel, handleMultiline);
68+
}
69+
70+
if (obj instanceof Promise) {
71+
return COLOR_STRING('Promise {pending}');
72+
}
73+
5074
if (Array.isArray(obj)) {
5175
const arrayItems = obj.map((item) =>
5276
formatJson(item, indentLevel + 1, handleMultiline),
@@ -57,20 +81,21 @@ const formatJson = (
5781
}
5882

5983
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
60-
const entries = Object.entries(obj).map(
61-
([key, value]) =>
62-
`${COLOR_KEY(`"${key}"`)}: ${formatJson(
63-
value,
64-
indentLevel + 1,
65-
handleMultiline,
66-
)}`,
84+
const entries = Object.entries(obj).map(([key, value]) =>
85+
shouldPrint(value)
86+
? `${COLOR_KEY(`"${key}"`)}: ${formatJson(
87+
value,
88+
indentLevel + 1,
89+
handleMultiline,
90+
)}`
91+
: '',
6792
);
6893
return `${COLOR_BRACKETS('{')}\n${indent} ${entries.join(
6994
`,\n${indent} `,
7095
)}\n${indent}${COLOR_BRACKETS('}')}`;
7196
};
7297

73-
export const prettyPrintJson = (
98+
export const prettyJson = (
7499
obj: unknown,
75-
handleMultiline: boolean = false,
76-
): string => formatJson(obj, 0, handleMultiline);
100+
options?: { handleMultiline?: boolean },
101+
): string => formatJson(obj, 0, options?.handleMultiline);

src/packages/dumbo/src/core/tracing/printing/pretty.unit.spec.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import assert from 'assert';
22
import chalk from 'chalk';
33
import { describe, it } from 'node:test';
4-
import { prettyPrintJson } from './pretty';
4+
import { prettyJson } from './pretty';
55

6-
// Define a basic test suite
76
void describe('prettyPrintJson', () => {
87
// Turn off chalk colorization during tests for easy comparison
98
chalk.level = 0;
@@ -19,7 +18,7 @@ void describe('prettyPrintJson', () => {
1918
"age": 30
2019
}`;
2120

22-
const output = prettyPrintJson(input, false); // Multiline handling off
21+
const output = prettyJson(input, { handleMultiline: false });
2322
assert.strictEqual(output, expectedOutput);
2423
});
2524

@@ -37,7 +36,7 @@ void describe('prettyPrintJson', () => {
3736
"
3837
}`;
3938

40-
const output = prettyPrintJson(input, true); // Multiline handling on
39+
const output = prettyJson(input, { handleMultiline: true });
4140
assert.strictEqual(output, expectedOutput);
4241
});
4342

@@ -64,7 +63,7 @@ void describe('prettyPrintJson', () => {
6463
}
6564
}`;
6665

67-
const output = prettyPrintJson(input, false); // Multiline handling off
66+
const output = prettyJson(input, { handleMultiline: false });
6867
assert.strictEqual(output, expectedOutput);
6968
});
7069

@@ -85,7 +84,7 @@ void describe('prettyPrintJson', () => {
8584
"active": true
8685
}`;
8786

88-
const output = prettyPrintJson(input, false); // Multiline handling off
87+
const output = prettyJson(input, { handleMultiline: false });
8988
assert.strictEqual(output, expectedOutput);
9089
});
9190

@@ -102,7 +101,7 @@ void describe('prettyPrintJson', () => {
102101
"tags": null
103102
}`;
104103

105-
const output = prettyPrintJson(input, false); // Multiline handling off
104+
const output = prettyJson(input, { handleMultiline: false });
106105
assert.strictEqual(output, expectedOutput);
107106
});
108107

@@ -121,8 +120,7 @@ void describe('prettyPrintJson', () => {
121120
"
122121
}`;
123122

124-
const output = prettyPrintJson(input, true); // Multiline handling on
125-
console.log(output);
123+
const output = prettyJson(input, { handleMultiline: true });
126124
assert.strictEqual(output, expectedOutput);
127125
});
128126
});

src/packages/dumbo/src/postgres/pg/connections/connection.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,47 @@ export function nodePostgresConnection(
7777
? nodePostgresClientConnection(options)
7878
: nodePostgresPoolClientConnection(options);
7979
}
80+
81+
export type ConnectionCheckResult =
82+
| { successful: true }
83+
| {
84+
successful: false;
85+
code: string | undefined;
86+
errorType: 'ConnectionRefused' | 'Authentication' | 'Unknown';
87+
error: unknown;
88+
};
89+
90+
export const checkConnection = async (
91+
connectionString: string,
92+
): Promise<ConnectionCheckResult> => {
93+
const client = new pg.Client({
94+
connectionString: connectionString,
95+
});
96+
97+
try {
98+
await client.connect();
99+
return { successful: true };
100+
} catch (error) {
101+
const code =
102+
error instanceof Error &&
103+
'code' in error &&
104+
typeof error.code === 'string'
105+
? error.code
106+
: undefined;
107+
108+
return {
109+
successful: false,
110+
errorType:
111+
code === 'ECONNREFUSED'
112+
? 'ConnectionRefused'
113+
: code === '28P01'
114+
? 'Authentication'
115+
: 'Unknown',
116+
code,
117+
error,
118+
};
119+
} finally {
120+
// Ensure the client is closed properly if connected
121+
await client.end();
122+
}
123+
};

src/packages/dumbo/src/postgres/pg/connections/pool.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@ import pg from 'pg';
22
import {
33
createConnectionPool,
44
JSONSerializer,
5+
tracer,
56
type ConnectionPool,
67
} from '../../../core';
78
import {
89
defaultPostgreSqlDatabase,
910
getDatabaseNameOrDefault,
1011
} from '../../core';
12+
import { setNodePostgresTypeParser } from '../serialization';
1113
import {
1214
nodePostgresConnection,
1315
NodePostgresConnectorType,
1416
type NodePostgresClientConnection,
1517
type NodePostgresConnector,
1618
type NodePostgresPoolClientConnection,
1719
} from './connection';
18-
import { setNodePostgresTypeParser } from '../serialization';
1920

2021
export type NodePostgresNativePool =
2122
ConnectionPool<NodePostgresPoolClientConnection>;
@@ -291,8 +292,7 @@ export const onEndPool = async (lookupKey: string, pool: pg.Pool) => {
291292
try {
292293
await pool.end();
293294
} catch (error) {
294-
console.log(`Error while closing the connection pool: ${lookupKey}`);
295-
console.log(error);
295+
tracer.error('connection-closing-error', { lookupKey, error });
296296
}
297297
pools.delete(lookupKey);
298298
};

src/packages/pongo/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@event-driven-io/pongo",
3-
"version": "0.15.3",
3+
"version": "0.16.0-alpha.6",
44
"description": "Pongo - Mongo with strong consistency on top of Postgres",
55
"type": "module",
66
"scripts": {
@@ -87,7 +87,7 @@
8787
"pongo": "./dist/cli.js"
8888
},
8989
"peerDependencies": {
90-
"@event-driven-io/dumbo": "0.11.1",
90+
"@event-driven-io/dumbo": "0.12.0-alpha.6",
9191
"@types/mongodb": "^4.0.7",
9292
"@types/pg": "^8.11.6",
9393
"@types/uuid": "^10.0.0",

0 commit comments

Comments
 (0)