Added internal GraphQL client, using GraphQL for scenes API.

This commit is contained in:
DebaucheryLibrarian
2021-02-27 03:52:27 +01:00
parent 162e5c2181
commit 2deed3a7eb
6 changed files with 220 additions and 108 deletions

View File

@@ -5,7 +5,78 @@ const inquirer = require('inquirer');
const logger = require('./logger')(__filename);
const knex = require('./knex');
const { flushOrphanedMedia } = require('./media');
const { HttpError } = require('./errors');
const { graphql } = require('./web/graphql');
const releaseFields = `
id
entryId
shootId
title
url
date
description
duration
entity {
id
name
slug
parent {
id
name
slug
}
}
actors: releasesActors {
actor {
id
name
slug
gender
aliasFor
entityId
entryId
}
}
tags: releasesTags {
tag {
id
name
slug
}
}
chapters @include (if: $full) {
id
index
time
duration
title
description
}
poster: releasesPosterByReleaseId {
media {
id
path
thumbnail
s3: isS3
width
height
size
}
}
photos: releasesPhotos @include (if: $full) {
media {
id
path
thumbnail
s3: isS3
width
height
size
}
}
createdAt
`;
function curateRelease(release, withMedia = false, withPoster = true) {
if (!release) {
@@ -81,93 +152,100 @@ function curateRelease(release, withMedia = false, withPoster = true) {
};
}
function withRelations(queryBuilder, withMedia = false, withPoster = true) {
queryBuilder
.select(knex.raw(`
releases.id, releases.entry_id, releases.shoot_id, releases.title, releases.url, releases.date, releases.description, releases.duration, releases.created_at,
row_to_json(entities) as entity,
row_to_json(parents) as parent,
COALESCE(json_agg(DISTINCT actors) FILTER (WHERE actors.id IS NOT NULL), '[]') as actors,
COALESCE(json_agg(DISTINCT tags) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
COALESCE(json_agg(DISTINCT chapters) FILTER (WHERE chapters.id IS NOT NULL), '[]') as chapters
`))
.leftJoin('entities', 'entities.id', 'releases.entity_id')
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
.leftJoin('releases_actors', 'releases_actors.release_id', 'releases.id')
.leftJoin('actors', 'actors.id', 'releases_actors.actor_id')
.leftJoin('releases_tags', 'releases_tags.release_id', 'releases.id')
.leftJoin('tags', 'tags.id', 'releases_tags.tag_id')
.leftJoin('chapters', 'chapters.release_id', 'releases.id')
.groupBy(knex.raw(`
releases.id, releases.entry_id, releases.shoot_id, releases.title, releases.url, releases.date, releases.description, releases.duration, releases.created_at,
entities.id, parents.id
`));
if (withMedia || withPoster) {
queryBuilder
.select(knex.raw(`
row_to_json(posters) as poster
`))
.leftJoin('releases_posters', 'releases_posters.release_id', 'releases.id')
.leftJoin('media as posters', 'posters.id', 'releases_posters.media_id')
.groupBy('posters.id');
function curateGraphqlRelease(release) {
if (!release) {
return null;
}
if (withMedia) {
queryBuilder
.select(knex.raw(`
row_to_json(trailers) as trailer,
COALESCE(json_agg(DISTINCT photos) FILTER (WHERE photos.id IS NOT NULL), '[]') as photos
`))
.leftJoin('releases_photos', 'releases_photos.release_id', 'releases.id')
.leftJoin('media as photos', 'photos.id', 'releases_photos.media_id')
.leftJoin('releases_trailers', 'releases_trailers.release_id', 'releases.id')
.leftJoin('media as trailers', 'trailers.id', 'releases_trailers.media_id')
.groupBy('posters.id', 'trailers.id');
}
return {
id: release.id,
...(release.relevance && { relevance: release.relevance }),
entryId: release.entryId,
shootId: release.shootId,
title: release.title || null,
url: release.url || null,
date: release.date,
description: release.description || null,
duration: release.duration,
entity: release.entity,
actors: release.actors.map(actor => actor.actor),
tags: release.tags.map(tag => tag.tag),
...(release.chapters && { chapters: release.chapters }),
poster: release.poster?.media || null,
...(release.photos && { photos: release.photos.map(photo => photo.media) }),
trailer: release.trailer?.media || null,
createdAt: release.createdAt,
};
}
async function fetchScene(releaseId) {
const release = await knex('releases')
.where('releases.id', releaseId)
.modify(withRelations, true, true)
.first();
const { release } = await graphql(`
query Release(
$releaseId: Int!
$full: Boolean = true
) {
release(id: $releaseId) {
${releaseFields}
}
}
`, {
releaseId: Number(releaseId),
});
return curateRelease(release, true);
return curateGraphqlRelease(release);
}
async function fetchScenes(limit = 100) {
if (typeof limit !== 'number') {
throw new HttpError('Limit parameter needs to be a number', 400);
}
const { releases } = await graphql(`
query SearchReleases(
$limit: Int = 20
$full: Boolean = false
) {
releases(
first: $limit
orderBy: DATE_DESC
) {
${releaseFields}
}
}
`, {
limit: Math.min(limit, 10000),
});
const releases = await knex('releases')
.modify(withRelations, false, true)
.limit(Math.min(limit, 1000000));
return releases.map(release => curateRelease(release));
return releases.map(release => curateGraphqlRelease(release));
}
async function searchScenes(query, limit = 100, relevance = 0) {
if (typeof limit !== 'number') {
throw new HttpError('Limit parameter needs to be a number', 400);
}
const { releases } = await graphql(`
query SearchReleases(
$query: String!
$limit: Int = 20
$relevance: Float = 0.025
$full: Boolean = false
) {
releases: searchReleases(
query: $query
first: $limit
orderBy: RANK_DESC
filter: {
rank: {
greaterThan: $relevance
}
}
) {
rank
release {
${releaseFields}
}
}
}
`, {
query,
limit,
relevance,
});
if (typeof relevance !== 'number') {
throw new HttpError('Relevance parameter needs to be a number', 400);
}
const releases = await knex
.select(knex.raw('search_results.rank as relevance'))
.from(knex.raw('search_releases(:query) as search_results', { query }))
.leftJoin('releases', 'releases.id', 'search_results.release_id')
.where('search_results.rank', '>=', relevance)
.modify(withRelations, false, true)
.limit(Math.min(limit, 1000000))
.groupBy('search_results.rank')
.orderBy('search_results.rank', 'desc');
return releases.map(release => curateRelease(release));
return releases.map(release => curateGraphqlRelease({ ...release.release, relevance: release.rank }));
}
async function deleteScenes(sceneIds) {