diff --git a/client/src/api.ts b/client/src/api.ts index 3ec1933..f119434 100644 --- a/client/src/api.ts +++ b/client/src/api.ts @@ -7,23 +7,38 @@ // a request structure, a response structure and // a checking function which determines request validity. +export enum ItemType { + Song = 0, + Artist, + Album, + Tag +} + export interface ArtistDetails { - id: Number, + artistId: Number, name: String, storeLinks?: String[], } export interface TagDetails { - id: Number, + tagId: Number, name: String, parent?: TagDetails, storeLinks?: String[], } +export interface RankingDetails { + rankingId: Number, + type: ItemType, // The item type being ranked + rankedId: Number, // The item being ranked + context: ArtistDetails | TagDetails, + value: Number, // The ranking (higher = better) +} export interface SongDetails { - id: Number, + songId: Number, title: String, artists?: ArtistDetails[], tags?: TagDetails[], storeLinks?: String[], + rankings?: RankingDetails[], } // Query for items (POST). diff --git a/client/src/components/ItemList.tsx b/client/src/components/ItemList.tsx index 422224d..2a1ec18 100644 --- a/client/src/components/ItemList.tsx +++ b/client/src/components/ItemList.tsx @@ -17,7 +17,9 @@ export default function ItemList(props:any) { return (
- {props.children} + {props.children.map((child: any) => { + return child; + })}
); diff --git a/server/app.ts b/server/app.ts index 101981f..3eb1619 100644 --- a/server/app.ts +++ b/server/app.ts @@ -4,7 +4,6 @@ import * as api from '../client/src/api'; import { CreateSongEndpointHandler } from './endpoints/CreateSongEndpointHandler'; import { CreateArtistEndpointHandler } from './endpoints/CreateArtistEndpointHandler'; import { QueryEndpointHandler } from './endpoints/QueryEndpointHandler'; -import { QueryArtistsEndpointHandler } from './endpoints/QueryArtistsEndpointHandler'; import { ArtistDetailsEndpointHandler } from './endpoints/ArtistDetailsEndpointHandler' import { SongDetailsEndpointHandler } from './endpoints/SongDetailsEndpointHandler'; import { ModifyArtistEndpointHandler } from './endpoints/ModifyArtistEndpointHandler'; diff --git a/server/endpoints/QueryArtistsEndpointHandler.ts b/server/endpoints/QueryArtistsEndpointHandler.ts deleted file mode 100644 index d521935..0000000 --- a/server/endpoints/QueryArtistsEndpointHandler.ts +++ /dev/null @@ -1,28 +0,0 @@ -const models = require('../models'); -import * as api from '../../client/src/api'; -import { EndpointError, EndpointHandler, catchUnhandledErrors } from './types'; - -export const QueryArtistsEndpointHandler: EndpointHandler = async (req: any, res: any) => { - if (!api.checkQueryArtistsRequest(req.body)) { - const e: EndpointError = { - internalMessage: 'Invalid QueryArtists request: ' + JSON.stringify(req.body), - httpStatus: 400 - }; - throw e; - } - const reqObject: api.QueryArtistsRequest = req.body; - - await models.Artist.findAll({ - offset: reqObject.offset, - limit: reqObject.limit, - }) - .then((artists: any[]) => { - const response: api.QueryArtistsResponse = { - ids: artists.map((artist: any) => { - return artist.id - }) - } - res.send(response); - }) - .catch(catchUnhandledErrors); -} \ No newline at end of file diff --git a/server/endpoints/QueryEndpointHandler.ts b/server/endpoints/QueryEndpointHandler.ts index f293845..b7a2f33 100644 --- a/server/endpoints/QueryEndpointHandler.ts +++ b/server/endpoints/QueryEndpointHandler.ts @@ -81,7 +81,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any) // NOTE: have to disable limit and offset because of bug: https://github.com/sequelize/sequelize/issues/11938. // Custom pagination is implemented before responding. where: getSequelizeWhere(reqObject.query, QueryType.Song), - include: [models.Artist, models.Album, models.Tag], + include: [models.Artist, models.Album, models.Tag, models.Ranking], //limit: reqObject.limit, //offset: reqObject.offset, }) @@ -104,36 +104,49 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any) const response: api.QueryResponse = { songs: (reqObject.songLimit <= 0) ? [] : await Promise.all(songs.map(async (song: any) => { - const artists = await song.getArtists(); - const tags = await song.getTags(); + const artists = song.getArtists(); + const tags = song.getTags(); + const rankings = song.getRankings(); return { - id: song.id, + songId: song.id, title: song.title, storeLinks: song.storeLinks, - artists: artists.map((artist: any) => { + artists: (await artists).map((artist: any) => { return { - id: artist.id, + artistId: artist.id, name: artist.name, } }), - tags: tags.map((tag: any) => { + tags: (await tags).map((tag: any) => { return { - id: tag.id, + tagId: tag.id, name: tag.name, } }), + rankings: await (await rankings).map(async (ranking: any) => { + const maybeTagContext: api.TagDetails | undefined = await ranking.getTagContext(); + const maybeArtistContext: api.ArtistDetails | undefined = await ranking.getArtistContext(); + const maybeContext = maybeTagContext || maybeArtistContext; + return { + rankingId: ranking.id, + type: api.ItemType.Song, + rankedId: song.id, + context: maybeContext, + value: ranking.value, + } + }) }; }).slice(reqObject.songOffset, reqObject.songOffset + reqObject.songLimit)), // TODO: custom pagination due to bug mentioned above artists: (reqObject.artistLimit <= 0) ? [] : await Promise.all(artists.map(async (artist: any) => { return { - id: artist.id, + artistId: artist.id, name: artist.name, }; }).slice(reqObject.artistOffset, reqObject.artistOffset + reqObject.artistLimit)), tags: (reqObject.tagLimit <= 0) ? [] : await Promise.all(tags.map(async (tag: any) => { return { - id: tag.id, + tagId: tag.id, name: tag.name, }; }).slice(reqObject.tagOffset, reqObject.tagOffset + reqObject.tagLimit)), diff --git a/server/models/ranking.js b/server/models/ranking.js new file mode 100644 index 0000000..d15a74e --- /dev/null +++ b/server/models/ranking.js @@ -0,0 +1,13 @@ +module.exports = (sequelize, DataTypes) => { + var Ranking = sequelize.define('Ranking', { + rank: DataTypes.DOUBLE + }); + + Ranking.associate = function (models) { + models.Ranking.hasOne(models.Tag, { as: 'tagContext' }); + models.Ranking.hasOne(models.Artist, { as: 'artistContext' }); + models.Ranking.belongsToMany(models.Song, { through: 'SongRankings' }); + }; + + return Ranking; +}; \ No newline at end of file diff --git a/server/models/song.js b/server/models/song.js index f21785d..0f0e965 100644 --- a/server/models/song.js +++ b/server/models/song.js @@ -8,6 +8,7 @@ module.exports = (sequelize, DataTypes) => { models.Song.belongsToMany(models.Artist, { through: "SongArtists" }); models.Song.belongsToMany(models.Album, { through: "SongAlbums" }); models.Song.belongsToMany(models.Tag, { through: 'SongTags' }); + models.Song.belongsToMany(models.Ranking, { through: 'SongRankings'}); }; return Song;