Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bigint codec #410

Closed
mixedCase opened this issue Jan 17, 2020 · 7 comments 路 Fixed by #417
Closed

Bigint codec #410

mixedCase opened this issue Jan 17, 2020 · 7 comments 路 Fixed by #417

Comments

@mixedCase
Copy link
Contributor

馃殌 Feature request

Current Behavior

No bigint codec.

Desired Behavior

Having a bigint codec available, like there's for other primitives (string, number, etc.).

Suggested Solution

Add a bigint codec to the library.

Who does this impact? Who is this for?

People who would like to implement codecs on top of bigint, or at least that's my case.

Describe alternatives you've considered

Using my own implementation.

Your environment

Software Version(s)
io-ts 2.0.0
fp-ts 2.0.5
TypeScript 3.5.3
Node 13.6.0
@gcanti
Copy link
Owner

gcanti commented Feb 5, 2020

Using my own implementation

@mixedCase could you please show your implementation?

@mixedCase
Copy link
Contributor Author

@gcanti I just tried to submit a pull request but it turns out there's a linting rule from tslint-eslint-rules (valid-typeof) which is copy-pasted from a really old version of ESLint and isn't aware of bigint.

With TSLint now being deprecated, is there anything WIP regarding this or should I try moving the project from TSLint to ESLint?

@gcanti
Copy link
Owner

gcanti commented Feb 5, 2020

@mixedCase if you are using typeof the codec you are defining is not a "proper" decoder I guess, i.e. it just validates the input (rather than, for example, decoding a bigint from a string). May I ask what's the use case for such a codec?

@mixedCase
Copy link
Contributor Author

@gcanti One is implementing codecs on top of bigint, such as BigIntFromString or BigIntFromNumber.

A more direct one is validating database input, the Postgres Node driver at least is discussing using bigint for database 64-bit integers: brianc/node-pg-types#78

@mlegenhausen
Copy link
Contributor

I would add it io-ts-types cause bigint are still hard to use in practice. There is currently no standardized way to serialize a bigint to JSON. Most of the approaches are flawed cause of the fact that bigint can be used for arbitrarily large integers. Simply converting them to string makes them unsortable.

For anyone interested to use them with pg I do the following

import * as t from 'io-ts'
import { either } from 'fp-ts/lib/Either'

// use this in environments that do not support bigint
export interface Int8Brand {
  readonly Int8: unique symbol
}
export type Int8 = t.Branded<string, Int8Brand>
export interface Int8C extends t.Type<Int8, string, unknown> {}
export const Int8: Int8C = t.brand(t.string, (s): s is Int8 => /^[0-9a-f]{16}$/.test(s), 'Int8')

// Use this in nodejs environments
export interface BigIntFromInt8C extends t.Type<bigint, Int8, unknown> {}

export const BigIntFromInt8: BigIntFromInt8C = new t.Type<bigint, Int8, unknown>(
  'BigIntFromInt8',
  (v): v is bigint => typeof v === 'bigint',
  (u, c) => either.chain(Int8.validate(u, c), v => t.success(BigInt(`0x${v}`))),
  v => {
    const buf = Buffer.allocUnsafe(8)
    buf.writeBigInt64BE(v)
    return buf.toString('hex') as any
  }
)

pg.types.setTypeParser(pg.types.builtins.INT8, value => BigIntFromInt8.encode(BigInt(value)))

Int8 can be used in any environment that can not handle bigint and it can be sorted and serialized to JSON.

@mixedCase
Copy link
Contributor Author

@mlegenhausen bigint is not a valid JSON type, so that's why it doesn't apply to JSON.

But bigints are a standard JS primitive and still can be used for other data serialization formats which do contain 64-bit integers, whether it is for RPC such as Protobuf, Cap'n'proto, database protocols, etc., or decoding file formats (first thing I found as an example, the Matroska multimedia container). All cases where io-ts would be useful.

As for the package to use, all other standard JS primitives are in io-ts, so it only makes sense to me that bigint belongs here as well. Codecs like BigIntFromString and BigIntFromNumber (which would build upon this) however do sound like they belong in io-ts-types.

@christianbradley
Copy link

Here's what the bigint codec should look like:

import { identity } from 'fp-ts/lib/function'
import { failure, success, Type } from 'io-ts'

export function isBigInt(u: unknown): u is bigint {
  return typeof u === 'bigint'
}

export const bigint = new Type<bigint, bigint, unknown>(
  'bigint',
  isBigInt,
  (i, c) => (isBigInt(i) ? success(i) : failure(i, c)),
  identity
)

Keeping with the other standard codecs, it should do nothing more than validate the core js type and encode using identity.

Anything else belongs in io-ts-types (ie: BigIntFromString)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants