Skip to content
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.17.1
21.0.0
9 changes: 8 additions & 1 deletion apps/nest-server/src/app/app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ export class AppService {
const results = await client.query(
`select returnflag, linestatus, sum(quantity) as sum_qty, sum(extendedprice) as sum_base_price, sum(extendedprice * (1 - discount)) as sum_disc_price, sum(extendedprice * (1 - discount) * (1 + tax)) as sum_charge, avg(quantity) as avg_qty, avg(extendedprice) as avg_price, avg(discount) as avg_disc, count(*) as count_order from lineitem where shipdate <= date '1998-12-01' group by returnflag, linestatus order by returnflag, linestatus`,
)
return { columns: results.columns, rows: results.data }
return {
columns: results.columns,
rows: JSON.stringify(results.data, (key, value) => {
if (typeof value !== 'bigint') return value

return value.toString()
}),
}
} catch (error) {
return (error as PrestoError).message
}
Expand Down
10 changes: 9 additions & 1 deletion presto-client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
QueryInfo,
Table,
} from './types'
import { parseWithBigInts } from './utils'

export class PrestoClient {
private baseUrl: string
Expand Down Expand Up @@ -270,7 +271,7 @@ export class PrestoClient {
throw new Error(`Query failed: ${JSON.stringify(await response.text())}`)
}

const prestoResponse = (await response.json()) as PrestoResponse
const prestoResponse = (await this.prestoConversionToJSON({ response })) as PrestoResponse
if (!prestoResponse) {
throw new Error(`Query failed with an empty response from the server.`)
}
Expand Down Expand Up @@ -334,6 +335,13 @@ export class PrestoClient {
method,
})
}

private async prestoConversionToJSON({ response }: { response: Response }): Promise<unknown> {
const text = await response.text()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore JSON.parse with a 3 argument reviver is a stage 3 proposal with some support, allow it here.
return JSON.parse(text, parseWithBigInts)
}
}

export default PrestoClient
29 changes: 29 additions & 0 deletions presto-client/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Parses a JSON including bigger numbers into BigInts
* This function checks if JSON.parse reviver callback has a context parameter
* and falls back onto the default parsing if not.
* See also:
* - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#browser_compatibility
* - https://github.com/tc39/proposal-json-parse-with-source
* @param _ Key
* @param value Parsed value
* @param context Context with source text
* @returns Parsed object with BigInts where required
*/
export function parseWithBigInts(_: string, value: unknown, context: { source: string }) {
if (!context) return value // Context is not available, fallback to default parse
const { source } = context
if (!source) return value // Source is not available, fallback to default parse

// Ignore non-numbers
if (typeof value !== 'number') return value

// If not an integer, use the value
// TODO: Check if Presto can return floats that could also lose precision
if (!Number.isInteger(value)) return value

// If number is a safe integer, we can use it
if (Number.isSafeInteger(value)) return value

return BigInt(source)
}
Loading