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

Full support 64 bit integers with BigInt #1501

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/macros.h
Expand Up @@ -23,6 +23,9 @@ inline bool OtherIsInt(Napi::Number source) {
}
}

#define JS_MAX_SAFE_INTEGER 9007199254740991
#define JS_MIN_SAFE_INTEGER -JS_MAX_SAFE_INTEGER

#define REQUIRE_ARGUMENTS(n) \
if (info.Length() < (n)) { \
Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \
Expand Down
29 changes: 27 additions & 2 deletions src/statement.cc
Expand Up @@ -204,6 +204,22 @@ template <class T> Values::Field*
else if (OtherInstanceOf(source.As<Object>(), "Date")) {
return new Values::Float(pos, source.ToNumber().DoubleValue());
}
#if NAPI_VERSION >= 6
else if (source.IsBigInt()) {
bool lossless;
auto ret = new Values::Integer(pos, source.As<Napi::BigInt>().Int64Value(&lossless));

if (!lossless) {
Napi::RangeError::New(
source.Env(),
"Value can't be losslessly converted to 64 bit integer.")
.ThrowAsJavaScriptException();
return NULL;
}

return ret;
}
#endif
else if (source.IsObject()) {
Napi::String napiVal = source.ToString();
// Check whether toString returned a value that is not undefined.
Expand Down Expand Up @@ -299,7 +315,7 @@ bool Statement::Bind(const Parameters & parameters) {

switch (field->type) {
case SQLITE_INTEGER: {
status = sqlite3_bind_int(_handle, pos,
status = sqlite3_bind_int64(_handle, pos,
((Values::Integer*)field)->value);
} break;
case SQLITE_FLOAT: {
Expand Down Expand Up @@ -810,7 +826,16 @@ Napi::Value Statement::RowToJS(Napi::Env env, Row* row) {

switch (field->type) {
case SQLITE_INTEGER: {
value = Napi::Number::New(env, ((Values::Integer*)field)->value);
auto field_value = ((Values::Integer*)field)->value;

#if NAPI_VERSION >= 6
if (field_value > JS_MAX_SAFE_INTEGER || field_value < JS_MIN_SAFE_INTEGER) {
value = Napi::BigInt::New(env, field_value);
} else
#endif
{
value = Napi::Number::New(env, field_value);
}
} break;
case SQLITE_FLOAT: {
value = Napi::Number::New(env, ((Values::Float*)field)->value);
Expand Down
39 changes: 38 additions & 1 deletion test/other_objects.test.js
Expand Up @@ -8,11 +8,12 @@ describe('data types', function() {
db.run("CREATE TABLE txt_table (txt TEXT)");
db.run("CREATE TABLE int_table (int INTEGER)");
db.run("CREATE TABLE flt_table (flt FLOAT)");
db.run("CREATE TABLE bigint_table (big BIGINT)");
db.wait(done);
});

beforeEach(function(done) {
db.exec('DELETE FROM txt_table; DELETE FROM int_table; DELETE FROM flt_table;', done);
db.exec('DELETE FROM txt_table; DELETE FROM int_table; DELETE FROM flt_table; DELETE FROM bigint_table;', done);
});

it('should serialize Date()', function(done) {
Expand Down Expand Up @@ -95,4 +96,40 @@ describe('data types', function() {
});
});

if (process.versions.napi >= '6') {
[
1n,
1337n,
8876343627091516928n,
-8876343627091516928n,
].forEach(function (bigint) {
it('should serialize BigInt ' + bigint, function (done) {
db.run("INSERT INTO bigint_table VALUES(?)", bigint, function(err) {
if (err) throw err;
db.get("SELECT big AS bigint FROM bigint_table", function (err, row) {
if (err) throw err
assert.equal(row.bigint, bigint);
done();
});
});
});
});
}

if (process.versions.napi >= '6') {
it('should fail to serialize larger numbers', function (done) {
const bigint = 0xffffffffffffffffffffn; // 80 bits
let error;

try {
db.run('INSERT INTO bigint_table VALUES(?)', bigint);
} catch (err) {
error = err;
} finally {
assert.notEqual(error, undefined);
done();
}
})
}

});