diff --git a/client/src/api.ts b/client/src/api.ts
index 812ad32..3ef33f7 100644
--- a/client/src/api.ts
+++ b/client/src/api.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) {
diff --git a/client/src/components/Window.tsx b/client/src/components/Window.tsx
index 52856da..3b13f01 100644
--- a/client/src/components/Window.tsx
+++ b/client/src/components/Window.tsx
@@ -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,
}}
/>
diff --git a/client/src/components/querybuilder/QBAddElemMenu.tsx b/client/src/components/querybuilder/QBAddElemMenu.tsx
index b0fc151..acce42d 100644
--- a/client/src/components/querybuilder/QBAddElemMenu.tsx
+++ b/client/src/components/querybuilder/QBAddElemMenu.tsx
@@ -59,5 +59,23 @@ export function QBAddElemMenu(props: MenuProps) {
style={{ width: 300 }}
/>
+
+ {
+ onClose();
+ props.onCreateQuery({
+ a: QueryLeafBy.AlbumName,
+ leafOp: exact ? QueryLeafOp.Equals : QueryLeafOp.Like,
+ b: s
+ });
+ }}
+ style={{ width: 300 }}
+ />
+
}
diff --git a/client/src/components/querybuilder/QBLeafElem.tsx b/client/src/components/querybuilder/QBLeafElem.tsx
index f4904ea..d772b7e 100644
--- a/client/src/components/querybuilder/QBLeafElem.tsx
+++ b/client/src/components/querybuilder/QBLeafElem.tsx
@@ -51,6 +51,20 @@ export function QBQueryElemTitleLike(props: LeafProps) {
/>
}
+export function QBQueryElemAlbumEquals(props: LeafProps) {
+ return
+}
+
+export function QBQueryElemAlbumLike(props: LeafProps) {
+ return
+}
+
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
+ } else if (e.a == QueryLeafBy.AlbumName &&
+ e.leafOp == QueryLeafOp.Like &&
+ typeof e.b == "string") {
+ return
} if (e.a == QueryLeafBy.SongTitle &&
e.leafOp == QueryLeafOp.Equals &&
typeof e.b == "string") {
diff --git a/client/src/components/querybuilder/QueryBuilder.tsx b/client/src/components/querybuilder/QueryBuilder.tsx
index dc73d57..25fab68 100644
--- a/client/src/components/querybuilder/QueryBuilder.tsx
+++ b/client/src/components/querybuilder/QueryBuilder.tsx
@@ -7,6 +7,7 @@ import { QueryElem, addPlaceholders, removePlaceholders, simplify } from '../../
export interface Requests {
getArtists: (filter: string) => Promise,
+ getAlbums: (filter: string) => Promise,
getSongTitles: (filter: string) => Promise,
}
diff --git a/client/src/lib/query/Getters.tsx b/client/src/lib/query/Getters.tsx
new file mode 100644
index 0000000..56c4f33
--- /dev/null
+++ b/client/src/lib/query/Getters.tsx
@@ -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)];
+ })();
+}
\ No newline at end of file
diff --git a/client/src/lib/query/Query.tsx b/client/src/lib/query/Query.tsx
index ad617b3..75f86e8 100644
--- a/client/src/lib/query/Query.tsx
+++ b/client/src/lib/query/Query.tsx
@@ -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,
diff --git a/server/endpoints/QueryEndpointHandler.ts b/server/endpoints/QueryEndpointHandler.ts
index 3be1197..6b37ea3 100644
--- a/server/endpoints/QueryEndpointHandler.ts
+++ b/server/endpoints/QueryEndpointHandler.ts
@@ -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 = (artistLimit && artistLimit > 0) ?
constructQuery(knex,
@@ -259,6 +261,16 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any,
) :
(async () => [])();
+ const albumsPromise: Promise = (albumLimit && albumLimit > 0) ?
+ constructQuery(knex,
+ ObjectType.Album,
+ reqObject.query,
+ reqObject.ordering,
+ artistOffset || 0,
+ albumLimit
+ ) :
+ (async () => [])();
+
const songsPromise: Promise = (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 {
+ albumId: album['albums.id'],
+ name: album['albums.name'],
+ storeLinks: asJson(album['albums.storeLinks']),
+ }
+ }),
tags: tags.map((tag: any) => {
return {
tagId: tag['tags.id'],