UNPKG

@uwdata/mosaic-sql

Version:

SQL query construction and analysis.

109 lines (97 loc) 3.17 kB
import { binStep } from './bin-step.js'; export type DateTimeValue = Date | number; export type TimeUnit = | 'year' | 'quarter' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' | 'microsecond'; const YEAR = 'year'; const MONTH = 'month'; const DAY = 'day'; const HOUR = 'hour'; const MINUTE = 'minute'; const SECOND = 'second'; const MILLISECOND = 'millisecond'; const MICROSECOND = 'microsecond'; const durationSecond = 1000; const durationMinute = durationSecond * 60; const durationHour = durationMinute * 60; const durationDay = durationHour * 24; const durationWeek = durationDay * 7; const durationMonth = durationDay * 30; const durationYear = durationDay * 365; const units: {unit: TimeUnit, step: number, dt: number}[] = [ { unit: SECOND, step: 1, dt: durationSecond }, { unit: SECOND, step: 5, dt: durationSecond * 5 }, { unit: SECOND, step: 15, dt: durationSecond * 15 }, { unit: SECOND, step: 30, dt: durationSecond * 30 }, { unit: MINUTE, step: 1, dt: durationMinute }, { unit: MINUTE, step: 5, dt: durationMinute * 5 }, { unit: MINUTE, step: 15, dt: durationMinute * 15 }, { unit: MINUTE, step: 30, dt: durationMinute * 30 }, { unit: HOUR, step: 1, dt: durationHour }, { unit: HOUR, step: 3, dt: durationHour * 3 }, { unit: HOUR, step: 6, dt: durationHour * 6 }, { unit: HOUR, step: 12, dt: durationHour * 12 }, { unit: DAY, step: 1, dt: durationDay }, { unit: DAY, step: 7, dt: durationWeek }, { unit: MONTH, step: 1, dt: durationMonth }, { unit: MONTH, step: 3, dt: durationMonth * 3 }, { unit: YEAR, step: 1, dt: durationYear } ]; /** * Determine a time interval for binning based on provided min * and max timestamps and approximate step count. * @param min The minimum timestamp value. * @param max The maximum timestamp value. * @param steps The approximate number of bins desired. */ export function timeInterval( min: DateTimeValue, max: DateTimeValue, steps: number ): ({ unit: TimeUnit, step: number }) { const span = +max - +min; const t = span / steps; // target step size duration const i = bisect(units, t, v => v.dt); let unit: TimeUnit; let step: number; if (i === units.length) { unit = YEAR; step = binStep(span / durationYear, steps); } else if (i) { ({ unit, step } = units[t / units[i-1].dt < units[i].dt / t ? i-1 : i]); } else { step = binStep(span, steps); unit = step >= 1 ? MILLISECOND : MICROSECOND; step = step >= 1 ? step : step * 1000; } return { unit, step }; } /** * Perform a binary search. * @param a The array to search. * @param x The target value. * @param value A value accessor. * @returns The search result array index. */ function bisect<I, T>(a: I[], x: T, value: (item: I) => T) { const compare1 = (a: T, b: T) => Number(a) - Number(b); const compare2 = (d: I, x: T) => compare1(value(d), x); let lo = 0; let hi = a.length; if (lo < hi) { if (compare1(x, x) !== 0) return hi; do { const mid = (lo + hi) >>> 1; if (compare2(a[mid], x) <= 0) lo = mid + 1; else hi = mid; } while (lo < hi); } return lo; }