Skip to content

Commit

Permalink
Add JSDocs (#451)
Browse files Browse the repository at this point in the history
* chore : add JSDocs

* chore: fix port type in client config

* chore: fix client config type

* chore: remove import statments from JSDocs examples

* chore: fix JSDocs examples code

* chore: format deno files

* chore: fix grammar in comment
  • Loading branch information
bombillazo committed Feb 6, 2024
1 parent ac33655 commit e158263
Show file tree
Hide file tree
Showing 9 changed files with 430 additions and 272 deletions.
186 changes: 101 additions & 85 deletions client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import {
import { Transaction, type TransactionOptions } from "./query/transaction.ts";
import { isTemplateString } from "./utils/utils.ts";

/**
* The Session representing the current state of the connection
*/
export interface Session {
/**
* This is the code for the transaction currently locking the connection.
Expand All @@ -43,19 +46,31 @@ export interface Session {
transport: "tcp" | "socket" | undefined;
}

/**
* An abstract class used to define common database client properties and methods
*/
export abstract class QueryClient {
#connection: Connection;
#terminated = false;
#transaction: string | null = null;

/**
* Create a new query client
*/
constructor(connection: Connection) {
this.#connection = connection;
}

/**
* Indicates if the client is currently connected to the database
*/
get connected(): boolean {
return this.#connection.connected;
}

/**
* The current session metadata
*/
get session(): Session {
return {
current_transaction: this.#transaction,
Expand All @@ -71,6 +86,9 @@ export abstract class QueryClient {
}
}

/**
* Close the connection to the database
*/
protected async closeConnection() {
if (this.connected) {
await this.#connection.end();
Expand All @@ -87,8 +105,7 @@ export abstract class QueryClient {
* In order to create a transaction, use the `createTransaction` method in your client as follows:
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = client.createTransaction("my_transaction_name");
*
Expand All @@ -101,8 +118,7 @@ export abstract class QueryClient {
* the client without applying any of the changes that took place inside it
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = client.createTransaction("transaction");
*
Expand All @@ -119,8 +135,7 @@ export abstract class QueryClient {
* the transaction
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = client.createTransaction("transaction");
*
Expand All @@ -145,17 +160,15 @@ export abstract class QueryClient {
* - Repeatable read: This isolates the transaction in a way that any external changes to the data we are reading
* won't be visible inside the transaction until it has finished
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = await client.createTransaction("my_transaction", { isolation_level: "repeatable_read" });
* ```
*
* - Serializable: This isolation level prevents the current transaction from making persistent changes
* if the data they were reading at the beginning of the transaction has been modified (recommended)
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = await client.createTransaction("my_transaction", { isolation_level: "serializable" });
* ```
Expand All @@ -168,8 +181,7 @@ export abstract class QueryClient {
* is to in conjuction with the repeatable read isolation, ensuring the data you are reading does not change
* during the transaction, specially useful for data extraction
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* const transaction = await client.createTransaction("my_transaction", { read_only: true });
* ```
Expand All @@ -180,8 +192,7 @@ export abstract class QueryClient {
* you can do the following:
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client_1 = new Client();
* const client_2 = new Client();
* const transaction_1 = client_1.createTransaction("transaction_1");
Expand Down Expand Up @@ -246,47 +257,52 @@ export abstract class QueryClient {
}

/**
* This method allows executed queries to be retrieved as array entries.
* It supports a generic interface in order to type the entries retrieved by the query
* Execute queries and retrieve the data as array entries. It supports a generic in order to type the entries retrieved by the query
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
*
* const {rows} = await my_client.queryArray(
* const { rows: rows1 } = await my_client.queryArray(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Array<unknown[]>
* ```
*
* You can pass type arguments to the query in order to hint TypeScript what the return value will be
* ```ts
* import { Client } from "./client.ts";
*
* const my_client = new Client();
* const { rows } = await my_client.queryArray<[number, string]>(
* const { rows: rows2 } = await my_client.queryArray<[number, string]>(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Array<[number, string]>
* ```
*/
async queryArray<T extends Array<unknown>>(
query: string,
args?: QueryArguments,
): Promise<QueryArrayResult<T>>;
/**
* Use the configuration object for more advance options to execute the query
*
* It also allows you to execute prepared statements with template strings
* ```ts
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
* const { rows } = await my_client.queryArray<[number, string]>({
* text: "SELECT ID, NAME FROM CLIENTS",
* name: "select_clients",
* }); // Array<[number, string]>
* ```
*/
async queryArray<T extends Array<unknown>>(
config: QueryOptions,
): Promise<QueryArrayResult<T>>;
/**
* Execute prepared statements with template strings
*
* ```ts
* import { Client } from "./client.ts";
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
*
* const id = 12;
* // Array<[number, string]>
* const {rows} = await my_client.queryArray<[number, string]>`SELECT ID, NAME FROM CLIENTS WHERE ID = ${id}`;
* ```
*/
async queryArray<T extends Array<unknown>>(
query: string,
args?: QueryArguments,
): Promise<QueryArrayResult<T>>;
async queryArray<T extends Array<unknown>>(
config: QueryOptions,
): Promise<QueryArrayResult<T>>;
async queryArray<T extends Array<unknown>>(
strings: TemplateStringsArray,
...args: unknown[]
Expand Down Expand Up @@ -324,71 +340,58 @@ export abstract class QueryClient {
}

/**
* This method allows executed queries to be retrieved as object entries.
* It supports a generic interface in order to type the entries retrieved by the query
* Executed queries and retrieve the data as object entries. It supports a generic in order to type the entries retrieved by the query
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
*
* {
* const { rows } = await my_client.queryObject(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Record<string, unknown>
* }
* const { rows: rows1 } = await my_client.queryObject(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Record<string, unknown>
*
* {
* const { rows } = await my_client.queryObject<{id: number, name: string}>(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Array<{id: number, name: string}>
* }
* const { rows: rows2 } = await my_client.queryObject<{id: number, name: string}>(
* "SELECT ID, NAME FROM CLIENTS"
* ); // Array<{id: number, name: string}>
* ```
*
* You can also map the expected results to object fields using the configuration interface.
* This will be assigned in the order they were provided
*/
async queryObject<T>(
query: string,
args?: QueryArguments,
): Promise<QueryObjectResult<T>>;
/**
* Use the configuration object for more advance options to execute the query
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
*
* {
* const {rows} = await my_client.queryObject(
* "SELECT ID, NAME FROM CLIENTS"
* );
*
* console.log(rows); // [{id: 78, name: "Frank"}, {id: 15, name: "Sarah"}]
* }
*
* {
* const {rows} = await my_client.queryObject({
* text: "SELECT ID, NAME FROM CLIENTS",
* fields: ["personal_id", "complete_name"],
* });
*
* console.log(rows); // [{personal_id: 78, complete_name: "Frank"}, {personal_id: 15, complete_name: "Sarah"}]
* }
* const { rows: rows1 } = await my_client.queryObject(
* "SELECT ID, NAME FROM CLIENTS"
* );
* console.log(rows1); // [{id: 78, name: "Frank"}, {id: 15, name: "Sarah"}]
*
* const { rows: rows2 } = await my_client.queryObject({
* text: "SELECT ID, NAME FROM CLIENTS",
* fields: ["personal_id", "complete_name"],
* });
* console.log(rows2); // [{personal_id: 78, complete_name: "Frank"}, {personal_id: 15, complete_name: "Sarah"}]
* ```
*
* It also allows you to execute prepared statements with template strings
*/
async queryObject<T>(
config: QueryObjectOptions,
): Promise<QueryObjectResult<T>>;
/**
* Execute prepared statements with template strings
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const my_client = new Client();
* const id = 12;
* // Array<{id: number, name: string}>
* const { rows } = await my_client.queryObject<{id: number, name: string}>`SELECT ID, NAME FROM CLIENTS WHERE ID = ${id}`;
* ```
*/
async queryObject<T>(
query: string,
args?: QueryArguments,
): Promise<QueryObjectResult<T>>;
async queryObject<T>(
config: QueryObjectOptions,
): Promise<QueryObjectResult<T>>;
async queryObject<T>(
query: TemplateStringsArray,
...args: unknown[]
Expand Down Expand Up @@ -431,6 +434,9 @@ export abstract class QueryClient {
return await this.#executeQuery<T>(query);
}

/**
* Resets the transaction session metadata
*/
protected resetSessionMetadata() {
this.#transaction = null;
}
Expand All @@ -441,8 +447,7 @@ export abstract class QueryClient {
* statements asynchronously
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client = new Client();
* await client.connect();
* await client.queryArray`UPDATE MY_TABLE SET MY_FIELD = 0`;
Expand All @@ -453,8 +458,7 @@ export abstract class QueryClient {
* for concurrency capabilities check out connection pools
*
* ```ts
* import { Client } from "./client.ts";
*
* import { Client } from "https://deno.land/x/postgres/mod.ts";
* const client_1 = new Client();
* await client_1.connect();
* // Even if operations are not awaited, they will be executed in the order they were
Expand All @@ -472,6 +476,9 @@ export abstract class QueryClient {
* ```
*/
export class Client extends QueryClient {
/**
* Create a new client
*/
constructor(config?: ClientOptions | ConnectionString) {
super(
new Connection(createParams(config), async () => {
Expand All @@ -481,9 +488,15 @@ export class Client extends QueryClient {
}
}

/**
* A client used specifically by a connection pool
*/
export class PoolClient extends QueryClient {
#release: () => void;

/**
* Create a new Client used by the pool
*/
constructor(config: ClientConfiguration, releaseCallback: () => void) {
super(
new Connection(config, async () => {
Expand All @@ -493,6 +506,9 @@ export class PoolClient extends QueryClient {
this.#release = releaseCallback;
}

/**
* Releases the client back to the pool
*/
release() {
this.#release();

Expand Down
Loading

2 comments on commit e158263

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No typecheck tests failure

This error was most likely caused by incorrect type stripping from the SWC crate

Please report the following failure to https://github.com/denoland/deno with a reproduction of the current commit

Failure log

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No typecheck tests failure

This error was most likely caused by incorrect type stripping from the SWC crate

Please report the following failure to https://github.com/denoland/deno with a reproduction of the current commit

Failure log

Please sign in to comment.