Skip to content

Commit

Permalink
✨ Support for sorting #59
Browse files Browse the repository at this point in the history
Closes #59
  • Loading branch information
Ovi committed May 23, 2024
1 parent 3c6a792 commit d93f7ac
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 34 deletions.
25 changes: 19 additions & 6 deletions src/controllers/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ const {
getMultiObjectSubset,
getObjectSubset,
limitArray,
sortArray,
} = require('../utils/util');

const controller = {};

// get all posts
controller.getAllPosts = ({ limit, skip, select }) => {
let [...posts] = frozenData.posts;
controller.getAllPosts = _options => {
const { limit, skip, select, sortBy, order } = _options;

let { posts } = frozenData;
const total = posts.length;

posts = sortArray(posts, sortBy, order);

if (skip > 0) {
posts = posts.slice(skip);
}
Expand All @@ -29,12 +34,16 @@ controller.getAllPosts = ({ limit, skip, select }) => {
};

// search posts
controller.searchPosts = ({ limit, skip, select, q: searchQuery }) => {
let [...posts] = frozenData.posts.filter(p => {
controller.searchPosts = ({ q: searchQuery, ..._options }) => {
const { limit, skip, select, sortBy, order } = _options;

let posts = frozenData.posts.filter(p => {
return p.body.toLowerCase().includes(searchQuery);
});
const total = posts.length;

posts = sortArray(posts, sortBy, order);

if (skip > 0) {
posts = posts.slice(skip);
}
Expand Down Expand Up @@ -62,12 +71,16 @@ controller.getPostById = ({ id, select }) => {
};

// get posts by userId
controller.getPostsByUserId = ({ userId, limit, skip, select }) => {
controller.getPostsByUserId = ({ userId, ..._options }) => {
const { limit, skip, select, sortBy, order } = _options;

verifyUserHandler(userId);

let [...posts] = frozenData.posts.filter(p => p.userId.toString() === userId);
let posts = frozenData.posts.filter(p => p.userId.toString() === userId);
const total = posts.length;

posts = sortArray(posts, sortBy, order);

if (skip > 0) {
posts = posts.slice(skip);
}
Expand Down
21 changes: 15 additions & 6 deletions src/controllers/product.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ const {
getMultiObjectSubset,
getObjectSubset,
limitArray,
sortArray,
} = require('../utils/util');

const controller = {};

// get all products
controller.getAllProducts = ({ limit, skip, select }) => {
let [...products] = frozenData.products;
controller.getAllProducts = ({ limit, skip, select, sortBy, order }) => {
let products = [...frozenData.products];
const total = products.length;

products = sortArray(products, sortBy, order);

if (skip > 0) {
products = products.slice(skip);
}
Expand All @@ -29,15 +32,19 @@ controller.getAllProducts = ({ limit, skip, select }) => {
};

// search products
controller.searchProducts = ({ limit, skip, select, q: searchQuery }) => {
let [...products] = frozenData.products.filter(p => {
controller.searchProducts = _options => {
const { limit, skip, select, q: searchQuery, sortBy, order } = _options;

let products = frozenData.products.filter(p => {
return (
p.title.toLowerCase().includes(searchQuery) ||
p.description.toLowerCase().includes(searchQuery)
);
});
const total = products.length;

products = sortArray(products, sortBy, order);

if (skip > 0) {
products = products.slice(skip);
}
Expand Down Expand Up @@ -82,13 +89,15 @@ controller.getProductById = ({ id, select }) => {

// get products by categoryName
controller.getProductsByCategoryName = ({ categoryName = '', ..._options }) => {
const { limit, skip, select } = _options;
const { limit, skip, select, sortBy, order } = _options;

let [...products] = frozenData.products.filter(
let products = frozenData.products.filter(
p => p.category.toLowerCase() === categoryName.toLowerCase(),
);
const total = products.length;

products = sortArray(products, sortBy, order);

if (skip > 0) {
products = products.slice(skip);
}
Expand Down
27 changes: 19 additions & 8 deletions src/controllers/recipes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@ const {
getMultiObjectSubset,
getObjectSubset,
limitArray,
sortArray,
} = require('../utils/util');

const controller = {};

// get all recipes
controller.getAllRecipes = ({ limit, skip, select }) => {
let [...recipes] = frozenData.recipes;
controller.getAllRecipes = _options => {
const { limit, skip, select, sortBy, order } = _options;

let { recipes } = frozenData;
const total = recipes.length;

recipes = sortArray(recipes, sortBy, order);

if (skip > 0) {
recipes = recipes.slice(skip);
}
Expand All @@ -29,12 +34,16 @@ controller.getAllRecipes = ({ limit, skip, select }) => {
};

// search recipes
controller.searchRecipes = ({ limit, skip, select, q: searchQuery }) => {
let [...recipes] = frozenData.recipes.filter(r => {
controller.searchRecipes = ({ q: searchQuery, ..._options }) => {
const { limit, skip, select, sortBy, order } = _options;

let recipes = frozenData.recipes.filter(r => {
return r.name.toLowerCase().includes(searchQuery);
});
const total = recipes.length;

recipes = sortArray(recipes, sortBy, order);

if (skip > 0) {
recipes = recipes.slice(skip);
}
Expand Down Expand Up @@ -78,7 +87,7 @@ controller.getRecipeTags = () => {

// get recipes by tag
controller.getRecipesByTag = ({ tag, ..._options }) => {
const { limit, skip, select } = _options;
const { limit, skip, select, sortBy, order } = _options;

if (!tag) {
throw new APIError(`Tag is required`, 400);
Expand All @@ -87,9 +96,10 @@ controller.getRecipesByTag = ({ tag, ..._options }) => {
let recipes = frozenData.recipes.filter(r => {
return r.tags.some(t => t.toLowerCase() === tag.toLowerCase());
});

const total = recipes.length;

recipes = sortArray(recipes, sortBy, order);

if (skip > 0) {
recipes = recipes.slice(skip);
}
Expand All @@ -107,7 +117,7 @@ controller.getRecipesByTag = ({ tag, ..._options }) => {

// get recipes by meal type
controller.getRecipesByMealType = ({ mealType, ..._options }) => {
const { limit, skip, select } = _options;
const { limit, skip, select, sortBy, order } = _options;

if (!mealType) {
throw new APIError(`Meal type is required`, 400);
Expand All @@ -116,9 +126,10 @@ controller.getRecipesByMealType = ({ mealType, ..._options }) => {
let recipes = frozenData.recipes.filter(r => {
return r.mealType.some(t => t.toLowerCase() === mealType.toLowerCase());
});

const total = recipes.length;

recipes = sortArray(recipes, sortBy, order);

if (skip > 0) {
recipes = recipes.slice(skip);
}
Expand Down
26 changes: 19 additions & 7 deletions src/controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ const {
getObjectSubset,
getNestedValue,
limitArray,
sortArray,
} = require('../utils/util');

const controller = {};

// get all users
controller.getAllUsers = ({ limit, skip, select }) => {
let [...users] = frozenData.users;
controller.getAllUsers = _options => {
const { limit, skip, select, sortBy, order } = _options;

let users = [...frozenData.users];
const total = users.length;

users = sortArray(users, sortBy, order);

if (skip > 0) {
users = users.slice(skip);
}
Expand All @@ -30,8 +35,10 @@ controller.getAllUsers = ({ limit, skip, select }) => {
};

// search users
controller.searchUsers = ({ limit, skip, select, q: searchQuery }) => {
let [...users] = frozenData.users.filter(u => {
controller.searchUsers = ({ q: searchQuery, ..._options }) => {
const { limit, skip, select, sortBy, order } = _options;

let users = frozenData.users.filter(u => {
return (
u.firstName.toLowerCase().includes(searchQuery) ||
u.lastName.toLowerCase().includes(searchQuery) ||
Expand All @@ -41,6 +48,8 @@ controller.searchUsers = ({ limit, skip, select, q: searchQuery }) => {
});
const total = users.length;

users = sortArray(users, sortBy, order);

if (skip > 0) {
users = users.slice(skip);
}
Expand All @@ -57,14 +66,17 @@ controller.searchUsers = ({ limit, skip, select, q: searchQuery }) => {
};

// filter users
controller.filterUsers = ({ limit, skip, select, key, value }) => {
let [...users] = frozenData.users.filter(u => {
controller.filterUsers = ({ key, value, ..._options }) => {
const { limit, skip, select, sortBy, order } = _options;

let users = frozenData.users.filter(u => {
const val = getNestedValue(u, key);
return val && val.toString() === value;
});

const total = users.length;

users = sortArray(users, sortBy, order);

if (skip > 0) {
users = users.slice(skip);
}
Expand Down
20 changes: 17 additions & 3 deletions src/middleware/cleanRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const cleanRequest = (req, res, next) => {
const options = {};
req._options = options;

const { limit = 30, skip = 0, q, key, value, delay } = req.query;
let { select } = req.query;
const { limit = 30, skip = 0, q, key, value, delay, sortBy } = req.query;
let { select, order } = req.query;

if (!isNumber(limit)) {
throw new APIError('Invalid limit', 400);
Expand Down Expand Up @@ -52,7 +52,7 @@ const cleanRequest = (req, res, next) => {
}
}

let searchQuery = q;
let searchQuery = (q || '').trim().toLowerCase();

if (searchQuery) {
searchQuery = searchQuery
Expand All @@ -61,13 +61,27 @@ const cleanRequest = (req, res, next) => {
.join(' ');
}

if (order && sortBy) {
order = order.toLowerCase();

if (order !== 'asc' && order !== 'desc') {
throw new APIError('order can be: "asc" or "desc"', 400);
}
}

if (sortBy && !order) {
order = 'asc';
}

options.limit = parseInt(limit, 10);
options.skip = parseInt(skip, 10);
options.delay = parseInt(delay, 10);
options.select = select;
options.q = searchQuery;
options.key = key;
options.value = value;
options.sortBy = sortBy;
options.order = order;

if (req.headers['content-type']?.startsWith('multipart/form-data')) {
upload.none()(req, res, next);
Expand Down
3 changes: 1 addition & 2 deletions src/routes/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ router.get('/:id', (req, res) => {
// get posts by userId
router.get('/user/:userId', (req, res) => {
const { userId } = req.params;
const { limit, skip, select } = req._options;

res.send(getPostsByUserId({ userId, limit, skip, select }));
res.send(getPostsByUserId({ userId, ...req._options }));
});

// get comments by postId
Expand Down
26 changes: 26 additions & 0 deletions src/utils/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ utils.deepFreeze = function(obj) {
return obj;
};

utils.deepCopy = obj => {
if (typeof obj !== 'object' || obj === null) {
return obj;
}

const copy = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach(key => {
copy[key] = utils.deepCopy(obj[key]);
});
return copy;
};

utils.getNestedValue = (obj, keys) => {
return keys.split('.').reduce((o, k) => (o || {})[k], obj);
};
Expand All @@ -152,6 +164,20 @@ utils.limitArray = (arr, limit) => {
return limit === 0 || limit > arr.length ? arr : arr.slice(0, limit);
};

utils.sortArray = (arr, sortBy, order) => {
const arrCopy = utils.deepCopy(arr);

const sortedArray = arrCopy.sort((a, b) => {
if (a[sortBy] === b[sortBy]) return 0;
if (order === 'asc') {
return a[sortBy] > b[sortBy] ? 1 : -1;
}
return a[sortBy] < b[sortBy] ? 1 : -1;
});

return sortedArray;
};

utils.capitalize = str => {
return str.charAt(0).toUpperCase() + str.slice(1);
};
Expand Down
Loading

0 comments on commit d93f7ac

Please sign in to comment.