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 request structure, a response structure and
// a checking function which determines request validity. // a checking function which determines request validity.
export enum ItemType {
Song = 0,
Artist,
Album,
Tag
}
export interface ArtistDetails { export interface ArtistDetails {
id: Number, artistId: Number,
name: String, name: String,
storeLinks?: String[], storeLinks?: String[],
} }
export interface TagDetails { export interface TagDetails {
id: Number, tagId: Number,
name: String, name: String,
parent?: TagDetails, parent?: TagDetails,
storeLinks?: String[], 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 { export interface SongDetails {
id: Number, songId: Number,
title: String, title: String,
artists?: ArtistDetails[], artists?: ArtistDetails[],
tags?: TagDetails[], tags?: TagDetails[],
storeLinks?: String[], storeLinks?: String[],
rankings?: RankingDetails[],
} }
// Query for items (POST). // Query for items (POST).

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

@ -4,7 +4,6 @@ import * as api from '../client/src/api';
import { CreateSongEndpointHandler } from './endpoints/CreateSongEndpointHandler'; import { CreateSongEndpointHandler } from './endpoints/CreateSongEndpointHandler';
import { CreateArtistEndpointHandler } from './endpoints/CreateArtistEndpointHandler'; import { CreateArtistEndpointHandler } from './endpoints/CreateArtistEndpointHandler';
import { QueryEndpointHandler } from './endpoints/QueryEndpointHandler'; import { QueryEndpointHandler } from './endpoints/QueryEndpointHandler';
import { QueryArtistsEndpointHandler } from './endpoints/QueryArtistsEndpointHandler';
import { ArtistDetailsEndpointHandler } from './endpoints/ArtistDetailsEndpointHandler' import { ArtistDetailsEndpointHandler } from './endpoints/ArtistDetailsEndpointHandler'
import { SongDetailsEndpointHandler } from './endpoints/SongDetailsEndpointHandler'; import { SongDetailsEndpointHandler } from './endpoints/SongDetailsEndpointHandler';
import { ModifyArtistEndpointHandler } from './endpoints/ModifyArtistEndpointHandler'; 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. // NOTE: have to disable limit and offset because of bug: https://github.com/sequelize/sequelize/issues/11938.
// Custom pagination is implemented before responding. // Custom pagination is implemented before responding.
where: getSequelizeWhere(reqObject.query, QueryType.Song), 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, //limit: reqObject.limit,
//offset: reqObject.offset, //offset: reqObject.offset,
}) })
@ -104,36 +104,49 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any)
const response: api.QueryResponse = { const response: api.QueryResponse = {
songs: (reqObject.songLimit <= 0) ? [] : await Promise.all(songs.map(async (song: any) => { songs: (reqObject.songLimit <= 0) ? [] : await Promise.all(songs.map(async (song: any) => {
const artists = await song.getArtists(); const artists = song.getArtists();
const tags = await song.getTags(); const tags = song.getTags();
const rankings = song.getRankings();
return <api.SongDetails>{ return <api.SongDetails>{
id: song.id, songId: song.id,
title: song.title, title: song.title,
storeLinks: song.storeLinks, storeLinks: song.storeLinks,
artists: artists.map((artist: any) => { artists: (await artists).map((artist: any) => {
return <api.ArtistDetails>{ return <api.ArtistDetails>{
id: artist.id, artistId: artist.id,
name: artist.name, name: artist.name,
} }
}), }),
tags: tags.map((tag: any) => { tags: (await tags).map((tag: any) => {
return <api.TagDetails>{ return <api.TagDetails>{
id: tag.id, tagId: tag.id,
name: tag.name, 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)), }).slice(reqObject.songOffset, reqObject.songOffset + reqObject.songLimit)),
// TODO: custom pagination due to bug mentioned above // TODO: custom pagination due to bug mentioned above
artists: (reqObject.artistLimit <= 0) ? [] : await Promise.all(artists.map(async (artist: any) => { artists: (reqObject.artistLimit <= 0) ? [] : await Promise.all(artists.map(async (artist: any) => {
return <api.ArtistDetails>{ return <api.ArtistDetails>{
id: artist.id, artistId: artist.id,
name: artist.name, name: artist.name,
}; };
}).slice(reqObject.artistOffset, reqObject.artistOffset + reqObject.artistLimit)), }).slice(reqObject.artistOffset, reqObject.artistOffset + reqObject.artistLimit)),
tags: (reqObject.tagLimit <= 0) ? [] : await Promise.all(tags.map(async (tag: any) => { tags: (reqObject.tagLimit <= 0) ? [] : await Promise.all(tags.map(async (tag: any) => {
return <api.TagDetails>{ return <api.TagDetails>{
id: tag.id, tagId: tag.id,
name: tag.name, name: tag.name,
}; };
}).slice(reqObject.tagOffset, reqObject.tagOffset + reqObject.tagLimit)), }).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.Artist, { through: "SongArtists" });
models.Song.belongsToMany(models.Album, { through: "SongAlbums" }); models.Song.belongsToMany(models.Album, { through: "SongAlbums" });
models.Song.belongsToMany(models.Tag, { through: 'SongTags' }); models.Song.belongsToMany(models.Tag, { through: 'SongTags' });
models.Song.belongsToMany(models.Ranking, { through: 'SongRankings'});
}; };
return Song; return Song;

Loading…
Cancel
Save