Skip to content

Commit 79017c5

Browse files
authored
fix(types): fix parsing interval to support fractional seconds (#678)
1 parent d152bda commit 79017c5

7 files changed

Lines changed: 141 additions & 70 deletions

File tree

packages/graphile-build-pg/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
"jsonwebtoken": "^8.5.1",
4646
"lodash": ">=4 <5",
4747
"lru-cache": ">=4 <5",
48-
"pg-sql2": "4.9.0",
49-
"postgres-interval": "^2.1.0"
48+
"pg-sql2": "4.9.0"
5049
},
5150
"peerDependencies": {
5251
"pg": ">=6.1.0 <9"

packages/graphile-build-pg/src/plugins/PgTypesPlugin.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Plugin } from "graphile-build";
33

44
import makeGraphQLJSONType from "../GraphQLJSON";
55

6-
import rawParseInterval from "postgres-interval";
6+
import { parseInterval as rawParseInterval } from "../postgresInterval";
77
import LRU from "@graphile/lru";
88

99
function indent(str) {
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// @flow
2+
3+
// Regexp construction enhanced from `postgres-interval`, which is licensed
4+
// under the MIT license and is copyright (c) Ben Drucker <bvdrucker@gmail.com>
5+
// (bendrucker.me).
6+
7+
const NUMBER = "([+-]?\\d+)";
8+
const YEAR = `${NUMBER}\\s+years?`;
9+
const MONTH = `${NUMBER}\\s+mons?`;
10+
const DAY = `${NUMBER}\\s+days?`;
11+
// NOTE: PostgreSQL automatically overflows seconds into minutes and minutes
12+
// into hours, so we can rely on minutes and seconds always being 2 digits
13+
// (plus decimal for seconds). The overflow stops at hours - hours do not
14+
// overflow into days, so could be arbitrarily long.
15+
const TIME = "([+-])?(\\d+):(\\d\\d):(\\d\\d(?:\\.\\d{1,6})?)";
16+
17+
const INTERVAL = new RegExp(
18+
"^\\s*" +
19+
// All parts of an interval are optional
20+
[YEAR, MONTH, DAY, TIME].map(str => "(?:" + str + ")?").join("\\s*") +
21+
"\\s*$"
22+
);
23+
24+
export type Interval = {
25+
years: number,
26+
months: number,
27+
days: number,
28+
hours: number,
29+
minutes: number,
30+
seconds: number,
31+
};
32+
33+
// All intervals will have exactly these properties:
34+
const BASE: Interval = Object.freeze({
35+
years: 0,
36+
months: 0,
37+
days: 0,
38+
hours: 0,
39+
minutes: 0,
40+
seconds: 0.0,
41+
});
42+
43+
export function parseInterval(interval: string): Interval {
44+
const result = { ...BASE };
45+
46+
if (!interval) {
47+
return result;
48+
}
49+
50+
const matches = INTERVAL.exec(interval);
51+
if (!matches) {
52+
throw new Error(`Failed to parse interval '${interval}' from PostgreSQL`);
53+
}
54+
55+
const [
56+
,
57+
years,
58+
months,
59+
days,
60+
plusMinusTime,
61+
hours,
62+
minutes,
63+
seconds,
64+
] = matches;
65+
66+
const timeMultiplier = plusMinusTime === "-" ? -1 : 1;
67+
68+
if (years) result.years = parseInt(years, 10);
69+
if (months) result.months = parseInt(months, 10);
70+
if (days) result.days = parseInt(days, 10);
71+
if (hours) result.hours = timeMultiplier * parseInt(hours, 10);
72+
if (minutes) result.minutes = timeMultiplier * parseInt(minutes, 10);
73+
// Seconds can be decimal; all other values are integer
74+
if (seconds) result.seconds = timeMultiplier * parseFloat(seconds);
75+
76+
return result;
77+
}

packages/postgraphile-core/__tests__/integration/__snapshots__/mutations.test.js.snap

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,7 +2064,7 @@ Object {
20642064
"hours": 4,
20652065
"minutes": 5,
20662066
"months": 2,
2067-
"seconds": 6,
2067+
"seconds": 6.789123,
20682068
"years": 1,
20692069
},
20702070
"intervalArray": Array [
@@ -2073,7 +2073,7 @@ Object {
20732073
"hours": 4,
20742074
"minutes": 5,
20752075
"months": 2,
2076-
"seconds": 6,
2076+
"seconds": 6.789123,
20772077
"years": 1,
20782078
},
20792079
Object {
@@ -2214,7 +2214,7 @@ Object {
22142214
"hours": 4,
22152215
"minutes": 5,
22162216
"months": 2,
2217-
"seconds": 6,
2217+
"seconds": 6.789123,
22182218
"years": 1,
22192219
},
22202220
"intervalArray": Array [
@@ -2223,7 +2223,7 @@ Object {
22232223
"hours": 4,
22242224
"minutes": 5,
22252225
"months": 2,
2226-
"seconds": 6,
2226+
"seconds": 6.789123,
22272227
"years": 1,
22282228
},
22292229
Object {
@@ -2362,7 +2362,7 @@ Object {
23622362
"hours": 4,
23632363
"minutes": 5,
23642364
"months": 2,
2365-
"seconds": 6,
2365+
"seconds": 6.789123,
23662366
"years": 1,
23672367
},
23682368
"intervalArray": Array [
@@ -2371,7 +2371,7 @@ Object {
23712371
"hours": 4,
23722372
"minutes": 5,
23732373
"months": 2,
2374-
"seconds": 6,
2374+
"seconds": 6.789123,
23752375
"years": 1,
23762376
},
23772377
Object {
@@ -2512,7 +2512,7 @@ Object {
25122512
"hours": 4,
25132513
"minutes": 5,
25142514
"months": 2,
2515-
"seconds": 6,
2515+
"seconds": 6.789123,
25162516
"years": 1,
25172517
},
25182518
"intervalArray": Array [
@@ -2521,7 +2521,7 @@ Object {
25212521
"hours": 4,
25222522
"minutes": 5,
25232523
"months": 2,
2524-
"seconds": 6,
2524+
"seconds": 6.789123,
25252525
"years": 1,
25262526
},
25272527
Object {
@@ -2659,7 +2659,7 @@ Object {
26592659
"hours": 4,
26602660
"minutes": 5,
26612661
"months": 2,
2662-
"seconds": 6,
2662+
"seconds": 6.789123,
26632663
"years": 1,
26642664
},
26652665
"intervalArray": Array [
@@ -2668,7 +2668,7 @@ Object {
26682668
"hours": 4,
26692669
"minutes": 5,
26702670
"months": 2,
2671-
"seconds": 6,
2671+
"seconds": 6.789123,
26722672
"years": 1,
26732673
},
26742674
Object {

0 commit comments

Comments
 (0)