'use strict'; const knex = require('./knex'); const whereOr = require('./utils/where-or'); async function curateTag(tag) { const [aliases, media] = await Promise.all([ knex('tags').where({ alias_for: tag.id }), knex('media') .where('domain', 'tags') .andWhere('target_id', tag.id) .orderBy('index'), ]); return { id: tag.id, name: tag.name, slug: tag.slug, description: tag.description, poster: media.find(photo => photo.role === 'poster'), photos: media.filter(photo => photo.role === 'photo'), group: { id: tag.group_id, name: tag.group_name, description: tag.group_description, slug: tag.group_slug, }, aliases: aliases.map(({ name }) => name), }; } function curateTags(tags) { return Promise.all(tags.map(async tag => curateTag(tag))); } async function matchTags(rawTags) { const tags = rawTags .concat(rawTags.map(tag => tag.toLowerCase())) .concat(rawTags.map(tag => tag.toUpperCase())); const tagEntries = await knex('tags') .pluck('aliases.id') .whereIn('tags.name', tags) .where(function where() { this .whereNull('tags.alias_for') .orWhereNull('aliases.alias_for'); }) .join('tags as aliases', function join() { this .on('tags.alias_for', 'aliases.id') .orOn('tags.id', 'aliases.id'); }) .groupBy('aliases.id'); return tagEntries; } async function associateTags(release, releaseId) { if (!release.tags || release.tags.length === 0) { console.warn(`No tags available for (${release.site.name}, ${releaseId}) "${release.title}"`); return; } const tags = release.tags.some(tag => typeof tag === 'string') ? await matchTags(release.tags) // scraper returned raw tags : release.tags; // tags already matched by (outdated) scraper const associationEntries = await knex('tags_associated') .where({ domain: 'releases', target_id: releaseId, }) .whereIn('tag_id', tags); const existingAssociations = new Set(associationEntries.map(association => association.tag_id)); const newAssociations = tags.filter(tagId => !existingAssociations.has(tagId)); await knex('tags_associated').insert(newAssociations.map(tagId => ({ tag_id: tagId, domain: 'releases', target_id: releaseId, }))); } async function fetchTags(queryObject, groupsQueryObject, limit = 100) { const tags = await knex('tags') .where(builder => whereOr(queryObject, 'tags', builder)) .orWhere(builder => whereOr(groupsQueryObject, 'tags_groups', builder)) .andWhere({ 'tags.alias_for': null }) .select( 'tags.*', 'tags_groups.id as group_id', 'tags_groups.name as group_name', 'tags_groups.slug as group_slug', 'tags_groups.description as groups_description', ) .leftJoin('tags_groups', 'tags.group_id', 'tags_groups.id') .orderBy('name') .limit(limit); return curateTags(tags); } module.exports = { associateTags, fetchTags, matchTags, };