Add album query.

pull/20/head
Sander Vocke 5 years ago
parent f85f3b62b1
commit ff1ec095e1
  1. 3
      client/src/api.ts
  2. 72
      client/src/components/Window.tsx
  3. 18
      client/src/components/querybuilder/QBAddElemMenu.tsx
  4. 28
      client/src/components/querybuilder/QBLeafElem.tsx
  5. 1
      client/src/components/querybuilder/QueryBuilder.tsx
  6. 106
      client/src/lib/query/Getters.tsx
  7. 1
      client/src/lib/query/Query.tsx
  8. 21
      server/endpoints/QueryEndpointHandler.ts

@ -108,6 +108,7 @@ export interface QueryResponse {
songs: SongDetails[],
artists: ArtistDetails[],
tags: TagDetails[],
albums: AlbumDetails[],
}
export interface OffsetsLimits {
songOffset?: number,
@ -116,6 +117,8 @@ export interface OffsetsLimits {
artistLimit?: number,
tagOffset?: number,
tagLimit?: number,
albumOffset?: number,
albumLimit?: number,
}
export function checkQueryElem(elem: any): boolean {
if (elem.childrenOperator && elem.children) {

@ -5,6 +5,7 @@ import QueryBuilder from './querybuilder/QueryBuilder';
import * as serverApi from '../api';
import { SongTable } from './tables/ResultsTable';
import stringifyList from '../lib/stringifyList';
import { getArtists, getSongTitles, getAlbums } from '../lib/query/Getters';
var _ = require('lodash');
const darkTheme = createMuiTheme({
@ -13,76 +14,6 @@ const darkTheme = createMuiTheme({
},
});
export async function getArtists(filter: string) {
const query = filter.length > 0 ? {
prop: serverApi.QueryElemProperty.artistName,
propOperand: filter,
propOperator: serverApi.QueryFilterOp.Like,
} : {};
var q: serverApi.QueryRequest = {
query: query,
offsetsLimits: {
artistOffset: 0,
artistLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
const names: string[] = json.artists.map((elem: any) => { return elem.name; });
return [...new Set(names)];
})();
}
export async function getSongTitles(filter: string) {
const query = filter.length > 0 ? {
prop: serverApi.QueryElemProperty.songTitle,
propOperand: filter,
propOperator: serverApi.QueryFilterOp.Like,
} : {};
var q: serverApi.QueryRequest = {
query: query,
offsetsLimits: {
songOffset: 0,
songLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
const titles: string[] = json.songs.map((elem: any) => { return elem.title; });
return [...new Set(titles)];
})();
}
export default function Window(props: any) {
interface ResultsFor {
for: QueryElem,
@ -160,6 +91,7 @@ export default function Window(props: any) {
requestFunctions={{
getArtists: getArtists,
getSongTitles: getSongTitles,
getAlbums: getAlbums,
}}
/>
</Box>

@ -59,5 +59,23 @@ export function QBAddElemMenu(props: MenuProps) {
style={{ width: 300 }}
/>
</NestedMenuItem>
<NestedMenuItem
label="Album"
parentMenuOpen={Boolean(anchorEl)}
>
<QBSelectWithRequest
label="Name"
getNewOptions={props.requestFunctions.getAlbums}
onSubmit={(s: string, exact: boolean) => {
onClose();
props.onCreateQuery({
a: QueryLeafBy.AlbumName,
leafOp: exact ? QueryLeafOp.Equals : QueryLeafOp.Like,
b: s
});
}}
style={{ width: 300 }}
/>
</NestedMenuItem>
</Menu >
}

@ -51,6 +51,20 @@ export function QBQueryElemTitleLike(props: LeafProps) {
/>
}
export function QBQueryElemAlbumEquals(props: LeafProps) {
return <LabeledElemChip
label={"On \"" + props.elem.b + "\""}
extraElements={props.extraElements}
/>
}
export function QBQueryElemAlbumLike(props: LeafProps) {
return <LabeledElemChip
label={"Album like \"" + props.elem.b + "\""}
extraElements={props.extraElements}
/>
}
export interface DeleteButtonProps {
onClick?: (e: any) => void,
}
@ -97,6 +111,20 @@ export function QBLeafElem(props: IProps) {
{...props}
extraElements={extraElements}
/>
} else if (e.a == QueryLeafBy.AlbumName &&
e.leafOp == QueryLeafOp.Equals &&
typeof e.b == "string") {
return <QBQueryElemAlbumEquals
{...props}
extraElements={extraElements}
/>
} else if (e.a == QueryLeafBy.AlbumName &&
e.leafOp == QueryLeafOp.Like &&
typeof e.b == "string") {
return <QBQueryElemAlbumLike
{...props}
extraElements={extraElements}
/>
} if (e.a == QueryLeafBy.SongTitle &&
e.leafOp == QueryLeafOp.Equals &&
typeof e.b == "string") {

@ -7,6 +7,7 @@ import { QueryElem, addPlaceholders, removePlaceholders, simplify } from '../../
export interface Requests {
getArtists: (filter: string) => Promise<string[]>,
getAlbums: (filter: string) => Promise<string[]>,
getSongTitles: (filter: string) => Promise<string[]>,
}

@ -0,0 +1,106 @@
import * as serverApi from '../../api';
export async function getArtists(filter: string) {
const query = filter.length > 0 ? {
prop: serverApi.QueryElemProperty.artistName,
propOperand: filter,
propOperator: serverApi.QueryFilterOp.Like,
} : {};
var q: serverApi.QueryRequest = {
query: query,
offsetsLimits: {
artistOffset: 0,
artistLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
const names: string[] = json.artists.map((elem: any) => { return elem.name; });
return [...new Set(names)];
})();
}
export async function getAlbums(filter: string) {
const query = filter.length > 0 ? {
prop: serverApi.QueryElemProperty.albumName,
propOperand: filter,
propOperator: serverApi.QueryFilterOp.Like,
} : {};
var q: serverApi.QueryRequest = {
query: query,
offsetsLimits: {
albumOffset: 0,
albumLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
const names: string[] = json.albums.map((elem: any) => { return elem.name; });
return [...new Set(names)];
})();
}
export async function getSongTitles(filter: string) {
const query = filter.length > 0 ? {
prop: serverApi.QueryElemProperty.songTitle,
propOperand: filter,
propOperator: serverApi.QueryFilterOp.Like,
} : {};
var q: serverApi.QueryRequest = {
query: query,
offsetsLimits: {
songOffset: 0,
songLimit: 100,
},
ordering: {
orderBy: {
type: serverApi.OrderByType.Name,
},
ascending: true,
},
};
const requestOpts = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(q),
};
return (async () => {
const response = await fetch((process.env.REACT_APP_BACKEND || "") + serverApi.QueryEndpoint, requestOpts)
let json: any = await response.json();
const titles: string[] = json.songs.map((elem: any) => { return elem.title; });
return [...new Set(titles)];
})();
}

@ -157,6 +157,7 @@ export function toApiQuery(q: QueryElem) : serverApi.Query {
const propsMapping: any = {
[QueryLeafBy.SongTitle]: serverApi.QueryElemProperty.songTitle,
[QueryLeafBy.ArtistName]: serverApi.QueryElemProperty.artistName,
[QueryLeafBy.AlbumName]: serverApi.QueryElemProperty.albumName,
}
const leafOpsMapping: any = {
[QueryLeafOp.Equals]: serverApi.QueryFilterOp.Eq,

@ -248,6 +248,8 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
const tagOffset = reqObject.offsetsLimits.tagOffset;
const artistLimit = reqObject.offsetsLimits.artistLimit;
const artistOffset = reqObject.offsetsLimits.artistOffset;
const albumLimit = reqObject.offsetsLimits.albumLimit;
const albumOffset = reqObject.offsetsLimits.albumOffset;
const artistsPromise: Promise<any> = (artistLimit && artistLimit > 0) ?
constructQuery(knex,
@ -259,6 +261,16 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
) :
(async () => [])();
const albumsPromise: Promise<any> = (albumLimit && albumLimit > 0) ?
constructQuery(knex,
ObjectType.Album,
reqObject.query,
reqObject.ordering,
artistOffset || 0,
albumLimit
) :
(async () => [])();
const songsPromise: Promise<any> = (songLimit && songLimit > 0) ?
constructQuery(knex,
ObjectType.Song,
@ -306,6 +318,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
const [
songs,
artists,
albums,
tags,
songsArtists,
songsTags,
@ -314,6 +327,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
await Promise.all([
songsPromise,
artistsPromise,
albumsPromise,
tagsPromise,
songsArtistsPromise,
songsTagsPromise,
@ -355,6 +369,13 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
storeLinks: asJson(artist['artists.storeLinks']),
}
}),
albums: albums.map((album: any) => {
return <api.AlbumDetails>{
albumId: album['albums.id'],
name: album['albums.name'],
storeLinks: asJson(album['albums.storeLinks']),
}
}),
tags: tags.map((tag: any) => {
return <api.TagDetails>{
tagId: tag['tags.id'],

Loading…
Cancel
Save