/
utils.js
178 lines (147 loc) · 4.34 KB
/
utils.js
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import sqlString from 'sqlstring-sqlite';
import Long from 'long';
/*
* Validate configuration.
*/
export function validateConfigForImport(config) {
if (!config.agencies || config.agencies.length === 0) {
throw new Error('No `agencies` specified in config');
}
for (const [index, agency] of config.agencies.entries()) {
if (!agency.path && !agency.url) {
throw new Error(
`No Agency \`url\` or \`path\` specified in config for agency index ${index}.`,
);
}
}
return config;
}
/*
* Initialize configuration with defaults.
*/
export function setDefaultConfig(initialConfig) {
const defaults = {
sqlitePath: ':memory:',
ignoreDuplicates: false,
};
return {
...defaults,
...initialConfig,
};
}
export function convertLongTimeToDate(longDate) {
const { high, low, unsigned } = longDate;
return new Date(new Long(low, high, unsigned).toInt() * 1000).toISOString();
}
/*
* Calculate seconds from midnight for HH:mm:ss
*/
export function calculateSecondsFromMidnight(time) {
const split = time.split(':').map((d) => Number.parseInt(d, 10));
if (split.length !== 3) {
return null;
}
return split[0] * 3600 + split[1] * 60 + split[2];
}
/*
* Adds leading zeros to HH:mm:ss timestamps
*/
export function padLeadingZeros(time) {
const split = time.split(':').map((d) => String(Number(d)).padStart(2, '0'));
if (split.length !== 3) {
return null;
}
return split.join(':');
}
export function formatSelectClause(fields) {
if (Array.isArray(fields)) {
const selectItem =
fields.length > 0
? fields.map((fieldName) => sqlString.escapeId(fieldName)).join(', ')
: '*';
return `SELECT ${selectItem}`;
}
const selectItem = Object.entries(fields)
.map(
(key) => `${sqlString.escapeId(key[0])} AS ${sqlString.escapeId(key[1])}`,
)
.join(', ');
return `SELECT ${selectItem}`;
}
export function formatJoinClause(joinObject) {
return joinObject
.map(
(data) =>
`${data.type ? data.type + ' JOIN' : 'INNER JOIN'} ${sqlString.escapeId(
data.table,
)} ON ${data.on}`,
)
.join(' ');
}
function degree2radian(angle) {
return (angle * Math.PI) / 180;
}
function radian2degree(angle) {
return (angle / Math.PI) * 180;
}
/*
* Search inside GPS coordinates boundary box
* Distance unit: meters
* */
export function formatWhereClauseBoundingBox(
latitudeDegree,
longitudeDegree,
boundingBoxSideMeters,
) {
const earthRadius = 6371000;
latitudeDegree = parseFloat(latitudeDegree);
longitudeDegree = parseFloat(longitudeDegree);
const latitudeRadian = degree2radian(latitudeDegree);
const radiusFromLatitude = Math.cos(latitudeRadian) * earthRadius;
// `boundingBoxSideMeters` is divided by 2 we are centering the coordinates in the middle of this square
const deltaLatitude = radian2degree(boundingBoxSideMeters / 2 / earthRadius);
const deltaLongitude = radian2degree(
boundingBoxSideMeters / 2 / radiusFromLatitude,
);
let query = `stop_lat BETWEEN ${latitudeDegree - deltaLatitude} AND ${latitudeDegree + deltaLatitude}`;
query += ` AND stop_lon BETWEEN ${longitudeDegree - deltaLongitude} AND ${longitudeDegree + deltaLongitude}`;
return query;
}
export function formatWhereClause(key, value) {
if (Array.isArray(value)) {
let whereClause = `${sqlString.escapeId(key)} IN (${value
.filter((v) => v !== null)
.map((v) => sqlString.escape(v))
.join(', ')})`;
if (value.includes(null)) {
whereClause = `(${whereClause} OR ${sqlString.escapeId(key)} IS NULL)`;
}
return whereClause;
}
if (value === null) {
return `${sqlString.escapeId(key)} IS NULL`;
}
return `${sqlString.escapeId(key)} = ${sqlString.escape(value)}`;
}
export function formatWhereClauses(query) {
if (Object.keys(query).length === 0) {
return '';
}
const whereClauses = Object.entries(query).map(([key, value]) =>
formatWhereClause(key, value),
);
return `WHERE ${whereClauses.join(' AND ')}`;
}
export function formatOrderByClause(orderBy) {
let orderByClause = '';
if (orderBy.length > 0) {
orderByClause += 'ORDER BY ';
orderByClause += orderBy
.map(([key, value]) => {
const direction = value === 'DESC' ? 'DESC' : 'ASC';
return `${sqlString.escapeId(key)} ${direction}`;
})
.join(', ');
}
return orderByClause;
}