Expand query to support different levels of response detail.

editsong
Sander Vocke 5 years ago
parent 1148bc6bff
commit c28db21b18
  1. 17
      client/src/api.ts
  2. 63
      server/endpoints/Query.ts
  3. 93
      server/test/integration/flows/QueryFlow.js

@ -88,7 +88,12 @@ export enum QueryElemProperty {
albumStoreLinks = "albumStoreLinks", //Note: treated as a JSON string for filter operations
}
export enum OrderByType {
Name = 0,
Name = 'name',
}
export enum QueryResponseType {
Details = 'details', // Returns detailed result items.
Ids = 'ids', // Returns IDs only.
Count = 'count', // Returns an item count only.
}
export interface QueryElem {
prop?: QueryElemProperty,
@ -108,12 +113,13 @@ export interface QueryRequest {
query: Query,
offsetsLimits: OffsetsLimits,
ordering: Ordering,
responseType: QueryResponseType
}
export interface QueryResponse {
songs: SongDetails[],
artists: ArtistDetails[],
tags: TagDetails[],
albums: AlbumDetails[],
songs: SongDetails[] | number[] | number, // Details | IDs | count, depending on QueryResponseType
artists: ArtistDetails[] | number[] | number,
tags: TagDetails[] | number[] | number,
albums: AlbumDetails[] | number[] | number,
}
export interface OffsetsLimits {
songOffset?: number,
@ -141,6 +147,7 @@ export function checkQueryRequest(req: any): boolean {
return 'query' in req
&& 'offsetsLimits' in req
&& 'ordering' in req
&& 'responseType' in req
&& checkQueryElem(req.query);
}

@ -220,7 +220,7 @@ function constructQuery(knex: Knex, userId: number, queryFor: ObjectType, queryE
(ordering.ascending ? 'asc' : 'desc'));
// Apply limiting.
if(limit !== null) {
if (limit !== null) {
q = q.limit(limit)
}
@ -383,20 +383,53 @@ export const Query: EndpointHandler = async (req: any, res: any, knex: Knex) =>
songsAlbumsPromise,
]);
const response: api.QueryResponse = {
songs: songs.map((song: any) => {
const id = song['songs.id'];
return toApiSong(song, songsArtists[id], songsTags[id], songsAlbums[id]);
}),
artists: artists.map((artist: any) => {
return toApiArtist(artist);
}),
albums: albums.map((album: any) => {
return toApiAlbum(album);
}),
tags: tags.map((tag: any) => {
return toApiTag(tag);
}),
var response: api.QueryResponse = {
songs: [],
artists: [],
albums: [],
tags: [],
};
switch (reqObject.responseType) {
case api.QueryResponseType.Details: {
response = {
songs: songs.map((song: any) => {
const id = song['songs.id'];
return toApiSong(song, songsArtists[id], songsTags[id], songsAlbums[id]);
}),
artists: artists.map((artist: any) => {
return toApiArtist(artist);
}),
albums: albums.map((album: any) => {
return toApiAlbum(album);
}),
tags: tags.map((tag: any) => {
return toApiTag(tag);
}),
};
break;
}
case api.QueryResponseType.Ids: {
response = {
songs: songs.map((song: any) => song['songs.id']),
artists: artists.map((artist: any) => artist['artists.id']),
albums: albums.map((album: any) => album['albums.id']),
tags: tags.map((tag: any) => tag['tags.id']),
};
break;
}
case api.QueryResponseType.Count: {
response = {
songs: songs.length,
artists: artists.length,
albums: albums.length,
tags: tags.length,
};
break;
}
default: {
throw new Error("Unimplemented response type.")
}
}
console.log("Query repsonse", response);

@ -39,10 +39,11 @@ describe('POST /query with no songs', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
expect(res).to.have.status(200);
expect(res.body).to.deep.equal({
@ -114,10 +115,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -145,10 +147,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -176,10 +179,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -207,10 +211,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -248,10 +253,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -279,10 +285,11 @@ describe('POST /query with several songs and filters', () => {
},
'ordering': {
'orderBy': {
'type': 0,
'type': 'name',
},
'ascending': true
}
},
'responseType': 'details',
})
.then((res) => {
expect(res).to.have.status(200);
@ -295,6 +302,62 @@ describe('POST /query with several songs and filters', () => {
});
}
async function checkResponseTypeIds(req) {
await req
.post('/query')
.send({
"query": {},
'offsetsLimits': {
'songOffset': 0,
'songLimit': 10,
},
'ordering': {
'orderBy': {
'type': 'name',
},
'ascending': true
},
'responseType': 'ids',
})
.then((res) => {
expect(res).to.have.status(200);
expect(res.body).to.deep.equal({
songs: [song1.songId, song2.songId, song3.songId],
artists: [],
tags: [],
albums: [],
});
});
}
async function checkResponseTypeCount(req) {
await req
.post('/query')
.send({
"query": {},
'offsetsLimits': {
'songOffset': 0,
'songLimit': 10,
},
'ordering': {
'orderBy': {
'type': 'name',
},
'ascending': true
},
'responseType': 'count',
})
.then((res) => {
expect(res).to.have.status(200);
expect(res.body).to.deep.equal({
songs: 3,
artists: 0,
tags: 0,
albums: 0,
});
});
}
let agent = await init();
let req = agent.keepOpen();
try {
@ -309,6 +372,8 @@ describe('POST /query with several songs and filters', () => {
await checkArtistIdIn(req);
await checkOrRelation(req);
await checkStoreLinksLike(req);
await checkResponseTypeCount(req);
await checkResponseTypeIds(req);
} finally {
req.close();
agent.close();

Loading…
Cancel
Save