Skip to content

Commit

Permalink
Treat integers longer than 32 bit as floats. (#6082)
Browse files Browse the repository at this point in the history
* Fix handling of integers longer than 32 bits. Treat them as floats.

* Fix handling of integers longer than 32 bits. Treat them as floats.

* Added tests for number type inference.
  • Loading branch information
MichaelZoerner authored and m-allanson committed Jun 25, 2018
1 parent bb1d429 commit e117179
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 8 deletions.
24 changes: 20 additions & 4 deletions packages/gatsby/src/schema/__tests__/data-tree-utils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,34 +176,50 @@ describe(`Gatsby data tree utils`, () => {
it(`prefers float when multiple number types`, () => {
let example

// nodes starting with integer
// nodes starting with 32-bit integer ("big" ints are float)
example = getExampleValues({ nodes: [{ number: 5 }, { number: 2.5 }] })
expect(example.number).toBeDefined()
expect(example.number).toEqual(2.5)
example = getExampleValues({ nodes: [{ number: 5 }, { number: 3000000000 }] })
expect(example.number).toBeDefined()
expect(example.number).toEqual(3000000000)

// with node not containing number field
example = getExampleValues({ nodes: [{ number: 5 }, {}, { number: 2.5 }] })
expect(example.number).toBeDefined()
expect(example.number).toEqual(2.5)

// nodes starting with float
// nodes starting with float ("big" ints are float)
example = getExampleValues({ nodes: [{ number: 2.5 }, { number: 5 }] })
expect(example.number).toBeDefined()
expect(example.number).toEqual(2.5)
example = getExampleValues({ nodes: [{ number: 3000000000 }, { number: 5 }] })
expect(example.number).toBeDefined()
expect(example.number).toEqual(3000000000)

// array of numbers - starting with integer
// array of numbers - starting with float
example = getExampleValues({ nodes: [{ numbers: [2.5, 5] }] })
expect(example.numbers).toBeDefined()
expect(Array.isArray(example.numbers)).toBe(true)
expect(example.numbers.length).toBe(1)
expect(example.numbers[0]).toBe(2.5)
example = getExampleValues({ nodes: [{ numbers: [3000000000, 5] }] })
expect(example.numbers).toBeDefined()
expect(Array.isArray(example.numbers)).toBe(true)
expect(example.numbers.length).toBe(1)
expect(example.numbers[0]).toBe(3000000000)

// array of numbers - starting with float
// array of numbers - starting with 32-bit integer
example = getExampleValues({ nodes: [{ numbers: [5, 2.5] }] })
expect(example.numbers).toBeDefined()
expect(Array.isArray(example.numbers)).toBe(true)
expect(example.numbers.length).toBe(1)
expect(example.numbers[0]).toBe(2.5)
example = getExampleValues({ nodes: [{ numbers: [5, 3000000000] }] })
expect(example.numbers).toBeDefined()
expect(Array.isArray(example.numbers)).toBe(true)
expect(example.numbers.length).toBe(1)
expect(example.numbers[0]).toBe(3000000000)
})

it(`handles mix of date strings and date objects`, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ describe(`GraphQL Input args`, () => {
expect(Object.keys(fields.foo.type.getFields())).toHaveLength(2)
})

it(`infers number types`, () => {
const fields = inferInputObjectStructureFromNodes({
nodes: [
{
int32: 42,
float: 2.5,
longint: 3000000000,
},
],
}).inferredFields
expect(fields.int32.type.name.endsWith(`Integer`)).toBe(true)
expect(fields.float.type.name.endsWith(`Float`)).toBe(true)
expect(fields.longint.type.name.endsWith(`Float`)).toBe(true)
})

it(`handles eq operator`, async () => {
let result = await queryResult(
nodes,
Expand Down
29 changes: 29 additions & 0 deletions packages/gatsby/src/schema/__tests__/infer-graphql-type-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,20 @@ describe(`GraphQL type inferance`, () => {
)
})

it(`doesn't throw errors at ints longer than 32-bit`, async () => {
const result = await queryResult(
[
{
longint: 3000000000,
},
],
`
longint
`
)
expect(result.errors).toBeUndefined()
})

it(`prefers float when multiple number types`, async () => {
let result = await queryResult(
[{ number: 1.1 }, { number: 1 }],
Expand Down Expand Up @@ -199,6 +213,21 @@ describe(`GraphQL type inferance`, () => {
expect(Object.keys(fields.foo.type.getFields())).toHaveLength(4)
})

it(`infers number types`, () => {
const fields = inferObjectStructureFromNodes({
nodes: [
{
int32: 42,
float: 2.5,
longint: 3000000000,
},
],
})
expect(fields.int32.type.name).toEqual(`Int`)
expect(fields.float.type.name).toEqual(`Float`)
expect(fields.longint.type.name).toEqual(`Float`)
})

it(`Handle invalid graphql field names`, async () => {
let result = await queryResult(
nodes,
Expand Down
3 changes: 2 additions & 1 deletion packages/gatsby/src/schema/data-tree-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const invariant = require(`invariant`)
const createKey = require(`./create-key`)
const { typeConflictReporter } = require(`./type-conflict-reporter`)
const DateType = require(`./types/type-date`)
const is32BitInteger = require(`../utils/is-32-bit-integer`)

import type { TypeEntry } from "./type-conflict-reporter"

Expand Down Expand Up @@ -118,7 +119,7 @@ const getExampleScalarFromArray = values =>
values,
(value, nextValue) => {
// Prefer floats over ints as they're more specific.
if (nextValue && _.isNumber(nextValue) && !_.isInteger(nextValue)) {
if (nextValue && _.isNumber(nextValue) && !is32BitInteger(nextValue)) {
return nextValue
} else if (value === null) {
return nextValue
Expand Down
5 changes: 3 additions & 2 deletions packages/gatsby/src/schema/infer-graphql-input-fields.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {

const { findLinkedNode } = require(`./infer-graphql-type`)
const { getNodes } = require(`../redux`)
const is32BitInteger = require(`../utils/is-32-bit-integer`)

import type {
GraphQLInputFieldConfig,
Expand Down Expand Up @@ -76,7 +77,7 @@ function inferGraphQLInputFields({
let headType = typeOf(headValue)

if (headType === `number`)
headType = _.isInteger(headValue) ? `int` : `float`
headType = is32BitInteger(headValue) ? `int` : `float`

// Determine type for in operator.
let inType
Expand Down Expand Up @@ -165,7 +166,7 @@ function inferGraphQLInputFields({
}
}
case `number`: {
if (value % 1 === 0) {
if (is32BitInteger(value)) {
return {
type: new GraphQLInputObjectType({
name: createTypeName(`${prefix}QueryInteger`),
Expand Down
3 changes: 2 additions & 1 deletion packages/gatsby/src/schema/infer-graphql-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const createKey = require(`./create-key`)
const { getExampleValues, isEmptyObjectOrArray } = require(`./data-tree-utils`)
const DateType = require(`./types/type-date`)
const FileType = require(`./types/type-file`)
const is32BitInteger = require(`../utils/is-32-bit-integer`)

import type { GraphQLOutputType } from "graphql"
import type {
Expand Down Expand Up @@ -117,7 +118,7 @@ function inferGraphQLType({
}),
}
case `number`:
return _.isInteger(exampleValue)
return is32BitInteger(exampleValue)
? { type: GraphQLInt }
: { type: GraphQLFloat }
default:
Expand Down
21 changes: 21 additions & 0 deletions packages/gatsby/src/utils/__tests__/is-32-bit-integer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const is32BitInteger = require(`../is-32-bit-integer.js`)

const MAX_INT = 2147483647
const MIN_INT = -2147483648

describe(`is32BitInteger`, () => {
it(`works with all kind of values`, () => {
expect(is32BitInteger(MAX_INT)).toBe(true)
expect(is32BitInteger(MIN_INT)).toBe(true)
expect(is32BitInteger(MAX_INT + 1)).toBe(false)
expect(is32BitInteger(MIN_INT - 1)).toBe(false)
expect(is32BitInteger(2.4)).toBe(false)
expect(is32BitInteger(`42`)).toBe(false)
expect(is32BitInteger({})).toBe(false)
expect(is32BitInteger([1])).toBe(false)
expect(is32BitInteger(true)).toBe(false)
expect(is32BitInteger(false)).toBe(false)
expect(is32BitInteger(undefined)).toBe(false)
expect(is32BitInteger(null)).toBe(false)
})
})
3 changes: 3 additions & 0 deletions packages/gatsby/src/utils/is-32-bit-integer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = function(x) {
return (x | 0) === x
}

0 comments on commit e117179

Please sign in to comment.