2020-06-08 01:41:12 +00:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const config = require('config');
|
|
|
|
|
|
|
|
const argv = require('./argv');
|
|
|
|
const knex = require('./knex');
|
|
|
|
|
|
|
|
function curateEntity(entity, includeParameters = false) {
|
2020-08-13 21:59:54 +00:00
|
|
|
if (!entity) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const curatedEntity = entity.id ? {
|
2020-06-08 01:41:12 +00:00
|
|
|
id: entity.id,
|
|
|
|
name: entity.name,
|
|
|
|
url: entity.url,
|
|
|
|
description: entity.description,
|
|
|
|
slug: entity.slug,
|
2020-06-15 01:58:35 +00:00
|
|
|
type: entity.type,
|
2020-06-08 01:41:12 +00:00
|
|
|
parameters: includeParameters ? entity.parameters : null,
|
2020-09-18 01:27:00 +00:00
|
|
|
parent: curateEntity(entity.parent, includeParameters),
|
2020-08-13 21:59:54 +00:00
|
|
|
} : {};
|
|
|
|
|
|
|
|
if (entity.children) {
|
|
|
|
curatedEntity.children = entity.children.map(child => curateEntity({
|
2020-06-17 02:07:24 +00:00
|
|
|
...child,
|
2020-08-13 21:59:54 +00:00
|
|
|
parent: curatedEntity.id ? curatedEntity : null,
|
|
|
|
}, includeParameters));
|
|
|
|
}
|
2020-06-08 01:41:12 +00:00
|
|
|
|
2020-10-16 21:00:03 +00:00
|
|
|
if (entity.tags) {
|
|
|
|
curatedEntity.tags = entity.tags.map(tag => ({
|
|
|
|
id: tag.id,
|
|
|
|
name: tag.name,
|
|
|
|
slug: tag.slug,
|
|
|
|
priority: tag.priority,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2020-06-08 01:41:12 +00:00
|
|
|
return curatedEntity;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function curateEntities(entities, includeParameters) {
|
|
|
|
return Promise.all(entities.map(async entity => curateEntity(entity, includeParameters)));
|
|
|
|
}
|
|
|
|
|
2020-08-13 22:32:59 +00:00
|
|
|
async function fetchIncludedEntities() {
|
|
|
|
const include = {
|
|
|
|
includeAll: !argv.networks && !argv.channels && !config.include?.networks && !config.include?.channels,
|
|
|
|
includedNetworks: argv.networks || (!argv.channels && config.include?.networks) || [],
|
|
|
|
includedChannels: argv.channels || (!argv.networks && config.include?.channels) || [],
|
|
|
|
excludedNetworks: argv.excludeNetworks || config.exclude?.networks || [],
|
|
|
|
excludedChannels: argv.excludeChannels || config.exclude?.channels || [],
|
|
|
|
};
|
2020-06-08 01:41:12 +00:00
|
|
|
|
2020-07-09 00:00:54 +00:00
|
|
|
const rawNetworks = await knex.raw(`
|
2020-08-13 14:10:58 +00:00
|
|
|
WITH RECURSIVE channels AS (
|
2020-08-13 21:59:54 +00:00
|
|
|
/* select configured channels and networks */
|
2020-08-13 14:10:58 +00:00
|
|
|
SELECT
|
2020-08-13 21:59:54 +00:00
|
|
|
entities.*
|
2020-08-13 14:10:58 +00:00
|
|
|
FROM
|
|
|
|
entities
|
|
|
|
WHERE
|
2020-08-13 21:59:54 +00:00
|
|
|
CASE WHEN :includeAll
|
|
|
|
THEN
|
|
|
|
/* select all top level networks and independent channels */
|
|
|
|
entities.parent_id IS NULL
|
|
|
|
ELSE
|
|
|
|
((entities.slug = ANY(:includedNetworks)
|
|
|
|
AND entities.type = 'network')
|
|
|
|
OR (entities.slug = ANY(:includedChannels)
|
|
|
|
AND entities.type = 'channel'))
|
|
|
|
END
|
|
|
|
AND NOT (
|
|
|
|
(entities.slug = ANY(:excludedNetworks)
|
|
|
|
AND entities.type = 'network')
|
|
|
|
OR (entities.slug = ANY(:excludedChannels)
|
|
|
|
AND entities.type = 'channel'))
|
2020-07-09 00:00:54 +00:00
|
|
|
|
2020-08-13 14:10:58 +00:00
|
|
|
UNION ALL
|
|
|
|
|
|
|
|
/* select recursive children of configured networks */
|
|
|
|
SELECT
|
2020-08-13 21:59:54 +00:00
|
|
|
entities.*
|
2020-08-13 14:10:58 +00:00
|
|
|
FROM
|
|
|
|
entities
|
|
|
|
INNER JOIN
|
|
|
|
channels ON channels.id = entities.parent_id
|
|
|
|
WHERE
|
2020-08-13 21:59:54 +00:00
|
|
|
NOT ((entities.slug = ANY(:excludedNetworks)
|
|
|
|
AND entities.type = 'network')
|
|
|
|
OR (entities.slug = ANY(:excludedChannels)
|
|
|
|
AND entities.type = 'channel'))
|
2020-08-13 14:10:58 +00:00
|
|
|
)
|
|
|
|
/* select recursive channels as children of networks */
|
|
|
|
SELECT
|
2020-08-22 02:22:56 +00:00
|
|
|
entities.*, json_agg(channels ORDER BY channels.id) as children
|
2020-08-13 14:10:58 +00:00
|
|
|
FROM
|
|
|
|
channels
|
|
|
|
LEFT JOIN
|
|
|
|
entities ON entities.id = channels.parent_id
|
|
|
|
WHERE
|
|
|
|
channels.type = 'channel'
|
|
|
|
GROUP BY
|
|
|
|
entities.id
|
2020-08-13 22:32:59 +00:00
|
|
|
`, include);
|
2020-08-13 14:10:58 +00:00
|
|
|
|
2020-08-13 21:59:54 +00:00
|
|
|
const curatedNetworks = rawNetworks.rows.map(entity => curateEntity(entity, true));
|
2020-06-08 01:41:12 +00:00
|
|
|
|
2020-08-13 21:59:54 +00:00
|
|
|
return curatedNetworks;
|
2020-06-08 01:41:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 21:00:03 +00:00
|
|
|
async function fetchEntity(entityId, type) {
|
|
|
|
const entity = await knex('entities')
|
|
|
|
.select(knex.raw(`
|
|
|
|
entities.*,
|
|
|
|
COALESCE(json_agg(children) FILTER (WHERE children.id IS NOT NULL), '[]') as children,
|
|
|
|
COALESCE(json_agg(tags) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
|
|
|
row_to_json(parents) as parent
|
|
|
|
`))
|
|
|
|
.modify((queryBuilder) => {
|
|
|
|
if (Number(entityId)) {
|
|
|
|
queryBuilder.where('entities.id', entityId);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type) {
|
|
|
|
queryBuilder
|
|
|
|
.where('entities.slug', entityId)
|
|
|
|
.where('entities.type', type);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error('Invalid ID or unspecified entity type');
|
|
|
|
})
|
|
|
|
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
|
|
|
.leftJoin('entities as children', 'children.parent_id', 'entities.id')
|
|
|
|
.leftJoin('entities_tags', 'entities_tags.entity_id', 'entities.id')
|
|
|
|
.leftJoin('tags', 'tags.id', 'entities_tags.tag_id')
|
|
|
|
.groupBy('entities.id', 'parents.id')
|
|
|
|
.first();
|
|
|
|
|
|
|
|
return curateEntity(entity);
|
2020-06-08 01:41:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 21:00:03 +00:00
|
|
|
async function fetchEntities(type, limit) {
|
|
|
|
const entities = await knex('entities')
|
|
|
|
.select(knex.raw(`
|
|
|
|
entities.*,
|
|
|
|
COALESCE(json_agg(tags) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
|
|
|
row_to_json(parents) as parent
|
|
|
|
`))
|
|
|
|
.modify((queryBuilder) => {
|
|
|
|
if (type) {
|
|
|
|
queryBuilder.where('entities.type', type);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
|
|
|
.leftJoin('entities_tags', 'entities_tags.entity_id', 'entities.id')
|
|
|
|
.leftJoin('tags', 'tags.id', 'entities_tags.tag_id')
|
|
|
|
.groupBy('entities.id', 'parents.id')
|
|
|
|
.limit(limit || 100);
|
|
|
|
|
|
|
|
return curateEntities(entities);
|
|
|
|
}
|
2020-06-08 01:41:12 +00:00
|
|
|
|
2020-10-16 21:00:03 +00:00
|
|
|
async function searchEntities(query, type, limit) {
|
|
|
|
const entities = await knex
|
|
|
|
.select(knex.raw(`
|
|
|
|
entities.*,
|
|
|
|
COALESCE(json_agg(tags) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
|
|
|
row_to_json(parents) as parent
|
|
|
|
`))
|
|
|
|
.from(knex.raw('search_entities(?) as entities', [query]))
|
|
|
|
.modify((queryBuilder) => {
|
|
|
|
if (type) {
|
|
|
|
queryBuilder.where('entities.type', type);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
|
|
|
.leftJoin('entities_tags', 'entities_tags.entity_id', 'entities.id')
|
|
|
|
.leftJoin('tags', 'tags.id', 'entities_tags.tag_id')
|
|
|
|
.groupBy('entities.id', 'parents.id')
|
|
|
|
.limit(limit || 100);
|
|
|
|
|
|
|
|
return curateEntities(entities);
|
2020-06-08 01:41:12 +00:00
|
|
|
}
|
|
|
|
|
2020-10-16 21:00:03 +00:00
|
|
|
|
2020-06-08 01:41:12 +00:00
|
|
|
module.exports = {
|
|
|
|
curateEntity,
|
|
|
|
curateEntities,
|
|
|
|
fetchIncludedEntities,
|
2020-10-16 21:00:03 +00:00
|
|
|
fetchEntity,
|
|
|
|
fetchEntities,
|
|
|
|
searchEntities,
|
2020-06-08 01:41:12 +00:00
|
|
|
};
|