|
|
|
@ -178,7 +178,7 @@ const objectColumns = { |
|
|
|
|
[ObjectType.Tag]: ['tags.id as tags.id', 'tags.name as tags.name', 'tags.parentId as tags.parentId'] |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function constructQuery(knex: Knex, queryFor: ObjectType, queryElem: api.QueryElem, ordering: api.Ordering, |
|
|
|
|
function constructQuery(knex: Knex, userId: number, queryFor: ObjectType, queryElem: api.QueryElem, ordering: api.Ordering, |
|
|
|
|
offset: number, limit: number | null) { |
|
|
|
|
const joinObjects = getRequiredDatabaseObjects(queryElem); |
|
|
|
|
joinObjects.delete(queryFor); // We are already querying this object in the base query.
|
|
|
|
@ -194,6 +194,7 @@ function constructQuery(knex: Knex, queryFor: ObjectType, queryElem: api.QueryEl |
|
|
|
|
|
|
|
|
|
// First, we create a base query for the type of object we need to yield.
|
|
|
|
|
var q = knex.select(columns) |
|
|
|
|
.where({ [objectTables[queryFor] + '.user']: userId }) |
|
|
|
|
.groupBy(objectTables[queryFor] + '.' + 'id') |
|
|
|
|
.from(objectTables[queryFor]); |
|
|
|
|
|
|
|
|
@ -223,7 +224,7 @@ function constructQuery(knex: Knex, queryFor: ObjectType, queryElem: api.QueryEl |
|
|
|
|
return q; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async function getLinkedObjects(knex: Knex, base: ObjectType, linked: ObjectType, baseIds: number[]) { |
|
|
|
|
async function getLinkedObjects(knex: Knex, userId: number, base: ObjectType, linked: ObjectType, baseIds: number[]) { |
|
|
|
|
var result: Record<number, any[]> = {}; |
|
|
|
|
const otherTable = objectTables[linked]; |
|
|
|
|
const linkingTable = getLinkingTable(base, linked); |
|
|
|
@ -232,6 +233,7 @@ async function getLinkedObjects(knex: Knex, base: ObjectType, linked: ObjectType |
|
|
|
|
await Promise.all(baseIds.map((baseId: number) => { |
|
|
|
|
return knex.select(columns).groupBy(otherTable + '.id').from(otherTable) |
|
|
|
|
.join(linkingTable, { [linkingTable + '.' + linkingTableIdNames[linked]]: otherTable + '.id' }) |
|
|
|
|
.where({ [otherTable + '.user']: userId }) |
|
|
|
|
.where({ [linkingTable + '.' + linkingTableIdNames[base]]: baseId }) |
|
|
|
|
.then((others: any) => { result[baseId] = others; }) |
|
|
|
|
})) |
|
|
|
@ -241,11 +243,12 @@ async function getLinkedObjects(knex: Knex, base: ObjectType, linked: ObjectType |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Resolve a tag into the full nested structure of its ancestors.
|
|
|
|
|
async function getFullTag(knex: Knex, tag: any): Promise<any> { |
|
|
|
|
async function getFullTag(knex: Knex, userId: number, tag: any): Promise<any> { |
|
|
|
|
const resolveTag = async (t: any) => { |
|
|
|
|
if (t['tags.parentId']) { |
|
|
|
|
const parent = (await knex.select(objectColumns[ObjectType.Tag]) |
|
|
|
|
.from('tags') |
|
|
|
|
.where({ 'user': userId }) |
|
|
|
|
.where({ [objectTables[ObjectType.Tag] + '.id']: t['tags.parentId'] }))[0]; |
|
|
|
|
t.parent = await resolveTag(parent); |
|
|
|
|
} |
|
|
|
@ -264,7 +267,9 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
throw e; |
|
|
|
|
} |
|
|
|
|
const reqObject: api.QueryRequest = req.body; |
|
|
|
|
console.log("Query: ", reqObject); |
|
|
|
|
const { id: userId } = req.user; |
|
|
|
|
|
|
|
|
|
console.log("User ", userId, ": Query ", reqObject); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
const songLimit = reqObject.offsetsLimits.songLimit; |
|
|
|
@ -278,6 +283,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
|
|
|
|
|
const artistsPromise: Promise<any> = (artistLimit && artistLimit !== 0) ? |
|
|
|
|
constructQuery(knex, |
|
|
|
|
userId, |
|
|
|
|
ObjectType.Artist, |
|
|
|
|
reqObject.query, |
|
|
|
|
reqObject.ordering, |
|
|
|
@ -288,6 +294,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
|
|
|
|
|
const albumsPromise: Promise<any> = (albumLimit && albumLimit !== 0) ? |
|
|
|
|
constructQuery(knex, |
|
|
|
|
userId, |
|
|
|
|
ObjectType.Album, |
|
|
|
|
reqObject.query, |
|
|
|
|
reqObject.ordering, |
|
|
|
@ -298,6 +305,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
|
|
|
|
|
const songsPromise: Promise<any> = (songLimit && songLimit !== 0) ? |
|
|
|
|
constructQuery(knex, |
|
|
|
|
userId, |
|
|
|
|
ObjectType.Song, |
|
|
|
|
reqObject.query, |
|
|
|
|
reqObject.ordering, |
|
|
|
@ -308,6 +316,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
|
|
|
|
|
const tagsPromise: Promise<any> = (tagLimit && tagLimit !== 0) ? |
|
|
|
|
constructQuery(knex, |
|
|
|
|
userId, |
|
|
|
|
ObjectType.Tag, |
|
|
|
|
reqObject.query, |
|
|
|
|
reqObject.ordering, |
|
|
|
@ -325,18 +334,18 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
})(); |
|
|
|
|
const songsArtistsPromise: Promise<Record<number, any[]>> = (songLimit && songLimit !== 0) ? |
|
|
|
|
(async () => { |
|
|
|
|
return await getLinkedObjects(knex, ObjectType.Song, ObjectType.Artist, await songIdsPromise); |
|
|
|
|
return await getLinkedObjects(knex, userId, ObjectType.Song, ObjectType.Artist, await songIdsPromise); |
|
|
|
|
})() : |
|
|
|
|
(async () => { return {}; })(); |
|
|
|
|
const songsTagsPromise: Promise<Record<number, any[]>> = (songLimit && songLimit !== 0) ? |
|
|
|
|
(async () => { |
|
|
|
|
const tagsPerSong: Record<number, any> = await getLinkedObjects(knex, ObjectType.Song, ObjectType.Tag, await songIdsPromise); |
|
|
|
|
const tagsPerSong: Record<number, any> = await getLinkedObjects(knex, userId, ObjectType.Song, ObjectType.Tag, await songIdsPromise); |
|
|
|
|
var result: Record<number, any> = {}; |
|
|
|
|
for (var key in tagsPerSong) { |
|
|
|
|
const tags = tagsPerSong[key]; |
|
|
|
|
var fullTags: any[] = []; |
|
|
|
|
for (var idx in tags) { |
|
|
|
|
fullTags.push(await getFullTag(knex, tags[idx])); |
|
|
|
|
fullTags.push(await getFullTag(knex, userId, tags[idx])); |
|
|
|
|
} |
|
|
|
|
result[key] = fullTags; |
|
|
|
|
} |
|
|
|
@ -345,7 +354,7 @@ export const QueryEndpointHandler: EndpointHandler = async (req: any, res: any, |
|
|
|
|
(async () => { return {}; })(); |
|
|
|
|
const songsAlbumsPromise: Promise<Record<number, any[]>> = (songLimit && songLimit !== 0) ? |
|
|
|
|
(async () => { |
|
|
|
|
return await getLinkedObjects(knex, ObjectType.Song, ObjectType.Album, await songIdsPromise); |
|
|
|
|
return await getLinkedObjects(knex, userId, ObjectType.Song, ObjectType.Album, await songIdsPromise); |
|
|
|
|
})() : |
|
|
|
|
(async () => { return {}; })(); |
|
|
|
|
|
|
|
|
|