postgres-interval 2.1.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.js +66 -52
  2. package/package.json +4 -4
  3. package/readme.md +1 -1
package/index.js CHANGED
@@ -7,10 +7,6 @@ function PostgresInterval (raw) {
7
7
  return new PostgresInterval(raw)
8
8
  }
9
9
 
10
- for (const key in positions) {
11
- this[key] = 0
12
- }
13
-
14
10
  Object.assign(this, parse(raw))
15
11
  }
16
12
  const properties = ['seconds', 'minutes', 'hours', 'days', 'months', 'years']
@@ -88,55 +84,73 @@ function toISOString ({ short = false }) {
88
84
  }
89
85
 
90
86
  const NUMBER = '([+-]?\\d+)'
91
- const YEAR = NUMBER + '\\s+years?'
92
- const MONTH = NUMBER + '\\s+mons?'
93
- const DAY = NUMBER + '\\s+days?'
94
- const TIME = '([+-])?([\\d]*):(\\d\\d):(\\d\\d)\\.?(\\d{1,6})?'
95
- const INTERVAL = new RegExp([YEAR, MONTH, DAY, TIME].map(function (regexString) {
96
- return '(' + regexString + ')?'
87
+ const YEAR = `${NUMBER}\\s+years?`
88
+ const MONTH = `${NUMBER}\\s+mons?`
89
+ const DAY = `${NUMBER}\\s+days?`
90
+ // NOTE: PostgreSQL automatically overflows seconds into minutes and minutes
91
+ // into hours, so we can rely on minutes and seconds always being 2 digits
92
+ // (plus decimal for seconds). The overflow stops at hours - hours do not
93
+ // overflow into days, so could be arbitrarily long.
94
+ const TIME = '([+-])?(\\d+):(\\d\\d):(\\d\\d(?:\\.\\d{1,6})?)'
95
+ const INTERVAL = new RegExp(
96
+ '^\\s*' +
97
+ // All parts of an interval are optional
98
+ [YEAR, MONTH, DAY, TIME].map((str) => '(?:' + str + ')?').join('\\s*') +
99
+ '\\s*$'
100
+ )
101
+
102
+ // All intervals will have exactly these properties:
103
+ const ZERO_INTERVAL = Object.freeze({
104
+ years: 0,
105
+ months: 0,
106
+ days: 0,
107
+ hours: 0,
108
+ minutes: 0,
109
+ seconds: 0,
110
+ milliseconds: 0.0
97
111
  })
98
- .join('\\s*'))
99
-
100
- // Positions of values in regex match
101
- const positions = {
102
- years: 2,
103
- months: 4,
104
- days: 6,
105
- hours: 9,
106
- minutes: 10,
107
- seconds: 11,
108
- milliseconds: 12
109
- }
110
- // We can use negative time
111
- const negatives = ['hours', 'minutes', 'seconds', 'milliseconds']
112
-
113
- function parseMilliseconds (fraction) {
114
- // add omitted zeroes
115
- const microseconds = fraction + '000000'.slice(fraction.length)
116
- return parseInt(microseconds, 10) / 1000
117
- }
118
112
 
119
113
  function parse (interval) {
120
- if (!interval) return {}
121
- const matches = INTERVAL.exec(interval)
122
- const isNegative = matches[8] === '-'
123
- return Object.keys(positions)
124
- .reduce(function (parsed, property) {
125
- const position = positions[property]
126
- let value = matches[position]
127
- // no empty string
128
- if (!value) return parsed
129
- // milliseconds are actually microseconds (up to 6 digits)
130
- // with omitted trailing zeroes.
131
- value = property === 'milliseconds'
132
- ? parseMilliseconds(value)
133
- : parseInt(value, 10)
134
- // no zeros
135
- if (!value) return parsed
136
- if (isNegative && ~negatives.indexOf(property)) {
137
- value *= -1
138
- }
139
- parsed[property] = value
140
- return parsed
141
- }, {})
114
+ if (!interval) {
115
+ return ZERO_INTERVAL
116
+ }
117
+
118
+ const matches = INTERVAL.exec(interval) || []
119
+
120
+ const [
121
+ ,
122
+ yearsString,
123
+ monthsString,
124
+ daysString,
125
+ plusMinusTime,
126
+ hoursString,
127
+ minutesString,
128
+ secondsString
129
+ ] = matches
130
+
131
+ const timeMultiplier = plusMinusTime === '-' ? -1 : 1
132
+
133
+ const years = yearsString ? parseInt(yearsString, 10) : 0
134
+ const months = monthsString ? parseInt(monthsString, 10) : 0
135
+ const days = daysString ? parseInt(daysString, 10) : 0
136
+ const hours = hoursString ? timeMultiplier * parseInt(hoursString, 10) : 0
137
+ const minutes = minutesString
138
+ ? timeMultiplier * parseInt(minutesString, 10)
139
+ : 0
140
+ const secondsFloat = parseFloat(secondsString) || 0
141
+ // secondsFloat is guaranteed to be >= 0, so floor is safe
142
+ const absSeconds = Math.floor(secondsFloat)
143
+ const seconds = timeMultiplier * absSeconds
144
+ // Without the rounding, we end up with decimals like 455.99999999999994 instead of 456
145
+ const milliseconds = Math.round(timeMultiplier * (secondsFloat - absSeconds) * 1000000) / 1000
146
+ return {
147
+ years,
148
+ months,
149
+ days,
150
+ hours,
151
+ minutes,
152
+ seconds,
153
+ milliseconds
154
+ }
142
155
  }
156
+ PostgresInterval.parse = parse
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "postgres-interval",
3
3
  "main": "index.js",
4
- "version": "2.1.0",
4
+ "version": "3.0.0",
5
5
  "description": "Parse Postgres interval columns",
6
6
  "license": "MIT",
7
7
  "repository": "bendrucker/postgres-interval",
8
8
  "author": {
9
9
  "name": "Ben Drucker",
10
10
  "email": "bvdrucker@gmail.com",
11
- "url": "bendrucker.me"
11
+ "url": "https://www.bendrucker.me"
12
12
  },
13
13
  "engines": {
14
- "node": ">=8"
14
+ "node": ">=12"
15
15
  },
16
16
  "scripts": {
17
17
  "test": "standard && tape test.js"
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "dependencies": {},
25
25
  "devDependencies": {
26
- "standard": "^14.0.0",
26
+ "standard": "^16.0.0",
27
27
  "tape": "^5.0.0"
28
28
  },
29
29
  "files": [
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # postgres-interval [![Build Status](https://travis-ci.org/bendrucker/postgres-interval.svg?branch=master)](https://travis-ci.org/bendrucker/postgres-interval)
1
+ # postgres-interval [![tests](https://github.com/bendrucker/postgres-interval/workflows/tests/badge.svg)](https://github.com/bendrucker/postgres-interval/actions?query=workflow%3Atests)
2
2
 
3
3
  > Parse Postgres interval columns
4
4