Files
floci-ui/packages/api/src/adapter-azure/PostgresDataClient.ts
T
Zakaria 91ce11274d
CI / checks (pull_request) Successful in 25m47s
chore: show TheCloud instead of Floci in console text and messages
Labels, empty states, error messages and defaults the console shows now name
TheCloud or its runtimes. Identifiers that must match the emulator (FLOCI_*
settings, the X-Floci-CSRF header, emulator-returned host names) are unchanged.
2026-10-24 14:30:44 -04:00

63 lines
2.5 KiB
TypeScript

import {Client, types} from 'pg'
import type {QueryResult} from 'pg'
import type {SqlColumn, SqlQueryResult, SqlResultSet} from '../cloud-spi/types'
import type {SqlDataConnection, SqlDataClient} from './MssqlDataClient'
import {mapSqlDataError, type SqlDataPhase} from './sqlDataErrors'
import {normalizeSqlRow} from './sqlValues'
const MAX_ROWS_PER_RESULT_SET = 500
const TYPE_NAMES = new Map(
Object.entries(types.builtins)
.filter((entry): entry is [string, number] => typeof entry[1] === 'number')
.map(([name, oid]) => [oid, name.toLowerCase()]),
)
export class PostgresDataClient implements SqlDataClient {
async query(connection: SqlDataConnection, query: string): Promise<SqlQueryResult> {
const client = new Client({
host: connection.server,
port: connection.port,
database: connection.database,
user: connection.username,
password: connection.password,
ssl: connection.tlsMode === 'disable'
? false
: {rejectUnauthorized: connection.tlsMode === 'verify'},
connectionTimeoutMillis: 10_000,
query_timeout: 30_000,
statement_timeout: 30_000,
application_name: 'TheCloud',
})
const startedAt = performance.now()
let phase: SqlDataPhase = 'connect'
try {
await client.connect()
phase = 'query'
const rawResult = await client.query<Record<string, unknown>>(query)
phase = 'result'
const results = (Array.isArray(rawResult) ? rawResult : [rawResult]) as QueryResult<Record<string, unknown>>[]
return {
resultSets: results.filter((result) => result.fields.length > 0).map(toResultSet),
rowsAffected: results.map((result) => result.rowCount ?? 0),
durationMs: Math.round(performance.now() - startedAt),
}
} catch (error) {
throw mapSqlDataError('PostgreSQL', phase, error)
} finally {
await client.end().catch(() => undefined)
}
}
}
function toResultSet(result: QueryResult<Record<string, unknown>>): SqlResultSet {
return {
columns: result.fields.map((field): SqlColumn => ({
name: field.name,
type: TYPE_NAMES.get(field.dataTypeID) ?? `oid:${field.dataTypeID}`,
})),
rows: result.rows.slice(0, MAX_ROWS_PER_RESULT_SET).map(normalizeSqlRow),
truncated: result.rows.length > MAX_ROWS_PER_RESULT_SET,
}
}