Skip to content

Conversation

@Divyanshu-s13
Copy link
Contributor

@Divyanshu-s13 Divyanshu-s13 commented Nov 18, 2025

What's Changed

Added a new decimal.ts module that provides high-level utilities for working with Decimal128 and Decimal256 values in JavaScript. These utilities make decimal handling more ergonomic by removing the need for low-level bit manipulation and aligning behavior with Arrow C++ semantics. The module is exported through the util namespace and integrates cleanly without introducing breaking changes.

Closes #81.

@Divyanshu-s13
Copy link
Contributor Author

Divyanshu-s13 commented Nov 18, 2025

@kou Fix #81: Improve ergonomics for the Decimal type in JavaScript bindings.

Copy link
Member

@domoritz domoritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pull request. This definitely needs tests.

Also, does this address #100 and #77 in some way?

- Comprehensive tests for isNegativeDecimal, negateDecimal
- Tests for toDecimalString and toDecimalNumber conversions
- Tests for fromDecimalString parsing with roundtrips
- Integration tests for negation and edge cases
@Divyanshu-s13
Copy link
Contributor Author

Divyanshu-s13 commented Nov 20, 2025

Thanks for the pull request. This definitely needs tests.

Also, does this address #100 and #77 in some way?

thanks for review!
I have added a test case for this.

This partially addresses Issues #77 and #100 by providing comprehensive utility functions for working with Decimal types in Apache Arrow JavaScript.

@kou kou changed the title Fix #81: Improve ergonomics for the Decimal type in JavaScript bindings fix: Improve ergonomics for the Decimal type Nov 22, 2025
@domoritz
Copy link
Member

Thanks for these utilities. I think we should try to use them in the default converters so that #77 gets fixed. Either you could do this here or we can do it in a follow up when you fixed the CI errors and we merged.

@Divyanshu-s13
Copy link
Contributor Author

Thanks for these utilities. I think we should try to use them in the default converters so that #77 gets fixed. Either you could do this here or we can do it in a follow up when you fixed the CI errors and we merged.

I have fixed CI error can you merge it.

@kou
Copy link
Member

kou commented Nov 25, 2025

Could you check lint failures?

https://github.com/apache/arrow-js/actions/runs/19644239168/job/56300291328?pr=341#step:5:8

/home/runner/work/arrow-js/arrow-js/src/util/decimal.ts
Error:    84:9  error  'n' is never reassigned. Use 'const' instead                 prefer-const
Error:    89:5  error  This `if` statement can be replaced by a ternary expression  unicorn/prefer-ternary
Error:   128:5  error  This `if` statement can be replaced by a ternary expression  unicorn/prefer-ternary

FYI: You can run CI on your fork by enabling GitHub Actions on your fork.

- Change 'let n' to 'const n' (prefer-const)
- Use ternary for magnitude assignment (unicorn/prefer-ternary)
- Use ternary for result composition (unicorn/prefer-ternary)
@Divyanshu-s13
Copy link
Contributor Author

Could you check lint failures?

https://github.com/apache/arrow-js/actions/runs/19644239168/job/56300291328?pr=341#step:5:8

/home/runner/work/arrow-js/arrow-js/src/util/decimal.ts
Error:    84:9  error  'n' is never reassigned. Use 'const' instead                 prefer-const
Error:    89:5  error  This `if` statement can be replaced by a ternary expression  unicorn/prefer-ternary
Error:   128:5  error  This `if` statement can be replaced by a ternary expression  unicorn/prefer-ternary

FYI: You can run CI on your fork by enabling GitHub Actions on your fork.

I have fix this can you merge it.

@Divyanshu-s13
Copy link
Contributor Author

@kou @domoritz I have fix all CI failure and all checks are passed please merge it.

}

// Calculate divisor as 10^scale
// Using a loop instead of BigInt exponentiation (**) for ES2015 compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we bump to something beyond es2015 for better code?

@ilyabo
Copy link

ilyabo commented Jan 13, 2026

It might be worth it to include Decimal256 support (as suggested by Coderabbit)

@Divyanshu-s13
Copy link
Contributor Author

@kou @domoritz please review it.

@domoritz
Copy link
Member

domoritz commented Feb 4, 2026

I started looking at this in November. Have you seen my question in #341 (comment)?

Copy link
Member

@domoritz domoritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making these utilities. I wonder, can we also use some of these utilities in other tests that already exist?

* ```
* @ignore
*/
export function toDecimalString(value: Uint32Array, scale: number): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you test this with Decimal256? I'm not 100% sure this method support it.

}

// Trim trailing zeros in fractional part
fracPart = fracPart.replace(/0+$/, '');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this mean that a scale of 5 would still return "0.0" rather than "0.00000"?

* ```
* @ignore
*/
export function fromDecimalString(str: string, scale: number): Uint32Array {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If toDecimalString supports Decimal256, shouldn't this support it as well?

const [wholePart = '0', fracPart = ''] = str.split('.');

// Pad or truncate fractional part to match scale
const adjustedFrac = (fracPart + '0'.repeat(scale)).slice(0, scale);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the input string has more fractional digits than scale, are they silently truncated without rounding?

};

// Detect sign via MSB of most-significant word
const isNegative = (value[3] & 0x80000000) !== 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not the same as isNegativeDecimal?

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 this pull request may close these issues.

[JS] Ergonomics for the Decimal type via the JavaScript bindings

4 participants