@worker-tools/deno-kv-storage
Version:
An implementation of the StorageArea (1,2,3) interface for Deno with an extensible system for supporting various database backends.
197 lines • 8.86 kB
JavaScript
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _Pool_instances, _Pool_available_connections, _Pool_connection_params, _Pool_ended, _Pool_lazy, _Pool_ready, _Pool_size, _Pool_initialize;
import { PoolClient } from "./client.js";
import { createParams, } from "./connection/connection_params.js";
import { DeferredAccessStack } from "./utils/deferred.js";
/**
* Connection pools are a powerful resource to execute parallel queries and
* save up time in connection initialization. It is highly recommended that all
* applications that require concurrent access use a pool to communicate
* with their PostgreSQL database
*
* ```ts
* import { Pool } from "./pool.ts";
*
* const pool = new Pool({
* database: "database",
* hostname: "hostname",
* password: "password",
* port: 5432,
* user: "user",
* }, 10); // Creates a pool with 10 available connections
*
* const client = await pool.connect();
* await client.queryArray`SELECT 1`;
* client.release();
* ```
*
* You can also opt to not initialize all your connections at once by passing the `lazy`
* option when instantiating your pool, this is useful to reduce startup time. In
* addition to this, the pool won't start the connection unless there isn't any already
* available connections in the pool
*
* ```ts
* import { Pool } from "./pool.ts";
*
* // Creates a pool with 10 max available connections
* // Connection with the database won't be established until the user requires it
* const pool = new Pool({}, 10, true);
*
* // Connection is created here, will be available from now on
* const client_1 = await pool.connect();
* await client_1.queryArray`SELECT 1`;
* await client_1.release();
*
* // Same connection as before, will be reused instead of starting a new one
* const client_2 = await pool.connect();
* await client_2.queryArray`SELECT 1`;
*
* // New connection, since previous one is still in use
* // There will be two open connections available from now on
* const client_3 = await pool.connect();
* await client_2.release();
* await client_3.release();
* ```
*/
export class Pool {
constructor(connection_params, size, lazy = false) {
_Pool_instances.add(this);
_Pool_available_connections.set(this, void 0);
_Pool_connection_params.set(this, void 0);
_Pool_ended.set(this, false);
_Pool_lazy.set(this, void 0);
// TODO
// Initialization should probably have a timeout
_Pool_ready.set(this, void 0);
_Pool_size.set(this, void 0);
__classPrivateFieldSet(this, _Pool_connection_params, createParams(connection_params), "f");
__classPrivateFieldSet(this, _Pool_lazy, lazy, "f");
__classPrivateFieldSet(this, _Pool_size, size, "f");
// This must ALWAYS be called the last
__classPrivateFieldSet(this, _Pool_ready, __classPrivateFieldGet(this, _Pool_instances, "m", _Pool_initialize).call(this), "f");
}
/**
* The number of open connections available for use
*
* Lazily initialized pools won't have any open connections by default
*/
get available() {
if (!__classPrivateFieldGet(this, _Pool_available_connections, "f")) {
return 0;
}
return __classPrivateFieldGet(this, _Pool_available_connections, "f").available;
}
/**
* The number of total connections open in the pool
*
* Both available and in use connections will be counted
*/
get size() {
if (!__classPrivateFieldGet(this, _Pool_available_connections, "f")) {
return 0;
}
return __classPrivateFieldGet(this, _Pool_available_connections, "f").size;
}
// TODO
// Rename to getClient or similar
// The connect method should initialize the connections instead of doing it
// in the constructor
/**
* This will return a new client from the available connections in
* the pool
*
* In the case of lazy initialized pools, a new connection will be established
* with the database if no other connections are available
*
* ```ts
* import { Pool } from "./pool.ts";
*
* const pool = new Pool({}, 10);
* const client = await pool.connect();
* await client.queryArray`UPDATE MY_TABLE SET X = 1`;
* client.release();
* ```
*/
async connect() {
// Reinitialize pool if it has been terminated
if (__classPrivateFieldGet(this, _Pool_ended, "f")) {
__classPrivateFieldSet(this, _Pool_ready, __classPrivateFieldGet(this, _Pool_instances, "m", _Pool_initialize).call(this), "f");
}
await __classPrivateFieldGet(this, _Pool_ready, "f");
return __classPrivateFieldGet(this, _Pool_available_connections, "f").pop();
}
/**
* This will close all open connections and set a terminated status in the pool
*
* ```ts
* import { Pool } from "./pool.ts";
*
* const pool = new Pool({}, 10);
*
* await pool.end();
* console.assert(pool.available === 0, "There are connections available after ending the pool");
* await pool.end(); // An exception will be thrown, pool doesn't have any connections to close
* ```
*
* However, a terminated pool can be reused by using the "connect" method, which
* will reinitialize the connections according to the original configuration of the pool
*
* ```ts
* import { Pool } from "./pool.ts";
*
* const pool = new Pool({}, 10);
* await pool.end();
* const client = await pool.connect();
* await client.queryArray`SELECT 1`; // Works!
* await client.release();
* ```
*/
async end() {
if (__classPrivateFieldGet(this, _Pool_ended, "f")) {
throw new Error("Pool connections have already been terminated");
}
await __classPrivateFieldGet(this, _Pool_ready, "f");
while (this.available > 0) {
const client = await __classPrivateFieldGet(this, _Pool_available_connections, "f").pop();
await client.end();
}
__classPrivateFieldSet(this, _Pool_available_connections, undefined, "f");
__classPrivateFieldSet(this, _Pool_ended, true, "f");
}
async initialized() {
if (!__classPrivateFieldGet(this, _Pool_available_connections, "f")) {
return 0;
}
return await __classPrivateFieldGet(this, _Pool_available_connections, "f").initialized();
}
}
_Pool_available_connections = new WeakMap(), _Pool_connection_params = new WeakMap(), _Pool_ended = new WeakMap(), _Pool_lazy = new WeakMap(), _Pool_ready = new WeakMap(), _Pool_size = new WeakMap(), _Pool_instances = new WeakSet(), _Pool_initialize =
/**
* Initialization will create all pool clients instances by default
*
* If the pool is lazily initialized, the clients will connect when they
* are requested by the user, otherwise they will all connect on initialization
*/
async function _Pool_initialize() {
const initialized = __classPrivateFieldGet(this, _Pool_lazy, "f") ? 0 : __classPrivateFieldGet(this, _Pool_size, "f");
const clients = Array.from({ length: __classPrivateFieldGet(this, _Pool_size, "f") }, async (_e, index) => {
const client = new PoolClient(__classPrivateFieldGet(this, _Pool_connection_params, "f"), () => __classPrivateFieldGet(this, _Pool_available_connections, "f").push(client));
if (index < initialized) {
await client.connect();
}
return client;
});
__classPrivateFieldSet(this, _Pool_available_connections, new DeferredAccessStack(await Promise.all(clients), (client) => client.connect(), (client) => client.connected), "f");
__classPrivateFieldSet(this, _Pool_ended, false, "f");
};
//# sourceMappingURL=pool.js.map