Skip to content

Commit

Permalink
Merge pull request #22 from mariojrrc/master
Browse files Browse the repository at this point in the history
refactor: npm audit fix, upgrade mongodb to v4, log4js to 6 and set node >=12
  • Loading branch information
Lansoweb authored Feb 8, 2022
2 parents 8c099a4 + 7619c66 commit 1be0ec8
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
},
"rules": {
"require-jsdoc": "off",
"no-underscore-dangle": ["error", { "allow": ["_id"] }],
"no-underscore-dangle": ["error", { "allow": ["_id", "_count", "_pageSize", "_total_items", "_page_count"] }],
"max-len": ["error", { "code": 120 }]
},
"globals": {
Expand Down
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"author": "Leandro Silva <[email protected]>",
"license": "MIT",
"private": false,
"engines": {
"node": ">=12.21"
},
"publishConfig": {
"access": "public"
},
Expand All @@ -25,19 +28,19 @@
"koa": "2.4.1",
"koa-helmet": "3.3.0",
"lodash.has": "^4.5.2",
"log4js": "2.4.1",
"log4js": "^6.4.1",
"moment": "^2.22.2",
"mongodb": "2.2.34",
"mongodb": "^4.3.1",
"query-string": "5.0.1",
"uuid": "^8.3.0"
},
"devDependencies": {
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@commitlint/cli": "^8.1.0",
"@commitlint/config-conventional": "^8.1.0",
"@commitlint/cli": "^16.1.0",
"@commitlint/config-conventional": "^16.0.0",
"babel-jest": "^26.6.1",
"eslint": "^6.2.1",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-import": "^2.18.2",
"husky": "^3.0.4",
Expand Down
91 changes: 47 additions & 44 deletions src/crud/mapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@ const DuplicationException = require('./duplication-exception');
const Uuid = require('../infra/uuid');
const MongoQF = require('./mongodb-query-filter');

function createQueryFilter(schema) {
if (Object.prototype.hasOwnProperty.call(schema, 'searchable') === false) {
// eslint-disable-next-line no-param-reassign
schema.searchable = Object.keys(schema.properties);
}
const whitelist = { after: 1, before: 1, between: 1 };
schema.searchable.forEach((key) => {
whitelist[key] = 1;
});
return new MongoQF({
custom: {
between: 'updatedAt',
after: 'updatedAt',
before: 'updatedAt',
},
whitelist,
});
}

class CrudMapper {
constructor(db, schema, options = {}) {
this.schema = schema;
Expand All @@ -21,7 +40,7 @@ class CrudMapper {
this.pageSize = 25;
this.queryFilter = createQueryFilter(schema);

if (this.schema.hasOwnProperty('unique') === false) {
if (Object.prototype.hasOwnProperty.call(this.schema, 'unique') === false) {
this.schema.unique = [];
}
}
Expand All @@ -31,9 +50,9 @@ class CrudMapper {

const withDeleted = params.deleted || params.disabled || false;
const withCount = params._count || false;
let pageSize = parseInt(params._pageSize || params.pageSize || this.pageSize);
let pageSize = parseInt(params._pageSize || params.pageSize || this.pageSize, 10);
const sortBy = params.sort || 'createdAt';
const orderBy = parseInt(params.order || -1);
const orderBy = parseInt(params.order || -1, 10);
const sort = {};
sort[sortBy] = orderBy;

Expand All @@ -56,12 +75,12 @@ class CrudMapper {
}
});

const page = parseInt(params.page || 1);
const page = parseInt(params.page || 1, 10);
let skip = (page - 1) * pageSize;

if (aggregateParam && page > 1) {
const aux = pageSize;
pageSize = page * pageSize;
pageSize *= page;
skip = pageSize - aux;
}

Expand Down Expand Up @@ -104,12 +123,12 @@ class CrudMapper {
filter.deleted = { $ne: true };
}

return await this.collection.findOne(filter);
return this.collection.findOne(filter);
}

async create(post) {
post = this.validateAll(post);
const data = this.toDatabase(post);
const validated = this.validateAll(post);
const data = this.toDatabase(validated);

await this.checkUniqueness(data);

Expand All @@ -126,7 +145,7 @@ class CrudMapper {
if (this.schema.unique.length > 0) {
const orFilter = [];
this.schema.unique.forEach((key) => {
if (data.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
if (typeof data[key] === 'object') {
data[key].forEach((value) => {
const obj = {};
Expand Down Expand Up @@ -154,7 +173,7 @@ class CrudMapper {
const message = [];
list.forEach((json) => {
this.schema.unique.forEach((key) => {
if (data.hasOwnProperty(key) && json.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(data, key) && Object.prototype.hasOwnProperty.call(json, key)) {
if (typeof data[key] === 'object') {
data[key].forEach((dataValue) => {
json[key].forEach((jsonValue) => {
Expand All @@ -180,8 +199,8 @@ class CrudMapper {
filter.deleted = { $ne: true };
}

post = this.validate(post);
const data = this.toDatabase(post);
const validated = this.validate(post);
const data = this.toDatabase(validated);

await this.checkUniqueness(data, id);

Expand Down Expand Up @@ -236,7 +255,7 @@ class CrudMapper {
return result.ok === 1;
}

toJson(data) {
static toJson(data) {
const json = { id: data._id, ...data };
delete json._id;
if (json.deleted === false) {
Expand All @@ -248,7 +267,7 @@ class CrudMapper {
}

toHal(result, router) {
const json = this.toJson(result);
const json = CrudMapper.toJson(result);
if (result.deleted === true) {
if (result.deletedAt) {
json.deletedAt = result.deletedAt;
Expand All @@ -267,7 +286,7 @@ class CrudMapper {
toHalCollection(result, ctx) {
const entities = [];

for (let i = 0; i < result.result.length; i++) {
for (let i = 0; i < result.result.length; i += 1) {
entities.push(this.toHal(result.result[i], ctx.router));
}

Expand All @@ -283,10 +302,10 @@ class CrudMapper {
_count: entities.length,
};

if (result.hasOwnProperty('count')) {
if (Object.prototype.hasOwnProperty.call(result, 'count')) {
paginationData._total_items = result.count || 0;
}
if (result.hasOwnProperty('page_count')) {
if (Object.prototype.hasOwnProperty.call(result, 'page_count')) {
paginationData._page_count = result.page_count || 1;
}

Expand All @@ -304,7 +323,7 @@ class CrudMapper {
query.page = result.page + 1;
collection.link('next', `${ctx.router.url(this.listRoute)}?${queryString.stringify(query)}`);

if (result.hasOwnProperty('page_count') && result.page < result.page_count - 1) {
if (Object.prototype.hasOwnProperty.call(result, 'page_count') && result.page < result.page_count - 1) {
query.page = result.page_count;
collection.link('last', `${ctx.router.url(this.listRoute)}?${queryString.stringify(query)}`);
}
Expand All @@ -315,7 +334,7 @@ class CrudMapper {

toDatabase(entity) {
const data = entity;
if (data.hasOwnProperty('id')) {
if (Object.prototype.hasOwnProperty.call(data, 'id')) {
data._id = data.id;
delete data.id;
}
Expand Down Expand Up @@ -352,7 +371,7 @@ class CrudMapper {
return Uuid.v4c();
}

getUUID() {
static getUUID() {
return CrudMapper.generateUuid();
}

Expand All @@ -362,16 +381,18 @@ class CrudMapper {
* @param {[type]} key Data key name where Date type must be set on
*/
setDates(data, key) {
for (const x in data) {
Object.keys(data).forEach((x) => {
if (typeof data[x] === 'object') {
this.setDates(data[x], key);
} else {
const dateComparisonOperators = ['$gt', '$gte', '$lt', '$lte', '$ne', '$eq', '$in', '$nin'];
if ((key === x || dateComparisonOperators.indexOf(x) > -1) && moment(data[x], moment.ISO_8601, true).isValid()) {
if ((key === x || dateComparisonOperators.indexOf(x) > -1)
&& moment(data[x], moment.ISO_8601, true).isValid()) {
// eslint-disable-next-line no-param-reassign
data[x] = new Date(data[x]);
}
}
}
});
}

/**
Expand All @@ -381,32 +402,14 @@ class CrudMapper {
* @return {[type]} [description]
*/
checkDates(schemaProperties, data) {
for (const k in schemaProperties) {
Object.keys(schemaProperties).forEach((k) => {
if (typeof schemaProperties[k] === 'object' && schemaProperties[k].type && schemaProperties[k].type === 'array') {
this.checkDates(schemaProperties[k].items.properties, data);
this.checkDates(schemaProperties[k].items.properties || {}, data);
} else if (schemaProperties[k].instanceOf && schemaProperties[k].instanceOf === 'Date') {
this.setDates(data, k);
}
}
}
}

function createQueryFilter(schema) {
if (schema.hasOwnProperty('searchable') === false) {
schema.searchable = Object.keys(schema.properties);
});
}
const whitelist = { after: 1, before: 1, between: 1 };
schema.searchable.forEach((key) => {
whitelist[key] = 1;
});
return new MongoQF({
custom: {
between: 'updatedAt',
after: 'updatedAt',
before: 'updatedAt',
},
whitelist,
});
}

module.exports = CrudMapper;
26 changes: 17 additions & 9 deletions src/crud/mongodb-query-filter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

module.exports = function MongoQF(options) {
const opts = options || {};

Expand Down Expand Up @@ -53,7 +52,8 @@ module.exports.prototype.customBBOX = (field) => (query, bbox) => {
bboxArr[2] = parseFloat(bboxArr[2], 10);
bboxArr[3] = parseFloat(bboxArr[3], 10);

if (!isNaN(bboxArr.reduce((a, b) => a + b))) {
if (!Number.isNaN(bboxArr.reduce((a, b) => a + b))) {
// eslint-disable-next-line no-param-reassign
query[field] = {
$geoWithin: {
$geometry: {
Expand All @@ -76,10 +76,11 @@ module.exports.prototype.customNear = (field) => (query, point) => {
const pointArr = point.split(',').map((p) => parseFloat(p, 10));

if (pointArr.length >= 2) {
if (!isNaN(pointArr.reduce((a, b) => a + b))) {
if (!Number.isNaN(pointArr.reduce((a, b) => a + b))) {
const max = pointArr[2];
const min = pointArr[3];

// eslint-disable-next-line no-param-reassign
query[field] = {
$near: {
$geometry: {
Expand All @@ -89,10 +90,12 @@ module.exports.prototype.customNear = (field) => (query, point) => {
},
};

if (!isNaN(max)) {
if (!Number.isNaN(max)) {
// eslint-disable-next-line no-param-reassign
query[field].$near.$maxDistance = max;

if (!isNaN(min)) {
if (!Number.isNaN(min)) {
// eslint-disable-next-line no-param-reassign
query[field].$near.$minDistance = min;
}
}
Expand All @@ -103,7 +106,7 @@ module.exports.prototype.customNear = (field) => (query, point) => {
function parseDate(value) {
let date = value;

if (!isNaN(date)) {
if (!Number.isNaN(date)) {
if (`${date}`.length === 10) {
date = `${date}000`;
}
Expand All @@ -116,6 +119,7 @@ function parseDate(value) {
module.exports.prototype.customAfter = (field) => (query, value) => {
const date = parseDate(value);
if (date.toString() !== 'Invalid Date') {
// eslint-disable-next-line no-param-reassign
query[field] = {
$gte: date,
};
Expand All @@ -126,6 +130,7 @@ module.exports.prototype.customBefore = (field) => (query, value) => {
const date = parseDate(value);

if (date.toString() !== 'Invalid Date') {
// eslint-disable-next-line no-param-reassign
query[field] = {
$lt: date,
};
Expand All @@ -141,6 +146,7 @@ module.exports.prototype.customBetween = (field) => (query, value) => {
const before = parseDate(beforeValue);

if (after.toString() !== 'Invalid Date' && before.toString() !== 'Invalid Date') {
// eslint-disable-next-line no-param-reassign
query[field] = {
$gte: after,
$lt: before,
Expand Down Expand Up @@ -192,8 +198,10 @@ module.exports.prototype.parseString = function parseString(string, array) {
}
break;
default:
ret.org = org = op + org;
ret.op = op = '';
org = op + org;
op = '';
ret.org = org;
ret.op = '';
ret.value = this.parseStringVal(org);

if (array) {
Expand Down Expand Up @@ -221,7 +229,7 @@ module.exports.prototype.parseStringVal = function parseStringVal(string) {
return true;
} if (this.string.toBoolean && string.toLowerCase() === 'false') {
return false;
} if (this.string.toNumber && !isNaN(parseInt(string, 10))
} if (this.string.toNumber && !Number.isNaN(parseInt(string, 10))
&& ((+string - +string) + 1) >= 0) {
return parseFloat(string, 10);
}
Expand Down

0 comments on commit 1be0ec8

Please sign in to comment.