Type filters. Starting drag n drop.

pull/7/head
Sander Vocke 5 years ago
parent b282a002b8
commit 98a01bb3ca
  1. 21
      client/src/api.ts
  2. 4
      client/src/components/ItemList.tsx
  3. 1
      server/app.ts
  4. 28
      server/endpoints/QueryArtistsEndpointHandler.ts
  5. 33
      server/endpoints/QueryEndpointHandler.ts
  6. 13
      server/models/ranking.js
  7. 1
      server/models/song.js

@ -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).

@ -17,7 +17,9 @@ export default function ItemList(props:any) {
return (
<div className={classes.root}>
<List dense={true}>
{props.children}
{props.children.map((child: any) => {
return child;
})}
</List>
</div>
);

@ -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';

@ -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);
}

@ -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 <api.SongDetails>{
id: song.id,
songId: song.id,
title: song.title,
storeLinks: song.storeLinks,
artists: artists.map((artist: any) => {
artists: (await artists).map((artist: any) => {
return <api.ArtistDetails>{
id: artist.id,
artistId: artist.id,
name: artist.name,
}
}),
tags: tags.map((tag: any) => {
tags: (await tags).map((tag: any) => {
return <api.TagDetails>{
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 <api.RankingDetails>{
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 <api.ArtistDetails>{
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 <api.TagDetails>{
id: tag.id,
tagId: tag.id,
name: tag.name,
};
}).slice(reqObject.tagOffset, reqObject.tagOffset + reqObject.tagLimit)),

@ -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;
};

@ -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;

Loading…
Cancel
Save