@tai-kun/surrealdb
Version:
The SurrealDB SDK for JavaScript
164 lines (139 loc) • 4.67 kB
text/typescript
import { Duration as Base } from "@tai-kun/surrealdb/decodeonly-datatypes";
import { NumberRangeError } from "@tai-kun/surrealdb/errors";
import { CBOR_TAG_DURATION, type Encodable } from "./spec";
export type * from "../decode-only/duration";
const SECONDS_PER_MINUTE = 60n;
const SECONDS_PER_HOUR = 60n * SECONDS_PER_MINUTE;
const SECONDS_PER_DAY = 24n * SECONDS_PER_HOUR;
const SECONDS_PER_WEEK = 7n * SECONDS_PER_DAY;
const SECONDS_PER_YEAR = 365n * SECONDS_PER_DAY;
const NANOSECONDS_PER_MICROSECOND = 1_000n;
const NANOSECONDS_PER_MILLISECOND = 1_000_000n;
const NANOSECONDS_PER_SECOND = 1_000_000_000n;
const JS_MAX_SAFE_UNSIGNED_INTEGER = 9007199254740991n; // 2^53-1
/**
* [API Reference](https://tai-kun.github.io/surrealdb.js/v2/api/data/duration)
*/
export default class Duration extends Base implements Encodable {
// dprint-ignore
parse(): {
years?: number;
weeks?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
milliseconds?: number;
microseconds?: number;
nanoseconds?: number;
} {
// https://github.com/surrealdb/surrealdb/blob/v2.0.1/core/src/sql/duration.rs#L166
let secs = this.seconds;
let nano = BigInt(this.nanoseconds);
if (secs === 0n && nano === 0n) {
return {
nanoseconds: 0,
}
}
let year = secs / SECONDS_PER_YEAR;
secs = secs % SECONDS_PER_YEAR;
let week = secs / SECONDS_PER_WEEK;
secs = secs % SECONDS_PER_WEEK;
let days = secs / SECONDS_PER_DAY;
secs = secs % SECONDS_PER_DAY;
let hour = secs / SECONDS_PER_HOUR;
secs = secs % SECONDS_PER_HOUR;
let mins = secs / SECONDS_PER_MINUTE;
secs = secs % SECONDS_PER_MINUTE;
let msec = nano / NANOSECONDS_PER_MILLISECOND;
nano = nano % NANOSECONDS_PER_MILLISECOND;
let usec = nano / NANOSECONDS_PER_MICROSECOND;
nano = nano % NANOSECONDS_PER_MICROSECOND;
const o: {
years?: number
weeks?: number
days?: number
hours?: number
minutes?: number
seconds?: number
milliseconds?: number
microseconds?: number
nanoseconds?: number
} = {}
if (year) o.years = Number(year);
if (week) o.weeks = Number(week);
if (days) o.days = Number(days);
if (hour) o.hours = Number(hour);
if (mins) o.minutes = Number(mins);
if (secs) o.seconds = Number(secs);
if (msec) o.milliseconds = Number(msec);
if (usec) o.microseconds = Number(usec);
if (nano) o.nanoseconds = Number(nano);
return o
}
override valueOf(): bigint {
return this.seconds * NANOSECONDS_PER_SECOND + BigInt(this.nanoseconds);
}
// dprint-ignore
override toString(): string {
// https://github.com/surrealdbdb/surrealdbdb/blob/v1.5.2/core/sql/duration.rs#L159-L217
const o = this.parse();
let s = "";
if ("years" in o) s += o.years + "y";
if ("weeks" in o) s += o.weeks + "w";
if ("days" in o) s += o.days + "d";
if ("hours" in o) s += o.hours + "h";
if ("minutes" in o) s += o.minutes + "m";
if ("seconds" in o) s += o.seconds + "s";
if ("milliseconds" in o) s += o.milliseconds + "ms";
if ("microseconds" in o) s += o.microseconds + "µs";
if ("nanoseconds" in o) s += o.nanoseconds + "ns";
return s
}
[Symbol.toPrimitive](hint: "default" | "string"): string;
[Symbol.toPrimitive](hint: "number"): number;
[Symbol.toPrimitive](hint: string): string | number;
[Symbol.toPrimitive](hint: string): string | number {
switch (hint) {
case "number": {
const ms = this.seconds * 1_000n
+ BigInt(this.nanoseconds) / 1_000_000n;
if (ms > JS_MAX_SAFE_UNSIGNED_INTEGER || ms < 0n) {
throw new NumberRangeError([0n, JS_MAX_SAFE_UNSIGNED_INTEGER], ms, {
integer: true,
});
}
return Number(ms) + (this.nanoseconds % 1e6) / 1e6;
}
case "string":
case "default":
return this.toString();
default:
throw TypeError("Invalid hint: " + String(hint));
}
}
toCBOR(): [
tag: typeof CBOR_TAG_DURATION,
value: [seconds: bigint, nanoseconds: number],
] {
return [
CBOR_TAG_DURATION,
[this.seconds, this.nanoseconds],
];
}
toJSON(): string {
return this.toString();
}
toSurql(): string {
return this.toString();
}
toPlainObject(): {
seconds: bigint;
nanoseconds: number;
} {
return {
seconds: this.seconds,
nanoseconds: this.nanoseconds,
};
}
}