MikroORM multirange (PostgreSQL) Custom Type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { Type } from '@mikro-orm/core';
import dayjs from 'dayjs';

/**
* Тип PostgreSQL 14+ tsmultirange
* @example tsmultirange.convertToJSValue('{["2024-01-01 00:00:00","2024-01-01 18:00:00"),["2024-01-01 19:00:00","2024-01-01 23:00:00")}');
* @example tsmultirange.convertToDatabaseValue([[1704056400000, 1704121200000], [1704124800000, 1704139200000]]);
*/
export class TsMultirange extends Type<[number, number][], string> {
/**
* Конвертировать значение в соответствующее представление tsmultirange в PostgreSQL
* @param jsRanges Диапазоны в формате [timestampFrom, timestampTo][]
* @returns Строчное представление данных в PostgreSQL
*/
convertToDatabaseValue(jsRanges: [number, number][]): string {
const ranges: string[] = [];
const dateFormat = 'YYYY-MM-DD HH:mm';
for (const [from, to] of jsRanges) {
ranges.push(`[${dayjs(from).format(dateFormat)}, ${dayjs(to).format(dateFormat)})`);
};
const result = `{${ranges.join(',')}}`;
return result;
};

/**
* Конвертировать значение, представленное в виде строки в PostgreSQL в соответствующий объект
* @param dbValue Диапазон в формате tsmultirange в PostgreSQL
* @returns Диапазоны в формате [timestampFrom, timestampTo][]
*/
convertToJSValue(dbValue: string): [number, number][] {
const rangesRegExp = /\[(.*?[^\\])\)/g;
const matches: IterableIterator<RegExpMatchArray> = dbValue.matchAll(rangesRegExp);
const result = [];
for (const match of matches) {
const jsRange = match[1]
.replace(/"/g, '')
.split(',')
.map((datetime: string) => dayjs(datetime).valueOf());
result.push(jsRange);
}
return result;
};

/**
* Тип столбца в PostgreSQL
* @returns Тип столбца
*/
getColumnType(): string {
return 'tsmultirange';
}
}