UNPKG

@prisma/ppg

Version:

Lightweight client for Prisma Postgres

140 lines (136 loc) 3.72 kB
// src/url.ts var ConnectionStringError = class extends Error { constructor(message) { super(message); this.name = "ConnectionStringError"; } }; function parsePpgConnectionString(connectionString) { const url = new URL(connectionString); if (url.protocol !== "prisma+postgres:") { throw new ConnectionStringError("Invalid protocol"); } const apiKey = url.searchParams.get("api_key"); if (!apiKey) { throw new ConnectionStringError("Missing API key"); } let baseUrl; if (isLocalhost(url.hostname)) { throw new ConnectionStringError("Local Prisma Postgres is not supported"); } return { apiKey }; } function isLocalhost(hostname) { return ["localhost", "127.0.0.1", "[::1]"].includes(hostname); } // src/client.ts var RequestError = class extends Error { constructor(message, httpCode) { if (httpCode !== void 0) { super(`HTTP ${httpCode}: ${message}`); } else { super(message); } this.name = "RequestError"; } }; var SqlError = class extends RequestError { error; severityLocal; severity; code; position; file; line; routine; constructor(pgError) { super(pgError.error); this.error = pgError.error; this.severityLocal = pgError.severity_local; this.severity = pgError.severity; this.code = pgError.code; this.position = pgError.position; this.file = pgError.file; this.line = pgError.line; this.routine = pgError.routine; } }; var API_ENDPOINT = "https://migrations.prisma-data.net/db/exec"; var Client = class { #headers; constructor(options) { const { apiKey } = parsePpgConnectionString(options.connectionString); this.#headers = new Headers({ Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", Accept: "application/json" }); } /** * Executes a query against the Prisma Postgres database. */ async query(query, parameters) { const response = await fetch(API_ENDPOINT, { method: "POST", headers: this.#headers, body: JSON.stringify({ query, parameters }) }); if (response.ok) { return await response.json(); } const errorText = await response.text(); let errorJson; try { errorJson = JSON.parse(errorText); } catch { throw new RequestError(errorText, response.status); } if (typeof errorJson === "object" && errorJson !== null && "error" in errorJson && "severity_local" in errorJson && "severity" in errorJson && "code" in errorJson && "file" in errorJson && "line" in errorJson && "routine" in errorJson) { throw new SqlError(errorJson); } throw new RequestError(errorText, response.status); } }; // src/sql.ts function sqlFactory(client, deserialize) { const query = async (query2, params) => { const { columns, rows } = await client.query(query2, params); return rows.map( (row) => Object.fromEntries( columns.map((column, i) => [ column.name, deserialize(row[i], column.oid) ]) ) ); }; const sql = async (strings, ...values) => { const queryString = strings.reduce( (acc, str, i) => acc + str + (i < values.length ? `$${i + 1}` : ""), "" ); return query(queryString, values); }; sql.query = query; Object.defineProperty(sql, "end", { value: () => Promise.resolve(), enumerable: false }); return sql; } // src/index.ts function ppg(url, deserialize = (value) => value) { const client = new Client({ connectionString: url }); return sqlFactory(client, deserialize); } var index_default = ppg; export { Client, ConnectionStringError, RequestError, SqlError, index_default as default, ppg };