193 lines
6.2 KiB
TypeScript
193 lines
6.2 KiB
TypeScript
import { Op } from 'sequelize';
|
|
|
|
import { Optional } from 'src/types';
|
|
import { Db } from 'src/db';
|
|
import { ValidationError } from '../errors';
|
|
|
|
type Order = 'ASC' | 'DESC';
|
|
|
|
class LocationRequest {
|
|
userId: Optional<number> = null;
|
|
deviceId: Optional<string> = null;
|
|
limit: Optional<number> = 250;
|
|
offset: Optional<number> = null;
|
|
startDate: Optional<Date> = null;
|
|
endDate: Optional<Date> = null;
|
|
ids: Optional<number[]> = null;
|
|
minId: Optional<number> = null;
|
|
maxId: Optional<number> = null;
|
|
minLatitude: Optional<number> = null;
|
|
maxLatitude: Optional<number> = null;
|
|
minLongitude: Optional<number> = null;
|
|
maxLongitude: Optional<number> = null;
|
|
country: Optional<string> = null;
|
|
locality: Optional<string> = null;
|
|
postalCode: Optional<string> = null;
|
|
description: Optional<string> = null;
|
|
orderBy: string = 'timestamp';
|
|
order: Order = 'DESC';
|
|
|
|
constructor(req: {
|
|
userId?: number;
|
|
deviceId?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
startDate?: Date;
|
|
endDate?: Date;
|
|
ids?: number[] | string;
|
|
minId?: number;
|
|
maxId?: number;
|
|
minLatitude?: number;
|
|
maxLatitude?: number;
|
|
minLongitude?: number;
|
|
maxLongitude?: number;
|
|
country?: string;
|
|
locality?: string;
|
|
postalCode?: string;
|
|
description?: string;
|
|
orderBy?: string;
|
|
order?: string;
|
|
}) {
|
|
this.userId = req.userId;
|
|
this.deviceId = req.deviceId?.length ? req.deviceId : this.deviceId;
|
|
this.initNumber('limit', req);
|
|
this.initNumber('offset', req);
|
|
this.initDate('startDate', req);
|
|
this.initDate('endDate', req);
|
|
this.initNumber('minId', req);
|
|
this.initNumber('maxId', req);
|
|
this.initNumber('minLatitude', req, parseFloat);
|
|
this.initNumber('maxLatitude', req, parseFloat);
|
|
this.initNumber('minLongitude', req, parseFloat);
|
|
this.initNumber('maxLongitude', req, parseFloat);
|
|
this.country = req.country?.toLowerCase();
|
|
this.locality = req.locality;
|
|
this.postalCode = req.postalCode;
|
|
this.description = req.description;
|
|
this.orderBy = req.orderBy || this.orderBy;
|
|
this.order = (req.order || this.order).toUpperCase() as Order;
|
|
|
|
const ids = typeof req.ids === 'string' ? req.ids.split(/\s*,\s*/) : req.ids;
|
|
this.ids = (ids || []).map((id: any) => {
|
|
const numId = parseInt(id);
|
|
if (isNaN(numId)) {
|
|
throw new ValidationError(`Invalid value for ids: ${id}`);
|
|
}
|
|
return numId;
|
|
});
|
|
}
|
|
|
|
private initNumber(key: string, req: any, parser: (s: string) => number = parseInt): void {
|
|
if (req[key] != null) {
|
|
const numValue = (this as any)[key] = parser(req[key]);
|
|
if (isNaN(numValue)) {
|
|
throw new ValidationError(`Invalid value for ${key}: ${req[key]}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
private initDate(key: string, req: any): void {
|
|
if (req[key] != null) {
|
|
const numValue = (this as any)[key] = parseInt(req[key]);
|
|
const dateValue = (this as any)[key] = new Date(isNaN(numValue) ? req[key] : numValue);
|
|
if (isNaN(dateValue.getTime())) {
|
|
throw new ValidationError(`Invalid value for ${key}: ${req[key]}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
public toMap(db: Db): any {
|
|
let queryMap: any = {};
|
|
const where: any = {};
|
|
|
|
if (this.ids?.length) {
|
|
queryMap.where = {
|
|
[db.locationTableColumns.id || 'id']: {[Op.in]: this.ids},
|
|
};
|
|
|
|
queryMap.order = [[db.locationTableColumns.timestamp || 'timestamp', this.order.toUpperCase()]];
|
|
// If we have ids, we don't need any other filters
|
|
return queryMap;
|
|
}
|
|
|
|
if (this.limit != null) {
|
|
queryMap.limit = this.limit;
|
|
}
|
|
|
|
if (this.offset != null) {
|
|
queryMap.offset = this.offset;
|
|
}
|
|
|
|
if (this.deviceId != null) {
|
|
const deviceIds = this.deviceId.split(/\s*,\s*/);
|
|
where[db.locationTableColumns.deviceId || 'deviceId'] = {[Op.in]: deviceIds};
|
|
}
|
|
|
|
const colMapping: any = db.locationTableColumns
|
|
if (this.startDate != null || this.endDate != null) {
|
|
const start = this.startDate == null ? 0 : this.startDate.getTime();
|
|
const end = this.endDate == null ? new Date().getTime() : this.endDate.getTime();
|
|
const column = colMapping.timestamp || 'timestamp';
|
|
const where_t: any = where[column] = {};
|
|
where_t[Op.between] = [start, end];
|
|
}
|
|
|
|
if (this.minId != null || this.maxId != null) {
|
|
const column = colMapping.id || 'id';
|
|
const where_id: any = where[column] = {};
|
|
if (this.minId == null && this.maxId != null) {
|
|
where_id[Op.lte] = this.maxId;
|
|
} else if (this.minId != null && this.maxId == null) {
|
|
where_id[Op.gte] = this.minId;
|
|
} else {
|
|
where_id[Op.between] = [this.minId, this.maxId];
|
|
}
|
|
}
|
|
|
|
if (this.country != null) {
|
|
where[colMapping.country || 'country'] = this.country;
|
|
}
|
|
|
|
if (this.locality != null) {
|
|
where[colMapping.locality || 'locality'] = this.locality;
|
|
}
|
|
|
|
if (this.postalCode != null) {
|
|
where[colMapping.postalCode || 'postalCode'] = this.postalCode;
|
|
}
|
|
|
|
if (this.description != null) {
|
|
where[colMapping.description || 'description'] = {[Op.like]: `%${this.description}%`};
|
|
}
|
|
|
|
if (this.minLatitude != null || this.maxLatitude != null) {
|
|
const column = colMapping.latitude || 'latitude';
|
|
const where_lat: any = where[column] = {};
|
|
if (this.minLatitude == null && this.maxLatitude != null) {
|
|
where_lat[Op.lte] = this.maxLatitude;
|
|
} else if (this.minLatitude != null && this.maxLatitude == null) {
|
|
where_lat[Op.gte] = this.minLatitude;
|
|
} else {
|
|
where_lat[Op.between] = [this.minLatitude, this.maxLatitude];
|
|
}
|
|
}
|
|
|
|
if (this.minLongitude != null || this.maxLongitude != null) {
|
|
const column = colMapping.longitude || 'longitude';
|
|
const where_lon: any = where[column] = {};
|
|
if (this.minLongitude == null && this.maxLongitude != null) {
|
|
where_lon[Op.lte] = this.maxLongitude;
|
|
} else if (this.minLongitude != null && this.maxLongitude == null) {
|
|
where_lon[Op.gte] = this.minLongitude;
|
|
} else {
|
|
where_lon[Op.between] = [this.minLongitude, this.maxLongitude];
|
|
}
|
|
}
|
|
|
|
queryMap.where = where;
|
|
queryMap.order = [[colMapping[this.orderBy], this.order.toUpperCase()]];
|
|
return queryMap;
|
|
}
|
|
}
|
|
|
|
export default LocationRequest;
|