Split out parsing helpers into proper functions

This commit is contained in:
Elliot DeNolf
2019-01-25 22:14:18 -05:00
parent 0282811bd1
commit 6d185c0cc2
3 changed files with 89 additions and 264 deletions

View File

@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
import {paramParser} from '../utils/paramParser';
@@ -17,6 +18,11 @@ const Page = mongoose.model('Page', PageSchema);
describe('param parser', () => {
describe('Parameter Parsing', () => {
it('No params', () => {
let parsed = paramParser(Page, {});
expect(parsed).toEqual({});
});
it('Property Equals', () => {
let parsed = paramParser(Page, {title: 'This is my title'});
expect(parsed.searchParams).toEqual({title: 'This is my title'});

View File

@@ -7,11 +7,11 @@ export default function apiQueryPlugin(schema) {
const model = this;
const params = paramParser(this, rawParams);
let // Create the Mongoose Query object.
query = model
.find(params.searchParams)
.limit(params.per_page)
.skip((params.page - 1) * params.per_page);
// Create the Mongoose Query object.
let query = model
.find(params.searchParams)
.limit(params.per_page)
.skip((params.page - 1) * params.per_page);
if (params.sort)
query = query.sort(params.sort);
@@ -22,192 +22,4 @@ export default function apiQueryPlugin(schema) {
return query;
}
};
schema.statics.apiQueryParams = function (rawParams) {
const model = this;
const convertToBoolean = str => {
return str.toLowerCase() === 'true' ||
str.toLowerCase() === 't' ||
str.toLowerCase() === 'yes' ||
str.toLowerCase() === 'y' ||
str === '1';
};
//changed
const searchParams = {};
let query;
let page = 1;
let per_page = 100;
let sort = false;
const parseSchemaForKey = (schema, keyPrefix, lcKey, val, operator) => {
let paramType;
const addSearchParam = val => {
const key = keyPrefix + lcKey;
if (typeof searchParams[key] !== 'undefined') {
for (i in val) {
searchParams[key][i] = val[i];
}
} else {
searchParams[key] = val;
}
};
let matches = lcKey.match(/(.+)\.(.+)/);
if (matches) {
// parse subschema
if (schema.paths[matches[1]].constructor.name === 'DocumentArray' ||
schema.paths[matches[1]].constructor.name === 'Mixed') {
parseSchemaForKey(schema.paths[matches[1]].schema, `${matches[1]}.`, matches[2], val, operator)
}
} else if (typeof schema === 'undefined') {
paramType = 'String';
} else if (typeof schema.paths[lcKey] === 'undefined') {
// nada, not found
} else if (operator === 'near') {
paramType = 'Near';
} else if (schema.paths[lcKey].constructor.name === 'SchemaBoolean') {
paramType = 'Boolean';
} else if (schema.paths[lcKey].constructor.name === 'SchemaString') {
paramType = 'String';
} else if (schema.paths[lcKey].constructor.name === 'SchemaNumber') {
paramType = 'Number';
} else if (schema.paths[lcKey].constructor.name === 'ObjectId') {
paramType = 'ObjectId';
}//changed
else if (schema.paths[lcKey].constructor.name === 'SchemaArray') {
paramType = 'Array';
}
console.log('Param Type: ' + paramType);
if (paramType === 'Boolean') {
addSearchParam(convertToBoolean(val));
} else if (paramType === 'Number') {
if (val.match(/([0-9]+,?)/) && val.match(',')) {
if (operator === 'all') {
addSearchParam({ $all: val.split(',') });
} else if (operator === 'nin') {
addSearchParam({ $nin: val.split(',') });
} else if (operator === 'mod') {
addSearchParam({ $mod: [val.split(',')[0], val.split(',')[1]] });
} else {
addSearchParam({ $in: val.split(',') });
}
} else if (val.match(/([0-9]+)/)) {
if (operator === 'gt' ||
operator === 'gte' ||
operator === 'lt' ||
operator === 'lte' ||
operator === 'ne') {
let newParam = {};
newParam[`$${operator}`] = val;
addSearchParam(newParam);
} else {//changed
addSearchParam(parseInt(val));
}
}
} else if (paramType === 'String') {
if (val.match(',')) {
const options = val.split(',').map(str => new RegExp(str, 'i'));
if (operator === 'all') {
addSearchParam({ $all: options });
} else if (operator === 'nin') {
addSearchParam({ $nin: options });
} else {
addSearchParam({ $in: options });
}
} else if (val.match(/([0-9]+)/)) {
if (operator === 'gt' ||
operator === 'gte' ||
operator === 'lt' ||
operator === 'lte') {
let newParam = {};
newParam[`$${operator}`] = val;
addSearchParam(newParam);
} else {
addSearchParam(val);
}
} else if (operator === 'ne' || operator === 'not') {
const neregex = new RegExp(val, 'i');
addSearchParam({ '$not': neregex });
} else if (operator === 'exact') {
addSearchParam(val);
} else {
addSearchParam({ $regex: val, $options: '-i' });
}
} else if (paramType === 'Near') {
// divide by 69 to convert miles to degrees
const latlng = val.split(',');
const distObj = { $near: [parseFloat(latlng[0]), parseFloat(latlng[1])] };
if (typeof latlng[2] !== 'undefined') {
distObj.$maxDistance = parseFloat(latlng[2]) / 69;
}
addSearchParam(distObj);
} else if (paramType === 'ObjectId') {
addSearchParam(val);
} else if (paramType === 'Array') {
addSearchParam(val);
console.log(lcKey)
}
};
const parseParam = (key, val) => {
console.log(key, val);
const lcKey = key;
let operator = val.match(/\{(.*)\}/);
val = val.replace(/\{(.*)\}/, '');
if (operator) operator = operator[1];
if (val === '') {
return;
} else if (lcKey === 'page') {
page = val;
} else if (lcKey === 'per_page' || lcKey === 'limit') {
per_page = parseInt(val);
} else if (lcKey === 'sort_by') {
const parts = val.split(',');
sort = {};
sort[parts[0]] = parts.length > 1 ? parts[1] : 1;
} else {
parseSchemaForKey(model.schema, '', lcKey, val, operator);
}
};
// Construct searchParams
for (const key in rawParams) {
const separatedParams = rawParams[key].match(/\{\w+\}(.[^\{\}]*)/g);
if (separatedParams === null) {
parseParam(key, rawParams[key]);
} else {
for (var i = 0, len = separatedParams.length; i < len; ++i) {
parseParam(key, separatedParams[i]);
}
}
}
let returnVal = {
searchParams,
page,
per_page,
sort
};
console.log(returnVal);
return returnVal;
};
}

View File

@@ -1,34 +1,89 @@
/* eslint-disable no-use-before-define */
export function paramParser(model, rawParams) {
const convertToBoolean = str => {
return str.toLowerCase() === 'true' ||
str.toLowerCase() === 't' ||
str.toLowerCase() === 'yes' ||
str.toLowerCase() === 'y' ||
str === '1';
};
//changed
const searchParams = {};
const searchPageSort = {
page: 1,
per_page: 100,
sort: false
};
let search = {};
let query;
let page = 1;
let per_page = 100;
let sort = false;
// Construct searchParams
for (const key in rawParams) {
const separatedParams = rawParams[key]
.match(/{\w+}(.[^{}]*)/g);
const parseSchemaForKey = (schema, keyPrefix, lcKey, val, operator) => {
if (separatedParams === null) {
console.log('separated params null');
search = parseParam(key, rawParams[key], model, searchParams, searchPageSort);
} else {
for (let i = 0; i < separatedParams.length; ++i) {
search = parseParam(key, separatedParams[i], model, searchParams, searchPageSort);
}
}
}
console.log(search, 'searchparams');
// let returnVal = {
// searchParams,
// ...searchPageSort
// };
//
// console.log(returnVal);
return search;
}
function convertToBoolean(str) {
return str.toLowerCase() === 'true' ||
str.toLowerCase() === 't' ||
str.toLowerCase() === 'yes' ||
str.toLowerCase() === 'y' ||
str === '1';
}
function parseParam (key, val, model, searchParams, searchPageSort) {
console.log(key, val);
const lcKey = key;
let operator = val.match(/\{(.*)\}/);
val = val.replace(/\{(.*)\}/, '');
if (operator) operator = operator[1];
if (val === '') {
// return;
} else if (lcKey === 'page') {
searchPageSort.page = val;
} else if (lcKey === 'per_page' || lcKey === 'limit') {
searchPageSort.per_page = parseInt(val);
} else if (lcKey === 'sort_by') {
const parts = val.split(',');
searchPageSort.sort = {};
searchPageSort.sort[parts[0]] = parts.length > 1 ? parts[1] : 1;
} else {
searchParams = parseSchemaForKey(model.schema, searchParams, '', lcKey, val, operator);
}
return {
searchParams,
...searchPageSort
};
}
function parseSchemaForKey(schema, searchParams, keyPrefix, lcKey, val, operator) {
let paramType;
const addSearchParam = val => {
const addSearchParam = value => {
const key = keyPrefix + lcKey;
if (typeof searchParams[key] !== 'undefined') {
for (let i in val) {
searchParams[key][i] = val[i];
for (let i in value) {
searchParams[key][i] = value[i];
}
} else {
searchParams[key] = val;
searchParams[key] = value;
}
};
@@ -55,7 +110,7 @@ export function paramParser(model, rawParams) {
paramType = 'Number';
} else if (schema.paths[lcKey].constructor.name === 'ObjectId') {
paramType = 'ObjectId';
}//changed
}
else if (schema.paths[lcKey].constructor.name === 'SchemaArray') {
paramType = 'Array';
}
@@ -82,9 +137,9 @@ export function paramParser(model, rawParams) {
operator === 'lte' ||
operator === 'ne') {
let newParam = {};
newParam[`$${operator}`] = val;
newParam['$' + operator] = val;
addSearchParam(newParam);
} else {//changed
} else {
addSearchParam(parseInt(val));
}
}
@@ -105,7 +160,7 @@ export function paramParser(model, rawParams) {
operator === 'lt' ||
operator === 'lte') {
let newParam = {};
newParam[`$${operator}`] = val;
newParam['$' + operator] = val;
addSearchParam(newParam);
} else {
addSearchParam(val);
@@ -124,53 +179,5 @@ export function paramParser(model, rawParams) {
addSearchParam(val);
console.log(lcKey)
}
};
const parseParam = (key, val) => {
console.log(key, val);
const lcKey = key;
let operator = val.match(/\{(.*)\}/);
val = val.replace(/\{(.*)\}/, '');
if (operator) operator = operator[1];
if (val === '') {
return;
} else if (lcKey === 'page') {
page = val;
} else if (lcKey === 'per_page' || lcKey === 'limit') {
per_page = parseInt(val);
} else if (lcKey === 'sort_by') {
const parts = val.split(',');
sort = {};
sort[parts[0]] = parts.length > 1 ? parts[1] : 1;
} else {
parseSchemaForKey(model.schema, '', lcKey, val, operator);
}
};
// Construct searchParams
for (const key in rawParams) {
const separatedParams = rawParams[key]
.match(/{\w+}(.[^{}]*)/g);
if (separatedParams === null) {
parseParam(key, rawParams[key]);
} else {
for (let i = 0; i < separatedParams.length; ++i) {
parseParam(key, separatedParams[i]);
}
}
return searchParams;
}
let returnVal = {
searchParams,
page,
per_page,
sort
};
console.log(returnVal);
return returnVal;
}