const models = require('../models'); const { Op } = require("sequelize"); import * as api from '../../client/src/api'; import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; const sequelizeOps: any = { [api.SongQueryFilterOp.Eq]: Op.eq, [api.SongQueryFilterOp.Ne]: Op.ne, [api.SongQueryFilterOp.In]: Op.in, [api.SongQueryFilterOp.NotIn]: Op.notIn, [api.SongQueryElemOp.And]: Op.and, [api.SongQueryElemOp.Or]: Op.or, }; const sequelizeProps: any = { [api.SongQueryElemProperty.id]: "id", [api.SongQueryElemProperty.artistIds]: "$Artists.id$", [api.SongQueryElemProperty.albumIds]: "$Albums.id$", }; // Returns the "where" clauses for Sequelize, per object type. const getSequelizeWhere = (queryElem: api.SongQueryElem) => { var where: any = { [Op.and]: [] }; if (queryElem.prop && queryElem.propOperator && queryElem.propOperand) { // Visit a filter-like subquery leaf. where[Op.and].push({ [sequelizeProps[queryElem.prop]]: { [sequelizeOps[queryElem.propOperator]]: queryElem.propOperand } }); } if (queryElem.childrenOperator && queryElem.children) { // Recursively visit a nested subquery. const children = queryElem.children.map((child: api.SongQueryElem) => getSequelizeWhere(child)); where[Op.and].push({ [sequelizeOps[queryElem.childrenOperator]]: children }); } return where; } export const QuerySongsEndpointHandler: EndpointHandler = async (req: any, res: any) => { if (!api.checkQuerySongsRequest(req)) { const e: EndpointError = { internalMessage: 'Invalid QuerySongs request: ' + JSON.stringify(req.body), httpStatus: 400 }; throw e; } const reqObject: api.QuerySongsRequest = req.body; await models.Song.findAll({ where: getSequelizeWhere(reqObject.query), include: [models.Artist, models.Album] }) .then((songs: any[]) => { const response: api.QuerySongsResponse = { ids: songs.map((song: any) => { return song.id; }) }; res.send(response); }) .catch(catchUnhandledErrors); }