Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Usability improvements for Pongo shell #93

Merged
merged 10 commits into from
Oct 9, 2024
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,11 @@ MongoDB is a decent database, yet it has issues around [ACID-complaince](https:/
- operate **easier than crafting native PostgreSQL JSON queries**. They're powerful but not the most accessible,
- get **performance boost** with [JSONB indexing capabilities](https://pganalyze.com/blog/gin-index#postgresql-jsonb-and-gin-indexes),
- **benefit from PostgreSQL advanced capabilities** like [partitioning](https://www.postgresql.fastware.com/postgresql-insider-prt-ove), [logical replication](https://event-driven.io/en/push_based_outbox_pattern_with_postgres_logical_replication/) and [other PostgreSQL superpowers](https://event-driven.io/en/postgres_superpowers/)
- **seamless integration with Cloud RDSes** and solutions like [CockroachDB](https://www.cockroachlabs.com/docs/stable/why-cockroachdb), [Supabase](https://supabase.com/), [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres).
- **seamless integration with Cloud RDSes** and solutions like [Supabase](https://supabase.com/), [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres), [YugabyteDB](https://www.yugabyte.com/yugabytedb/), [CockroachDB](https://www.cockroachlabs.com/docs/stable/why-cockroachdb), .

Watch also more in:

[![](https://i.ytimg.com/vi/P4r19rv4vOg/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLA5xOyPKh2X4f4ghHcapr5n69GvvA)](https://www.youtube.com/watch?v=P4r19rv4vOg)

## Storage

Expand Down
6 changes: 5 additions & 1 deletion src/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,11 @@ MongoDB is a decent database, yet it has issues around [ACID-complaince](https:/
- operate **easier than crafting native PostgreSQL JSON queries**. They're powerful but not the most accessible,
- get **performance boost** with [JSONB indexing capabilities](https://pganalyze.com/blog/gin-index#postgresql-jsonb-and-gin-indexes),
- **benefit from PostgreSQL advanced capabilities** like [partitioning](https://www.postgresql.fastware.com/postgresql-insider-prt-ove), [logical replication](https://event-driven.io/en/push_based_outbox_pattern_with_postgres_logical_replication/) and [other PostgreSQL superpowers](https://event-driven.io/en/postgres_superpowers/)
- **seamless integration with Cloud RDSes** and solutions like [CockroachDB](https://www.cockroachlabs.com/docs/stable/why-cockroachdb), [Supabase](https://supabase.com/), [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres).
- **seamless integration with Cloud RDSes** and solutions like [Supabase](https://supabase.com/), [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres), [YugabyteDB](https://www.yugabyte.com/yugabytedb/), [CockroachDB](https://www.cockroachlabs.com/docs/stable/why-cockroachdb), .

Watch also more in:

[![](https://i.ytimg.com/vi/P4r19rv4vOg/hqdefault.jpg?sqp=-oaymwEcCNACELwBSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLA5xOyPKh2X4f4ghHcapr5n69GvvA)](https://www.youtube.com/watch?v=P4r19rv4vOg)

## Storage

Expand Down
10 changes: 5 additions & 5 deletions src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@event-driven-io/pongo-core",
"version": "0.15.3",
"version": "0.16.0-alpha.11",
"description": "Pongo - Mongo with strong consistency on top of Postgres",
"type": "module",
"engines": {
Expand Down
2 changes: 1 addition & 1 deletion src/packages/dumbo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@event-driven-io/dumbo",
"version": "0.11.1",
"version": "0.12.0-alpha.11",
"description": "Dumbo - tools for dealing with PostgreSQL",
"type": "module",
"scripts": {
Expand Down
6 changes: 5 additions & 1 deletion src/packages/dumbo/src/core/schema/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
rawSql,
singleOrNull,
sql,
tracer,
type SchemaComponent,
type SQLExecutor,
} from '..';
Expand Down Expand Up @@ -101,7 +102,10 @@ const runSQLMigration = async (
await recordMigration(execute, newMigration);
// console.log(`Migration "${newMigration.name}" applied successfully.`);
} catch (error) {
console.error(`Failed to apply migration "${migration.name}":`, error);
tracer.error('migration-error', {
migationName: migration.name,
error: error,
});
throw error;
}
};
Expand Down
2 changes: 2 additions & 0 deletions src/packages/dumbo/src/core/sql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const defaultFormat = (value: unknown) => {
return format('%L', value);
} else if (Array.isArray(value)) {
return format('(%L)', value);
} else if (typeof value === 'object') {
return format('%s', JSON.stringify(value));
} else {
return format('%L', value);
}
Expand Down
21 changes: 14 additions & 7 deletions src/packages/dumbo/src/core/tracing/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { JSONSerializer } from '../serializer';
import { prettyPrintJson } from './printing';
import { prettyJson } from './printing';

export const tracer = () => {};

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

export type LogType = 'CONSOLE';

export type LogStyle = 'RAW' | 'PRETTY';

export const LogLevel = {
DISABLED: 'DISABLED' as LogLevel,
INFO: 'INFO' as LogLevel,
Expand All @@ -17,6 +13,15 @@ export const LogLevel = {
ERROR: 'ERROR' as LogLevel,
};

export type LogType = 'CONSOLE';

export type LogStyle = 'RAW' | 'PRETTY';

export const LogStyle = {
RAW: 'RAW' as LogStyle,
PRETTY: 'PRETTY' as LogStyle,
};

const shouldLog = (logLevel: LogLevel): boolean => {
const definedLogLevel = process.env.DUMBO_LOG_LEVEL ?? LogLevel.DISABLED;

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

if (
definedLogLevel === LogLevel.INFO &&
[LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO].includes(logLevel)
[LogLevel.ERROR, LogLevel.WARN, LogLevel.LOG, LogLevel.INFO].includes(
logLevel,
)
)
return true;

Expand All @@ -59,7 +66,7 @@ const getTraceEventFormatter =
case 'RAW':
return JSONSerializer.serialize(event);
case 'PRETTY':
return prettyPrintJson(event, true);
return prettyJson(event, { handleMultiline: true });
}
};

Expand Down
60 changes: 43 additions & 17 deletions src/packages/dumbo/src/core/tracing/printing/pretty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ const TWO_SPACES = ' ';

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

const processString = (
Expand All @@ -31,7 +31,10 @@ const processString = (
return COLOR_STRING(`"${str}"`);
};

// Function to format and colorize JSON by traversing it
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const shouldPrint = (obj: any): boolean =>
typeof obj !== 'function' && typeof obj !== 'symbol';

const formatJson = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
obj: any,
Expand All @@ -40,13 +43,34 @@ const formatJson = (
): string => {
const indent = TWO_SPACES.repeat(indentLevel);

if (obj === null) return COLOR_NULL('null');
if (obj === null) return COLOR_NULL_OR_UNDEFINED('null');

if (obj === undefined) return COLOR_NULL_OR_UNDEFINED('undefined');

if (typeof obj === 'string')
return processString(obj, indent, handleMultiline);
if (typeof obj === 'number') return COLOR_NUMBER(String(obj));
if (typeof obj === 'number' || typeof obj === 'bigint' || obj instanceof Date)
return COLOR_NUMBER_OR_DATE(String(obj));
if (typeof obj === 'boolean') return COLOR_BOOLEAN(String(obj));

// Handle arrays
if (obj instanceof Error) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const errorObj: Record<string, any> = {};

const propNames = Object.getOwnPropertyNames(obj);

propNames.forEach((key) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
errorObj[key] = (obj as any)[key];
});

return formatJson(errorObj, indentLevel, handleMultiline);
}

if (obj instanceof Promise) {
return COLOR_STRING('Promise {pending}');
}

if (Array.isArray(obj)) {
const arrayItems = obj.map((item) =>
formatJson(item, indentLevel + 1, handleMultiline),
Expand All @@ -57,20 +81,22 @@ const formatJson = (
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const entries = Object.entries(obj).map(
([key, value]) =>
`${COLOR_KEY(`"${key}"`)}: ${formatJson(
value,
indentLevel + 1,
handleMultiline,
)}`,
);
const entries = Object.entries(obj)
.filter(([_, value]) => shouldPrint(value))
.map(
([key, value]) =>
`${COLOR_KEY(`"${key}"`)}: ${formatJson(
value,
indentLevel + 1,
handleMultiline,
)}`,
);
return `${COLOR_BRACKETS('{')}\n${indent} ${entries.join(
`,\n${indent} `,
)}\n${indent}${COLOR_BRACKETS('}')}`;
};

export const prettyPrintJson = (
export const prettyJson = (
obj: unknown,
handleMultiline: boolean = false,
): string => formatJson(obj, 0, handleMultiline);
options?: { handleMultiline?: boolean },
): string => formatJson(obj, 0, options?.handleMultiline);
16 changes: 7 additions & 9 deletions src/packages/dumbo/src/core/tracing/printing/pretty.unit.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import assert from 'assert';
import chalk from 'chalk';
import { describe, it } from 'node:test';
import { prettyPrintJson } from './pretty';
import { prettyJson } from './pretty';

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

const output = prettyPrintJson(input, false); // Multiline handling off
const output = prettyJson(input, { handleMultiline: false });
assert.strictEqual(output, expectedOutput);
});

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

const output = prettyPrintJson(input, true); // Multiline handling on
const output = prettyJson(input, { handleMultiline: true });
assert.strictEqual(output, expectedOutput);
});

Expand All @@ -64,7 +63,7 @@ void describe('prettyPrintJson', () => {
}
}`;

const output = prettyPrintJson(input, false); // Multiline handling off
const output = prettyJson(input, { handleMultiline: false });
assert.strictEqual(output, expectedOutput);
});

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

const output = prettyPrintJson(input, false); // Multiline handling off
const output = prettyJson(input, { handleMultiline: false });
assert.strictEqual(output, expectedOutput);
});

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

const output = prettyPrintJson(input, false); // Multiline handling off
const output = prettyJson(input, { handleMultiline: false });
assert.strictEqual(output, expectedOutput);
});

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

const output = prettyPrintJson(input, true); // Multiline handling on
console.log(output);
const output = prettyJson(input, { handleMultiline: true });
assert.strictEqual(output, expectedOutput);
});
});
44 changes: 44 additions & 0 deletions src/packages/dumbo/src/postgres/pg/connections/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,47 @@ export function nodePostgresConnection(
? nodePostgresClientConnection(options)
: nodePostgresPoolClientConnection(options);
}

export type ConnectionCheckResult =
| { successful: true }
| {
successful: false;
code: string | undefined;
errorType: 'ConnectionRefused' | 'Authentication' | 'Unknown';
error: unknown;
};

export const checkConnection = async (
connectionString: string,
): Promise<ConnectionCheckResult> => {
const client = new pg.Client({
connectionString: connectionString,
});

try {
await client.connect();
return { successful: true };
} catch (error) {
const code =
error instanceof Error &&
'code' in error &&
typeof error.code === 'string'
? error.code
: undefined;

return {
successful: false,
errorType:
code === 'ECONNREFUSED'
? 'ConnectionRefused'
: code === '28P01'
? 'Authentication'
: 'Unknown',
code,
error,
};
} finally {
// Ensure the client is closed properly if connected
await client.end();
}
};
Loading