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

upgrade ints and floats in arrays with mixed sizes #138

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions json-to-go.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty
continue
}

// if variable was first detected as int (7) and a second time as float64 (3.14)
// then we want to select float64, not int. Similar for int64 and float64.
if(areSameType(currentValue, 1))
allFields[keyname].value = findBestValueForNumberType(existingValue, currentValue);

if (areObjects(existingValue, currentValue)) {
const comparisonResult = compareObjectKeys(
Object.keys(currentValue),
Expand Down Expand Up @@ -389,6 +394,50 @@ function jsonToGo(json, typename, flatten = true, example = false, allOmitempty
}
}

// change the value to expand ints and floats to their larger equivalent
function findBestValueForNumberType(existingValue, newValue) {
if (!areSameType(newValue, 1)) {
console.error(`Error: currentValue ${newValue} is not a number`)
return null // falls back to goType "any"
}

const newGoType = goType(newValue)
const existingGoType = goType(existingValue)

if (newGoType === existingGoType)
return existingValue

// always upgrade float64
if (newGoType === "float64")
return newValue
if (existingGoType === "float64")
return existingValue

// it's too complex to distinguish int types and float32, so we force-upgrade to float64
// if anyone has a better suggestion, PRs are welcome!
if (newGoType.includes("float") && existingGoType.includes("int"))
return Number.MAX_VALUE
if (newGoType.includes("int") && existingGoType.includes("float"))
return Number.MAX_VALUE

if (newGoType.includes("int") && existingGoType.includes("int")) {
const existingValueAbs = Math.abs(existingValue);
const newValueAbs = Math.abs(newValue);

// if the sum is overflowing, it's safe to assume numbers are very large. So we force int64.
if (!isFinite(existingValueAbs + newValueAbs))
return Number.MAX_SAFE_INTEGER

// it's too complex to distinguish int8, int16, int32 and int64, so we just use the sum as best-guess
return existingValueAbs + newValueAbs;
}

// There should be other cases
console.error(`Error: something went wrong with findBestValueForNumberType() using the values: '${newValue}' and '${existingValue}'`)
console.error(" Please report the problem to https://github.com/mholt/json-to-go/issues")
return null // falls back to goType "any"
}

// Given two types, returns the more specific of the two
function mostSpecificPossibleGoType(typ1, typ2)
{
Expand Down
1 change: 1 addition & 0 deletions json-to-go.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ function testFiles() {
const testCases = [
"duplicate-top-level-structs",
"double-nested-objects",
"array-with-mixed-float-int",
"array-with-nonmatching-types",
];

Expand Down
13 changes: 13 additions & 0 deletions tests/array-with-mixed-float-int.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type AutoGenerated struct {
AgeOfTheUniverse []AgeOfTheUniverse `json:"age of the universe"`
AgeOfTheEarth []AgeOfTheEarth `json:"age of the earth"`
Date string `json:"date"`
}
type AgeOfTheUniverse struct {
Name string `json:"name"`
Value float64 `json:"value"`
}
type AgeOfTheEarth struct {
Name string `json:"name"`
Value int64 `json:"value"`
}
31 changes: 31 additions & 0 deletions tests/array-with-mixed-float-int.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"age of the universe": [
{
"name": "in years",
"value": 1378700000
},
{
"name": "in seconds",
"value": 4.35075327952992e+17
},
{
"name": "in kapla",
"value": 0.31914351851
}
],
"age of the earth": [
{
"name": "in eons (roughly)",
"value": 4
},
{
"name": "in years",
"value": 4.543e9
},
{
"name": "in seconds",
"value": 1.6592953e+12
}
],
"date": "2024-07-25"
}