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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Javascript BigInt support in Node 10+ #10468

Open
gabegorelick opened this issue Feb 22, 2019 · 10 comments
Open

Javascript BigInt support in Node 10+ #10468

gabegorelick opened this issue Feb 22, 2019 · 10 comments
Assignees
Labels
P1: important For issues and PRs. status: understood For issues. Applied when the issue is understood / reproducible. type: feature For issues and PRs. For new features. Never breaking changes.

Comments

@gabegorelick
Copy link
Contributor

What are you doing?

That integers greater than Number.MAX_SAFE_INTEGER need to be represented as Javascript strings is an issue that confuses a lot of people. Now that Node 10+ has a native BigInt type, it may be time to reassess Sequelize's approach.

It would be nice if Sequelize deserialized arbitrary precision integer types as JS BigInts, perhaps falling back to a polyfill like https://www.npmjs.com/package/big-integer.

const User = sequelize.define('User', {
  userID: {
    type: Sequelize.BIGINT
  }
});

User.findOne({where: {userID: 1n}})
  .then(user => expect(user.userID).to.equal(1n));

This would be a breaking change, so an option to opt in to this behavior is probably warranted.

What do you expect to happen?

userID should equal 1n.

What is actually happening?

userID equals "1";

Dialect: any
Dialect version: any
Database version: any
Sequelize version: any
Tested with latest release: No (If yes, specify that version)

@gabegorelick
Copy link
Contributor Author

See brianc/node-pg-types#78 for discussion about this behavior upstream in node-pg. Arguably, Sequelize should just inherit the defaults of the underlying driver.

@gabegorelick
Copy link
Contributor Author

BigInt and other non-Number number types are now passed through as of #10492. But there's still room for Sequelize to do more with native support.

@stale
Copy link

stale bot commented May 31, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If this is still an issue, just leave a comment 🙂

@stale stale bot added the stale label May 31, 2019
@stale stale bot closed this as completed Jun 7, 2019
@papb
Copy link
Member

papb commented Oct 9, 2019

I like this idea, reopening

@papb papb reopened this Oct 9, 2019
@stale stale bot removed the stale label Oct 9, 2019
@papb papb added status: understood For issues. Applied when the issue is understood / reproducible. type: feature For issues and PRs. For new features. Never breaking changes. labels Oct 9, 2019
@gabegorelick
Copy link
Contributor Author

Node 8 reaches end-of-life on December 31, 2019. So any support probably shouldn't worry about polyfills at this point.

@adrigardi90
Copy link

I'm also having the same behaviour. Easy to handle but it would be nice to get more native support

@bradennapier
Copy link

Seems like its about time we solve this :-)

@dileepfrog
Copy link

I have been working around this by implementing a custom typeCast, but it doesn't work in all cases and baked-in support would be very welcome.

@bradennapier
Copy link

bradennapier commented Sep 9, 2020

Given TypeScript, some casting due to bad typing from Sequelize, and some hackery -- this appears to implement BigInt support although not ideal. It expected setting supportsBigNumber and bigNumbersAsStrings in dialect options, although may not be strictly necessary.

import { Utils, DataType } from 'sequelize';
import { Sequelize } from 'sequelize-typescript';

// must use the auto binding method due to how sequelize handles these values internally
// invalid types for this value
// eslint-disable-next-line @typescript-eslint/no-explicit-any
class BIGINT_NATIVE_CLASS extends (Sequelize as any).DataTypes.ABSTRACT {
  key = 'BIGINT';

  static key = 'BIGINT';

  toSql = () => 'BIGINT(20) UNSIGNED';

  validate = (value: unknown) => {
    return typeof value === 'bigint';
  };

  _stringify = (value: bigint) => String(value);

  _sanitize = (value: string) => BigInt(value);

  _bindParam = (value: bigint | number | string, options: object) => {
    return options.bindParam(BigInt(value));
  };
}

// Mandatory: add the new type to DataTypes. Optionally wrap it on `Utils.classToInvokable` to
// be able to use this datatype directly without having to call `new` on it.
const BIGINT_NATIVE = (Utils.classToInvokable(
  BIGINT_NATIVE_CLASS,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
) as any) as DataType;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(Sequelize as any).DataTypes.BIGINT_NATIVE = BIGINT_NATIVE;

export { BIGINT_NATIVE };

Should be easy enough to convert to js as well...

I believe with TypeScript they handle class properties differently than js does so the setting via _sanitize = () => {} is required so that the properties are bound at the right time. Otherwise they are not called by Sequelize.

@jobelenus
Copy link

jobelenus commented Jan 7, 2021

Note: I am on Node 12 w/ Sequelize 6.3.5 and am seeing the INTEGER sequelize type (w/ PG drivers) return Strings as well. Edit: the model definition is iNTEGER, but the postgres table definition is bigint so I assume sequelize is doing the smart thing and representing it as a bigint, thus a string.

@papb papb added the P1: important For issues and PRs. label Apr 7, 2021
@ephys ephys self-assigned this Oct 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P1: important For issues and PRs. status: understood For issues. Applied when the issue is understood / reproducible. type: feature For issues and PRs. For new features. Never breaking changes.
Projects
Status: v8
Development

No branches or pull requests

7 participants