Get rid of lots of unnecessary lodash calls.
This commit is contained in:
parent
b734a422a7
commit
5592892f0d
|
@ -1,6 +1,5 @@
|
||||||
import {LogLevel, LogLevels, isLogLevel} from "./types";
|
import {isLogLevel, LogLevel, LogLevels} from "./types";
|
||||||
import {ActivatableLoggerImpl} from "./logger";
|
import {ActivatableLoggerImpl} from "./logger";
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
class TestableLogger extends ActivatableLoggerImpl {
|
class TestableLogger extends ActivatableLoggerImpl {
|
||||||
private logs: any[][] = [];
|
private logs: any[][] = [];
|
||||||
|
@ -59,7 +58,7 @@ function parseLogEntry(logEntry: any[]): ParsedLogEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagsStr = groups[2].substring(1, groups[2].length - 1);
|
const tagsStr = groups[2].substring(1, groups[2].length - 1);
|
||||||
const tags = tagsStr ? _.split(tagsStr, ", ") : [];
|
const tags = tagsStr ? tagsStr.split(", "): [];
|
||||||
const message = groups[3];
|
const message = groups[3];
|
||||||
const args = logEntry.slice(1);
|
const args = logEntry.slice(1);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import {Logger, TaggedLogger, LogLevel} from './types';
|
import {isString, Logger, LogLevel, TaggedLogger} from './types';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
export type LoggingFunction = (...args: any[]) => void;
|
export type LoggingFunction = (...args: any[]) => void;
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ export class ActivatableLoggerImpl implements ActivatableLogger {
|
||||||
log(level: LogLevel, ...args: any[]): void {
|
log(level: LogLevel, ...args: any[]): void {
|
||||||
const timeStr = moment().format('YYYY-MM-DD HH:mm:ss');
|
const timeStr = moment().format('YYYY-MM-DD HH:mm:ss');
|
||||||
const levelStr = level.toUpperCase();
|
const levelStr = level.toUpperCase();
|
||||||
const tagsStr = tags ? '[' + _.join(tags, ', ') + ']' : '';
|
const tagsStr = tags ? '[' + tags.join(', ') + ']' : '';
|
||||||
const messagePrefix = `${timeStr} ${levelStr} - ${tagsStr}`;
|
const messagePrefix = `${timeStr} ${levelStr} - ${tagsStr}`;
|
||||||
|
|
||||||
// Make sure to only replace %s, etc. in real log message
|
// Make sure to only replace %s, etc. in real log message
|
||||||
|
@ -44,7 +43,7 @@ export class ActivatableLoggerImpl implements ActivatableLogger {
|
||||||
const escapedMessagePrefix = messagePrefix.replace(/%/g, '%%');
|
const escapedMessagePrefix = messagePrefix.replace(/%/g, '%%');
|
||||||
|
|
||||||
let message = '';
|
let message = '';
|
||||||
if (args && _.isString(args[0])) {
|
if (args && isString(args[0])) {
|
||||||
message = args[0];
|
message = args[0];
|
||||||
args.shift();
|
args.shift();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
import CONSTRAINTS from "../validation/constraints";
|
import CONSTRAINTS from "../validation/constraints";
|
||||||
import ErrorTypes from "../utils/errorTypes";
|
import ErrorTypes from "../utils/errorTypes";
|
||||||
import * as MonitoringService from "../services/monitoringService";
|
import * as MonitoringService from "../services/monitoringService";
|
||||||
|
@ -17,8 +15,8 @@ async function doGetAll(req: Request): Promise<{ total: number, result: any }> {
|
||||||
const {monitoringStates, total} = await MonitoringService.getAll(restParams);
|
const {monitoringStates, total} = await MonitoringService.getAll(restParams);
|
||||||
return {
|
return {
|
||||||
total,
|
total,
|
||||||
result: _.map(monitoringStates, function (state) {
|
result: monitoringStates.map(state => {
|
||||||
state.mapId = _.toLower(state.mac).replace(/:/g, '');
|
state.mapId = state.mac.toLowerCase().replace(/:/g, "");
|
||||||
return state;
|
return state;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
import Constraints from "../validation/constraints";
|
import Constraints from "../validation/constraints";
|
||||||
import ErrorTypes from "../utils/errorTypes";
|
import ErrorTypes from "../utils/errorTypes";
|
||||||
import * as MonitoringService from "../services/monitoringService";
|
import * as MonitoringService from "../services/monitoringService";
|
||||||
|
@ -13,12 +11,12 @@ import {
|
||||||
CreateOrUpdateNode,
|
CreateOrUpdateNode,
|
||||||
DomainSpecificNodeResponse,
|
DomainSpecificNodeResponse,
|
||||||
isNodeSortField,
|
isNodeSortField,
|
||||||
isToken, JSONObject,
|
isToken,
|
||||||
|
JSONObject,
|
||||||
MAC,
|
MAC,
|
||||||
NodeResponse,
|
NodeResponse,
|
||||||
NodeStateData,
|
NodeStateData,
|
||||||
NodeTokenResponse,
|
NodeTokenResponse,
|
||||||
StoredNode,
|
|
||||||
toDomainSpecificNodeResponse,
|
toDomainSpecificNodeResponse,
|
||||||
Token,
|
Token,
|
||||||
toNodeResponse,
|
toNodeResponse,
|
||||||
|
@ -27,15 +25,18 @@ import {
|
||||||
|
|
||||||
const nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
const nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
||||||
|
|
||||||
|
// TODO: Rename
|
||||||
function getNormalizedNodeData(reqData: any): CreateOrUpdateNode {
|
function getNormalizedNodeData(reqData: any): CreateOrUpdateNode {
|
||||||
const node: { [key: string]: any } = {};
|
const node: { [key: string]: any } = {};
|
||||||
_.each(nodeFields, function (field) {
|
for (const field of nodeFields) {
|
||||||
let value = normalizeString(reqData[field]);
|
let value = normalizeString(reqData[field]);
|
||||||
if (field === 'mac') {
|
if (field === 'mac') {
|
||||||
value = normalizeMac(value as MAC);
|
value = normalizeMac(value as MAC);
|
||||||
}
|
}
|
||||||
node[field] = value;
|
node[field] = value;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// TODO: Add typeguard before cast.
|
||||||
return node as CreateOrUpdateNode;
|
return node as CreateOrUpdateNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,15 +91,15 @@ async function doGetAll(req: Request): Promise<{ total: number; pageNodes: any }
|
||||||
|
|
||||||
const nodes = await NodeService.getAllNodes();
|
const nodes = await NodeService.getAllNodes();
|
||||||
|
|
||||||
const realNodes = _.filter(nodes, node =>
|
const realNodes = nodes.filter(node =>
|
||||||
// We ignore nodes without tokens as those are only manually added ones like gateways.
|
// We ignore nodes without tokens as those are only manually added ones like gateways.
|
||||||
!!node.token
|
!!node.token // FIXME: As node.token may not be undefined or null here, handle this when loading!
|
||||||
);
|
);
|
||||||
|
|
||||||
const macs: MAC[] = _.map(realNodes, (node: StoredNode): MAC => node.mac);
|
const macs: MAC[] = realNodes.map(node => node.mac);
|
||||||
const nodeStateByMac = await MonitoringService.getByMacs(macs);
|
const nodeStateByMac = await MonitoringService.getByMacs(macs);
|
||||||
|
|
||||||
const domainSpecificNodes: DomainSpecificNodeResponse[] = _.map(realNodes, (node: StoredNode): DomainSpecificNodeResponse => {
|
const domainSpecificNodes: DomainSpecificNodeResponse[] = realNodes.map(node => {
|
||||||
const nodeState: NodeStateData = nodeStateByMac[node.mac] || {};
|
const nodeState: NodeStateData = nodeStateByMac[node.mac] || {};
|
||||||
return toDomainSpecificNodeResponse(node, nodeState);
|
return toDomainSpecificNodeResponse(node, nodeState);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
import CONSTRAINTS from "../validation/constraints";
|
import CONSTRAINTS from "../validation/constraints";
|
||||||
import ErrorTypes from "../utils/errorTypes";
|
import ErrorTypes from "../utils/errorTypes";
|
||||||
import * as Resources from "../utils/resources";
|
import * as Resources from "../utils/resources";
|
||||||
import {Entity, handleJSONWithData, RequestData} from "../utils/resources";
|
import {handleJSONWithData, RequestData} from "../utils/resources";
|
||||||
import {getTasks, Task, TaskState} from "../jobs/scheduler";
|
import {getTasks, Task, TaskState} from "../jobs/scheduler";
|
||||||
import {normalizeString} from "../utils/strings";
|
import {normalizeString} from "../utils/strings";
|
||||||
import {forConstraint} from "../validation/validator";
|
import {forConstraint} from "../validation/validator";
|
||||||
|
@ -77,11 +75,11 @@ async function setTaskEnabled(data: RequestData, enable: boolean): Promise<TaskR
|
||||||
return toTaskResponse(task);
|
return toTaskResponse(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doGetAll(req: Request): Promise<{ total: number, pageTasks: Entity[] }> {
|
async function doGetAll(req: Request): Promise<{ total: number, pageTasks: Task[] }> {
|
||||||
const restParams = await Resources.getValidRestParams('list', null, req);
|
const restParams = await Resources.getValidRestParams('list', null, req);
|
||||||
|
|
||||||
const tasks = Resources.sort(
|
const tasks = Resources.sort(
|
||||||
_.values(getTasks()),
|
Object.values(getTasks()),
|
||||||
isTaskSortField,
|
isTaskSortField,
|
||||||
restParams
|
restParams
|
||||||
);
|
);
|
||||||
|
@ -104,7 +102,7 @@ export function getAll(req: Request, res: Response): void {
|
||||||
doGetAll(req)
|
doGetAll(req)
|
||||||
.then(({total, pageTasks}) => {
|
.then(({total, pageTasks}) => {
|
||||||
res.set('X-Total-Count', total.toString(10));
|
res.set('X-Total-Count', total.toString(10));
|
||||||
Resources.success(res, _.map(pageTasks, toTaskResponse));
|
Resources.success(res, pageTasks.map(toTaskResponse));
|
||||||
})
|
})
|
||||||
.catch(err => Resources.error(res, err));
|
.catch(err => Resources.error(res, err));
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ export async function getPendingMails(restParams: RestParams): Promise<{ mails:
|
||||||
|
|
||||||
const mails = await db.all(
|
const mails = await db.all(
|
||||||
'SELECT * FROM email_queue WHERE ' + filter.query,
|
'SELECT * FROM email_queue WHERE ' + filter.query,
|
||||||
_.concat([], filter.params),
|
filter.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -97,7 +97,7 @@ export async function render(mailOptions: Mail): Promise<{subject: string, body:
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return {
|
return {
|
||||||
subject: _.trim(_.template(subject.toString())(data)),
|
subject: _.template(subject.toString())(data).trim(),
|
||||||
body: _.template(body.toString())(data)
|
body: _.template(body.toString())(data)
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -19,10 +19,13 @@ import {
|
||||||
Domain,
|
Domain,
|
||||||
DurationSeconds,
|
DurationSeconds,
|
||||||
Hostname,
|
Hostname,
|
||||||
|
isBoolean,
|
||||||
isDomain,
|
isDomain,
|
||||||
isMonitoringSortField,
|
isMonitoringSortField,
|
||||||
isOnlineState,
|
isOnlineState,
|
||||||
isSite,
|
isSite,
|
||||||
|
isString,
|
||||||
|
isUndefined,
|
||||||
MAC,
|
MAC,
|
||||||
MailType,
|
MailType,
|
||||||
MonitoringSortField,
|
MonitoringSortField,
|
||||||
|
@ -164,7 +167,7 @@ async function storeNodeInformation(nodeData: ParsedNode, node: StoredNode): Pro
|
||||||
|
|
||||||
const row = await db.get('SELECT * FROM node_state WHERE mac = ?', [node.mac]);
|
const row = await db.get('SELECT * FROM node_state WHERE mac = ?', [node.mac]);
|
||||||
|
|
||||||
if (_.isUndefined(row)) {
|
if (isUndefined(row)) {
|
||||||
return await insertNodeInformation(nodeData, node);
|
return await insertNodeInformation(nodeData, node);
|
||||||
} else {
|
} else {
|
||||||
return await updateNodeInformation(nodeData, node, row);
|
return await updateNodeInformation(nodeData, node, row);
|
||||||
|
@ -188,7 +191,7 @@ export function parseNode(importTimestamp: UnixTimestampSeconds, nodeData: any):
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeId = nodeData.nodeinfo.node_id;
|
const nodeId = nodeData.nodeinfo.node_id;
|
||||||
if (!nodeId || !_.isString(nodeId)) {
|
if (!nodeId || !isString(nodeId)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Invalid node id of type "${typeof nodeId}": ${nodeId}`
|
`Invalid node id of type "${typeof nodeId}": ${nodeId}`
|
||||||
);
|
);
|
||||||
|
@ -212,7 +215,7 @@ export function parseNode(importTimestamp: UnixTimestampSeconds, nodeData: any):
|
||||||
'Node ' + nodeId + ': Unexpected flags type: ' + (typeof nodeData.flags)
|
'Node ' + nodeId + ': Unexpected flags type: ' + (typeof nodeData.flags)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!_.isBoolean(nodeData.flags.online)) {
|
if (!isBoolean(nodeData.flags.online)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Node ' + nodeId + ': Unexpected flags.online type: ' + (typeof nodeData.flags.online)
|
'Node ' + nodeId + ': Unexpected flags.online type: ' + (typeof nodeData.flags.online)
|
||||||
);
|
);
|
||||||
|
@ -558,6 +561,7 @@ async function retrieveNodeInformationForUrls(urls: string[]): Promise<RetrieveN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Replace any[] by type.
|
||||||
export async function getAll(restParams: RestParams): Promise<{ total: number, monitoringStates: any[] }> {
|
export async function getAll(restParams: RestParams): Promise<{ total: number, monitoringStates: any[] }> {
|
||||||
const filterFields = [
|
const filterFields = [
|
||||||
'hostname',
|
'hostname',
|
||||||
|
@ -571,7 +575,7 @@ export async function getAll(restParams: RestParams): Promise<{ total: number, m
|
||||||
|
|
||||||
const row = await db.get<{ total: number }>(
|
const row = await db.get<{ total: number }>(
|
||||||
'SELECT count(*) AS total FROM node_state WHERE ' + where.query,
|
'SELECT count(*) AS total FROM node_state WHERE ' + where.query,
|
||||||
_.concat([], where.params),
|
where.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
const total = row?.total || 0;
|
const total = row?.total || 0;
|
||||||
|
@ -585,7 +589,7 @@ export async function getAll(restParams: RestParams): Promise<{ total: number, m
|
||||||
|
|
||||||
const monitoringStates = await db.all(
|
const monitoringStates = await db.all(
|
||||||
'SELECT * FROM node_state WHERE ' + filter.query,
|
'SELECT * FROM node_state WHERE ' + filter.query,
|
||||||
_.concat([], filter.params),
|
filter.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {monitoringStates, total};
|
return {monitoringStates, total};
|
||||||
|
@ -603,7 +607,7 @@ export async function getByMacs(macs: MAC[]): Promise<Record<MAC, NodeStateData>
|
||||||
|
|
||||||
const rows = await db.all<NodeStateRow>(
|
const rows = await db.all<NodeStateRow>(
|
||||||
'SELECT * FROM node_state WHERE ' + inCondition.query,
|
'SELECT * FROM node_state WHERE ' + inCondition.query,
|
||||||
_.concat([], inCondition.params),
|
inCondition.params,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
|
@ -734,7 +738,7 @@ async function deleteNeverOnlineNodesBefore(deleteBefore: UnixTimestampSeconds):
|
||||||
deletionCandidates.length
|
deletionCandidates.length
|
||||||
);
|
);
|
||||||
|
|
||||||
const deletionCandidateMacs: MAC[] = _.map(deletionCandidates, node => node.mac);
|
const deletionCandidateMacs: MAC[] = deletionCandidates.map(node => node.mac);
|
||||||
const chunks: MAC[][] = _.chunk(deletionCandidateMacs, NEVER_ONLINE_NODES_DELETION_CHUNK_SIZE);
|
const chunks: MAC[][] = _.chunk(deletionCandidateMacs, NEVER_ONLINE_NODES_DELETION_CHUNK_SIZE);
|
||||||
|
|
||||||
Logger
|
Logger
|
||||||
|
@ -753,10 +757,7 @@ async function deleteNeverOnlineNodesBefore(deleteBefore: UnixTimestampSeconds):
|
||||||
' MACs for deletion.'
|
' MACs for deletion.'
|
||||||
);
|
);
|
||||||
|
|
||||||
const placeholders = _.join(
|
const placeholders = macs.map(() => '?').join(',');
|
||||||
_.map(macs, () => '?'),
|
|
||||||
','
|
|
||||||
);
|
|
||||||
|
|
||||||
const rows: { mac: MAC }[] = await db.all(
|
const rows: { mac: MAC }[] = await db.all(
|
||||||
`SELECT * FROM node_state WHERE mac IN (${placeholders})`,
|
`SELECT * FROM node_state WHERE mac IN (${placeholders})`,
|
||||||
|
@ -773,7 +774,7 @@ async function deleteNeverOnlineNodesBefore(deleteBefore: UnixTimestampSeconds):
|
||||||
' nodes found in monitoring database. Those should be skipped.'
|
' nodes found in monitoring database. Those should be skipped.'
|
||||||
);
|
);
|
||||||
|
|
||||||
const seenMacs: MAC[] = _.map(rows, (row: { mac: MAC }) => row.mac as MAC);
|
const seenMacs: MAC[] = rows.map(row => row.mac);
|
||||||
const neverSeenMacs = _.difference(macs, seenMacs);
|
const neverSeenMacs = _.difference(macs, seenMacs);
|
||||||
|
|
||||||
Logger
|
Logger
|
||||||
|
|
|
@ -108,15 +108,15 @@ async function findFilesInPeersPath(): Promise<string[]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseNodeFilename(filename: string): NodeFilenameParsed {
|
function parseNodeFilename(filename: string): NodeFilenameParsed {
|
||||||
const parts = _.split(filename, '@', filenameParts.length);
|
const parts = filename.split('@', filenameParts.length);
|
||||||
const parsed: { [key: string]: string | undefined } = {};
|
const parsed: { [key: string]: string | undefined } = {};
|
||||||
const zippedParts = _.zip<string, string>(filenameParts, parts);
|
const zippedParts = _.zip<string, string>(filenameParts, parts);
|
||||||
_.each(zippedParts, part => {
|
for (const part of zippedParts) {
|
||||||
const key = part[0];
|
const key = part[0];
|
||||||
if (key) {
|
if (key) {
|
||||||
parsed[key] = part[1];
|
parsed[key] = part[1];
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,14 +565,14 @@ export async function fixNodeFilenames(): Promise<void> {
|
||||||
|
|
||||||
export async function findNodesModifiedBefore(timestamp: UnixTimestampSeconds): Promise<StoredNode[]> {
|
export async function findNodesModifiedBefore(timestamp: UnixTimestampSeconds): Promise<StoredNode[]> {
|
||||||
const nodes = await getAllNodes();
|
const nodes = await getAllNodes();
|
||||||
return _.filter(nodes, node => node.modifiedAt < timestamp);
|
return nodes.filter(node => node.modifiedAt < timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getNodeStatistics(): Promise<NodeStatistics> {
|
export async function getNodeStatistics(): Promise<NodeStatistics> {
|
||||||
const nodes = await getAllNodes();
|
const nodes = await getAllNodes();
|
||||||
|
|
||||||
const nodeStatistics: NodeStatistics = {
|
const nodeStatistics: NodeStatistics = {
|
||||||
registered: _.size(nodes),
|
registered: nodes.length,
|
||||||
withVPN: 0,
|
withVPN: 0,
|
||||||
withCoords: 0,
|
withCoords: 0,
|
||||||
monitoring: {
|
monitoring: {
|
||||||
|
|
|
@ -116,6 +116,10 @@ export function toIsEnum<E>(enumDef: E): EnumTypeGuard<E> {
|
||||||
return (arg): arg is EnumValue<E> => Object.values(enumDef).includes(arg as [keyof E]);
|
return (arg): arg is EnumValue<E> => Object.values(enumDef).includes(arg as [keyof E]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRegExp(arg: unknown): arg is RegExp {
|
||||||
|
return isObject(arg) && arg instanceof RegExp;
|
||||||
|
}
|
||||||
|
|
||||||
export function isOptional<T>(arg: unknown, isT: TypeGuard<T>): arg is (T | undefined) {
|
export function isOptional<T>(arg: unknown, isT: TypeGuard<T>): arg is (T | undefined) {
|
||||||
return arg === undefined || isT(arg);
|
return arg === undefined || isT(arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import _ from "lodash";
|
||||||
|
|
||||||
export function inCondition<T>(field: string, list: T[]): {query: string, params: T[]} {
|
export function inCondition<T>(field: string, list: T[]): {query: string, params: T[]} {
|
||||||
return {
|
return {
|
||||||
query: '(' + field + ' IN (' + _.join(_.times(list.length, _.constant('?')), ', ') + '))',
|
query: '(' + field + ' IN (' + _.times(list.length, () =>'?').join(', ') + '))',
|
||||||
params: list,
|
params: list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ export function filter<E>(entities: E[], allowedFilterFields: string[], restPara
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return _.some(allowedFilterFields, (field: string): boolean => {
|
return allowedFilterFields.some((field: string): boolean => {
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -209,15 +209,15 @@ export function filter<E>(entities: E[], allowedFilterFields: string[], restPara
|
||||||
const filters = restParams.filters;
|
const filters = restParams.filters;
|
||||||
|
|
||||||
function filtersMatch(entity: Entity): boolean {
|
function filtersMatch(entity: Entity): boolean {
|
||||||
if (_.isEmpty(filters)) {
|
if (isUndefined(filters) || _.isEmpty(filters)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.every(filters, (value: any, key: string): boolean => {
|
return Object.entries(filters).every(([key, value]) => {
|
||||||
if (isUndefined(value)) {
|
if (isUndefined(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_.startsWith(key, 'has')) {
|
if (key.startsWith('has')) {
|
||||||
const entityKey = key.substring(3, 4).toLowerCase() + key.substring(4);
|
const entityKey = key.substring(3, 4).toLowerCase() + key.substring(4);
|
||||||
return _.isEmpty(entity[entityKey]).toString() !== value;
|
return _.isEmpty(entity[entityKey]).toString() !== value;
|
||||||
}
|
}
|
||||||
|
@ -225,9 +225,7 @@ export function filter<E>(entities: E[], allowedFilterFields: string[], restPara
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.filter(entities, function (entity) {
|
return entities.filter(entity => queryMatches(entity) && filtersMatch(entity));
|
||||||
return queryMatches(entity) && filtersMatch(entity);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sort<T extends Record<S, any>, S extends string>(entities: T[], isSortField: TypeGuard<S>, restParams: RestParams): T[] {
|
export function sort<T extends Record<S, any>, S extends string>(entities: T[], isSortField: TypeGuard<S>, restParams: RestParams): T[] {
|
||||||
|
@ -262,7 +260,7 @@ export function sort<T extends Record<S, any>, S extends string>(entities: T[],
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPageEntities(entities: Entity[], restParams: RestParams) {
|
export function getPageEntities<Entity>(entities: Entity[], restParams: RestParams): Entity[] {
|
||||||
const page = restParams._page;
|
const page = restParams._page;
|
||||||
const perPage = restParams._perPage;
|
const perPage = restParams._perPage;
|
||||||
|
|
||||||
|
@ -291,7 +289,7 @@ export function filterClause<S>(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
query: filter.query + ' ' + orderBy.query + ' ' + limitOffset.query,
|
query: filter.query + ' ' + orderBy.query + ' ' + limitOffset.query,
|
||||||
params: _.concat(filter.params, orderBy.params, limitOffset.params)
|
params: [...filter.params, ...orderBy.params, ...limitOffset.params]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import {MAC} from "../types";
|
import {isString, MAC} from "../types";
|
||||||
|
|
||||||
export function normalizeString(str: string): string {
|
export function normalizeString(str: string): string {
|
||||||
return _.isString(str) ? str.trim().replace(/\s+/g, ' ') : str;
|
return isString(str) ? str.trim().replace(/\s+/g, ' ') : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeMac(mac: MAC): MAC {
|
export function normalizeMac(mac: MAC): MAC {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {DurationSeconds, UnixTimestampSeconds} from "../types";
|
import {DurationSeconds, isString, UnixTimestampSeconds} from "../types";
|
||||||
import _ from "lodash";
|
|
||||||
import moment, {Moment} from "moment";
|
import moment, {Moment} from "moment";
|
||||||
|
|
||||||
export function now(): UnixTimestampSeconds {
|
export function now(): UnixTimestampSeconds {
|
||||||
|
@ -45,7 +44,7 @@ export function formatTimestamp(timestamp: UnixTimestampSeconds): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseTimestamp(timestamp: any): UnixTimestampSeconds | null {
|
export function parseTimestamp(timestamp: any): UnixTimestampSeconds | null {
|
||||||
if (!_.isString(timestamp)) {
|
if (!isString(timestamp)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const parsed = moment.utc(timestamp);
|
const parsed = moment.utc(timestamp);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import _ from "lodash"
|
|
||||||
import {config} from "../config"
|
import {config} from "../config"
|
||||||
import {MonitoringToken, Url} from "../types"
|
import {MonitoringToken, Url} from "../types"
|
||||||
|
|
||||||
|
@ -12,15 +11,10 @@ function formUrl(route: string, queryParams?: { [key: string]: string }): Url {
|
||||||
}
|
}
|
||||||
if (queryParams) {
|
if (queryParams) {
|
||||||
url += '?';
|
url += '?';
|
||||||
url += _.join(
|
url +=
|
||||||
_.map(
|
Object.entries(queryParams)
|
||||||
queryParams,
|
.map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
|
||||||
function (value, key) {
|
.join("&");
|
||||||
return encodeURIComponent(key) + '=' + encodeURIComponent(value);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
'&'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return url as Url;
|
return url as Url;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
import {parseInteger} from "../utils/strings";
|
import {parseInteger} from "../utils/strings";
|
||||||
import Logger from "../logger";
|
import Logger from "../logger";
|
||||||
|
import {isArray, isBoolean, isNumber, isObject, isRegExp, isString, isUndefined} from "../types";
|
||||||
|
|
||||||
export interface Constraint {
|
export interface Constraint {
|
||||||
type: string,
|
type: string,
|
||||||
|
@ -18,52 +17,48 @@ export interface Constraint {
|
||||||
regex?: RegExp,
|
regex?: RegExp,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Constraints = {[key: string]: Constraint};
|
export type Constraints = { [key: string]: Constraint };
|
||||||
export type Values = {[key: string]: any};
|
export type Values = { [key: string]: any };
|
||||||
|
|
||||||
function isStringArray(arr: any): arr is string[] {
|
|
||||||
return _.isArray(arr) && _.every(arr, (val: any) => _.isString(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isConstraint(val: any): val is Constraint {
|
export function isConstraint(val: any): val is Constraint {
|
||||||
if (!_.isObject(val)) {
|
if (!isObject(val)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const constraint = val as {[key: string]: any};
|
const constraint = val as { [key: string]: any };
|
||||||
|
|
||||||
if (!("type" in constraint) || !_.isString(constraint.type)) {
|
if (!("type" in constraint) || !isString(constraint.type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("optional" in constraint
|
if ("optional" in constraint
|
||||||
&& !_.isUndefined(constraint.optional)
|
&& !isUndefined(constraint.optional)
|
||||||
&& !_.isBoolean(constraint.optional)) {
|
&& !isBoolean(constraint.optional)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("allowed" in constraint
|
if ("allowed" in constraint
|
||||||
&& !_.isUndefined(constraint.allowed)
|
&& !isUndefined(constraint.allowed)
|
||||||
&& !isStringArray(constraint.allowed)) {
|
&& !isArray(constraint.allowed, isString)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("min" in constraint
|
if ("min" in constraint
|
||||||
&& !_.isUndefined(constraint.min)
|
&& !isUndefined(constraint.min)
|
||||||
&& !_.isNumber(constraint.min)) {
|
&& !isNumber(constraint.min)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("max" in constraint
|
if ("max" in constraint
|
||||||
&& !_.isUndefined(constraint.max)
|
&& !isUndefined(constraint.max)
|
||||||
&& !_.isNumber(constraint.max)) {
|
&& !isNumber(constraint.max)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// noinspection RedundantIfStatementJS
|
// noinspection RedundantIfStatementJS
|
||||||
if ("regex" in constraint
|
if ("regex" in constraint
|
||||||
&& !_.isUndefined(constraint.regex)
|
&& !isUndefined(constraint.regex)
|
||||||
&& !_.isRegExp(constraint.regex)) {
|
&& !isRegExp(constraint.regex)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,41 +66,38 @@ export function isConstraint(val: any): val is Constraint {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isConstraints(constraints: any): constraints is Constraints {
|
export function isConstraints(constraints: any): constraints is Constraints {
|
||||||
if (!_.isObject(constraints)) {
|
if (!isObject(constraints)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.every(
|
return Object.entries(constraints).every(([key, constraint]) => isString(key) && isConstraint(constraint));
|
||||||
constraints,
|
|
||||||
(constraint: any, key: any) => _.isString(key) && isConstraint(constraint)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: sanitize input for further processing as specified by constraints (correct types, trimming, etc.)
|
// TODO: sanitize input for further processing as specified by constraints (correct types, trimming, etc.)
|
||||||
|
|
||||||
function isValidBoolean(value: any): boolean {
|
function isValidBoolean(value: any): boolean {
|
||||||
return _.isBoolean(value) || value === 'true' || value === 'false';
|
return isBoolean(value) || value === 'true' || value === 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidNumber(constraint: Constraint, value: any): boolean {
|
function isValidNumber(constraint: Constraint, value: any): boolean {
|
||||||
if (_.isString(value)) {
|
if (isString(value)) {
|
||||||
value = parseInteger(value);
|
value = parseInteger(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isNumber(value)) {
|
if (!isNumber(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isNaN(value) || !_.isFinite(value)) {
|
if (isNaN(value) || !isFinite(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isNumber(constraint.min) && value < constraint.min) {
|
if (isNumber(constraint.min) && value < constraint.min) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// noinspection RedundantIfStatementJS
|
// noinspection RedundantIfStatementJS
|
||||||
if (_.isNumber(constraint.max) && value > constraint.max) {
|
if (isNumber(constraint.max) && value > constraint.max) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,11 +105,12 @@ function isValidNumber(constraint: Constraint, value: any): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidEnum(constraint: Constraint, value: any): boolean {
|
function isValidEnum(constraint: Constraint, value: any): boolean {
|
||||||
if (!_.isString(value)) {
|
if (!isString(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _.indexOf(constraint.allowed, value) >= 0;
|
const allowed = constraint.allowed || [];
|
||||||
|
return allowed.indexOf(value) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidString(constraint: Constraint, value: any): boolean {
|
function isValidString(constraint: Constraint, value: any): boolean {
|
||||||
|
@ -125,7 +118,7 @@ function isValidString(constraint: Constraint, value: any): boolean {
|
||||||
throw new Error("String constraints must have regex set: " + constraint);
|
throw new Error("String constraints must have regex set: " + constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_.isString(value)) {
|
if (!isString(value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,10 +167,10 @@ function areValid(constraints: Constraints, acceptUndefined: boolean, values: Va
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forConstraint (constraint: Constraint, acceptUndefined: boolean): (value: any) => boolean {
|
export function forConstraint(constraint: Constraint, acceptUndefined: boolean): (value: any) => boolean {
|
||||||
return ((value: any): boolean => isValid(constraint, acceptUndefined, value));
|
return ((value: any): boolean => isValid(constraint, acceptUndefined, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function forConstraints (constraints: Constraints, acceptUndefined: boolean): (values: Values) => boolean {
|
export function forConstraints(constraints: Constraints, acceptUndefined: boolean): (values: Values) => boolean {
|
||||||
return ((values: Values): boolean => areValid(constraints, acceptUndefined, values));
|
return ((values: Values): boolean => areValid(constraints, acceptUndefined, values));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue