electric-sql / electric-sql/pglite

PgliteWorker: Failed to execute 'postMessage' on Number(value) // and BigDecimal(value)

Open
#755 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
TypeScript
Stars
16k
Forks
442
Avg merge
20h 19m
Merged PRs (30d)
7

Description

```
Uncaught (in promise) DataCloneError: Failed to execute 'postMessage' on 'Worker': (value) => {
return Number(value);
} could not be cloned.
at F.K (index.ts:160:26)
at async F.create (index.ts:281:3)
```

I am using PGliteWorker and am trying to parse Numerics into Number. I have a class called BigDecimal that I would prefer to use (added below). Whenever I try to use either of them, I get an error as above.

These are the relevant issues I saw, but don't see a fix in them: https://github.com/electric-sql/pglite/issues?q=postMessage.

> Main thread
```
import PGWorker from "components/pg-lite/pglite-worker?worker";

void PGliteWorker.create(
new PGWorker({
name: "pglite-worker",
}),
{
parsers: {
[types.NUMERIC]: (value) => {
// console.log("Parsing NUMERIC value:", value);
return Number(value);
},
},
extensions: {
live,
vector,
electric: electricSync(),
},
},
)
```

> Worker
```
import { PGlite, PGliteInterfaceExtensions, types } from "@electric-sql/pglite";
import { electricSync } from "@electric-sql/pglite-sync";
import { live } from "@electric-sql/pglite/live";
import { OpfsAhpFS } from "@electric-sql/pglite/opfs-ahp";
import { vector } from "@electric-sql/pglite/vector";
import { PGliteWorker, worker } from "@electric-sql/pglite/worker";

export type CustomPGlite = PGliteWorker &
PGliteInterfaceExtensions<{
live: typeof live;
vector: typeof vector;
electric: ReturnType;
}>;

void worker({
async init() {
// Create and return a PGlite instance
const pg = await PGlite.create({
fs: new OpfsAhpFS("pglite-db", {}),
extensions: {
live,
vector,
electric: electricSync(),
},
});

return pg;
},
});
```

> BigDecimal

I tried making `#n` not private like `n` but the error remained.
```
export class BigDecimal {
// Configuration: private constants
private static readonly DECIMALS: number = 18; // Number of decimals on all instances
private static readonly ROUNDED: boolean = true; // Numbers are truncated (false) or rounded (true)
private static readonly SHIFT: bigint = 10n ** BigInt(BigDecimal.DECIMALS); // Derived constant
private static readonly fromBigInt: unique symbol = Symbol(); // Secret to allow construction with given #n value

public static get ZERO(): BigDecimal {
return new BigDecimal(0);
}

#n: bigint; // the BigInt that holds the BigDecimal's value multiplied by SHIFT

constructor(
value: string | number | BigDecimal | bigint,
convert?: typeof BigDecimal.fromBigInt,
) {
if (value instanceof BigDecimal) {
this.#n = value.#n;
return;
}
if (convert === BigDecimal.fromBigInt) {
this.#n = BigInt(value);
return;
}

const str = String(value);
const [ints, decis = ""] = str.split(".");
const padded = decis
.padEnd(BigDecimal.DECIMALS, "0")
.slice(0, BigDecimal.DECIMALS);
const base = BigInt(ints + padded);
const roundIncrement =
// @ts-expect-error
BigDecimal.ROUNDED && decis[BigDecimal.DECIMALS] >= "5" ? 1n : 0n;

this.#n = base + roundIncrement;
}

add(num: string | number | BigDecimal): BigDecimal {
const other = new BigDecimal(num);
const sum = this.#n + other.#n;
return new BigDecimal(sum, BigDecimal.fromBigInt);
}

subtract(num: string | number | BigDecimal): BigDecimal {
const other = new BigDecimal(num);
const diff = this.#n - other.#n;
return new BigDecimal(diff, BigDecimal.fromBigInt);
}

private static divRound(dividend: bigint, divisor: bigint): BigDecimal {
const quotient = dividend / divisor;
const remainder = dividend % divisor;
const shouldRound = BigDecimal.ROUNDED && remainder * 2n >= divisor;
return new BigDecimal(
quotient + (shouldRound ? 1n : 0n),
BigDecimal.fromBigInt,
);
}

multiply(num: string | number | BigDecimal): BigDecimal {
const other = new BigDecimal(num);
const product = this.#n * other.#n;
return BigDecimal.divRound(product, BigDecimal.SHIFT);
}

divide(num: string | number | BigDecimal): BigDecimal {
const other = new BigDecimal(num);
const scaled = this.#n * BigDecimal.SHIFT;
return BigDecimal.divRound(scaled, other.#n);
}

toString(): string {
const negative = this.#n < 0n;
let s = this.#n
.toString()
.replace("-", "")
.padStart(BigDecimal.DECIMALS + 1, "0");
s = s
.slice(0, -BigDecimal.DECIMALS)
.concat(".")
.concat(s.slice(-BigDecimal.DECIMALS))
.replace(/(\.0*|0+)$/, "");
return negative ? "-" + s : s;
}

toNumber(): number {
return Number(this.toString());
}
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.