diff --git a/README.md b/README.md index 17859ea..fdd8a4f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,15 @@ A lightweight PostgreSQL driver for Deno focused on developer experience. [node-postgres](https://github.com/brianc/node-postgres) and [pq](https://github.com/lib/pq). -## Example +## Documentation + +The documentation is available on the deno-postgres website +[https://deno-postgres.com/](https://deno-postgres.com/) + +Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to +discuss bugs and features before opening issues. + +## Examples ```ts // deno run --allow-net --allow-read mod.ts @@ -32,8 +40,8 @@ await client.connect(); } { - const result = await client - .queryArray`SELECT ID, NAME FROM PEOPLE WHERE ID = ${1}`; + const result = + await client.queryArray`SELECT ID, NAME FROM PEOPLE WHERE ID = ${1}`; console.log(result.rows); // [[1, 'Carlos']] } @@ -43,25 +51,14 @@ await client.connect(); } { - const result = await client - .queryObject`SELECT ID, NAME FROM PEOPLE WHERE ID = ${1}`; + const result = + await client.queryObject`SELECT ID, NAME FROM PEOPLE WHERE ID = ${1}`; console.log(result.rows); // [{id: 1, name: 'Carlos'}] } await client.end(); ``` -For more examples, visit the documentation available at -[https://deno-postgres.com/](https://deno-postgres.com/) - -## Documentation - -The documentation is available on the deno-postgres website -[https://deno-postgres.com/](https://deno-postgres.com/) - -Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to -discuss bugs and features before opening issues. - ## Contributing ### Prerequisites @@ -156,6 +153,14 @@ This situation will stabilize as `std` and `deno-postgres` approach version 1.0. | 1.17.0 | 0.15.0 | 0.17.1 | | | 1.40.0 | 0.17.2 | | Now available on JSR | +## Breaking changes + +Although the `deno-driver` is pretty stable and robust, it is a WIP and we're still exploring the design. Expect some breaking changes as we reach version 1.0 and enhance the feature set. PLease check the Releases for more info on breaking changes. Please reach out if there are any undocumented breaking changes. + +## Found issues? + +Please file an issue with any problems with the driver in this repository's issue section. If you would like to help, please look at the issues as well. You can pick up one of them and try to implement it. + ## Contributing guidelines When contributing to the repository, make sure to: diff --git a/connection/connection.ts b/connection/connection.ts index c062553..4d5e270 100644 --- a/connection/connection.ts +++ b/connection/connection.ts @@ -30,6 +30,7 @@ import { bold, BufReader, BufWriter, + cyan, delay, joinPath, yellow, @@ -68,6 +69,7 @@ import { INCOMING_TLS_MESSAGES, } from "./message_code.ts"; import { hashMd5Password } from "./auth.ts"; +import { isDebugOptionEnabled } from "../debug.ts"; // Work around unstable limitation type ConnectOptions = @@ -100,6 +102,14 @@ function logNotice(notice: Notice) { console.error(`${bold(yellow(notice.severity))}: ${notice.message}`); } +function logQuery(query: string) { + console.error(`${bold(cyan("QUERY"))}: ${query}`); +} + +function logResults(rows: unknown[]) { + console.error(`${bold("RESULTS")}: ${rows}`); +} + const decoder = new TextDecoder(); const encoder = new TextEncoder(); @@ -695,7 +705,14 @@ export class Connection { break; case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: { const notice = parseNoticeMessage(current_message); - logNotice(notice); + if ( + isDebugOptionEnabled( + "notices", + this.#connection_params.controls?.debug, + ) + ) { + logNotice(notice); + } result.warnings.push(notice); break; } @@ -819,6 +836,12 @@ export class Connection { /** * https://www.postgresql.org/docs/14/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY */ + async #preparedQuery( + query: Query, + ): Promise; + async #preparedQuery( + query: Query, + ): Promise; async #preparedQuery( query: Query, ): Promise { @@ -872,7 +895,14 @@ export class Connection { break; case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: { const notice = parseNoticeMessage(current_message); - logNotice(notice); + if ( + isDebugOptionEnabled( + "notices", + this.#connection_params.controls?.debug, + ) + ) { + logNotice(notice); + } result.warnings.push(notice); break; } @@ -911,11 +941,23 @@ export class Connection { await this.#queryLock.pop(); try { + if ( + isDebugOptionEnabled("queries", this.#connection_params.controls?.debug) + ) { + logQuery(query.text); + } + let result: QueryArrayResult | QueryObjectResult; if (query.args.length === 0) { - return await this.#simpleQuery(query); + result = await this.#simpleQuery(query); } else { - return await this.#preparedQuery(query); + result = await this.#preparedQuery(query); + } + if ( + isDebugOptionEnabled("results", this.#connection_params.controls?.debug) + ) { + logResults(result.rows); } + return result; } catch (e) { if (e instanceof ConnectionError) { await this.end(); diff --git a/connection/connection_params.ts b/connection/connection_params.ts index 8201625..7c69bec 100644 --- a/connection/connection_params.ts +++ b/connection/connection_params.ts @@ -2,6 +2,7 @@ import { parseConnectionUri } from "../utils/utils.ts"; import { ConnectionParamsError } from "../client/error.ts"; import { fromFileUrl, isAbsolute } from "../deps.ts"; import { OidType } from "../query/oid.ts"; +import { DebugControls } from "../debug.ts"; /** * The connection string must match the following URI structure. All parameters but database and user are optional @@ -115,6 +116,10 @@ export type DecoderFunction = (value: string, oid: number) => unknown; * Control the behavior for the client instance */ export type ClientControls = { + /** + * Debugging options + */ + debug: DebugControls; /** * The strategy to use when decoding results data * diff --git a/debug.ts b/debug.ts new file mode 100644 index 0000000..c71fe9c --- /dev/null +++ b/debug.ts @@ -0,0 +1,30 @@ +/** + * Controls debugging behavior {@default false} + * + * - `true` : all debug options are enabled + * - `false` : all debug options are disabled + * - DebugOptions: + * - `query` : Log queries + * - `notices` : Log notices + */ +export type DebugControls = DebugOptions | boolean; + +type DebugOptions = { + /** Log queries */ + queries?: boolean; + /** Log notices */ + notices?: boolean; + /** Log results */ + results?: boolean; +}; + +export const isDebugOptionEnabled = ( + option: keyof DebugOptions, + options?: DebugControls, +): boolean => { + if (typeof options === "boolean") { + return options; + } + + return !!options?.[option]; +}; diff --git a/deps.ts b/deps.ts index 1dcd6ce..3b9b8ff 100644 --- a/deps.ts +++ b/deps.ts @@ -6,7 +6,11 @@ export { BufWriter } from "https://deno.land/std@0.214.0/io/buf_writer.ts"; export { copy } from "https://deno.land/std@0.214.0/bytes/copy.ts"; export { crypto } from "https://deno.land/std@0.214.0/crypto/crypto.ts"; export { delay } from "https://deno.land/std@0.214.0/async/delay.ts"; -export { bold, yellow } from "https://deno.land/std@0.214.0/fmt/colors.ts"; +export { + bold, + cyan, + yellow, +} from "https://deno.land/std@0.214.0/fmt/colors.ts"; export { fromFileUrl, isAbsolute, diff --git a/docs/README.md b/docs/README.md index f9c7559..05dd78b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1393,3 +1393,37 @@ await transaction.queryArray`INSERT INTO DONT_DELETE_ME VALUES (2)`; // Still in await transaction.commit(); // Transaction ends, client gets unlocked ``` + +## Debugging + +The driver can provide different types of logs if as needed. By default, logs +are disabled to keep your environment as uncluttered as possible. Logging can be +enabled by using the `debug` option in the Client `controls` parameter. Pass +`true` to enable all logs, or turn on logs granulary by enabling the following +options: + +- `queries` : Logs all SQL queries executed by the client +- `notices` : Logs database notices +- `results` : Logs the result of the queries + +```ts +{ + const client = new Client({ + ... + controls: { + // enable all logs + debug: true, + }, + }); + + const client = new Client({ + ... + controls: { + // only enable logging of SQL query statements + debug: { + queries: true, + }, + }, + }); +} +```