GladysProject/Gladys

View on GitHub
server/lib/scene/scene.get.js

Summary

Maintainability
A
2 hrs
Test Coverage
const { Op } = require('sequelize');
const Sequelize = require('sequelize');
const intersection = require('lodash.intersection');
const db = require('../../models');

const DEFAULT_OPTIONS = {
  fields: ['id', 'name', 'description', 'icon', 'selector', 'active', 'last_executed', 'updated_at'],
  skip: 0,
  order_dir: 'ASC',
  order_by: 'name',
};

/**
 * @description Get list of scenes.
 * @param {object} [options] - Options of the query.
 * @returns {Promise<Array>} Resolve with list of scenes.
 * @example
 * const scenes = await gladys.scene.get({
 *  take: 20,
 *  skip: 0
 * });
 */
async function get(options) {
  const optionsWithDefault = { ...DEFAULT_OPTIONS, ...options };

  const queryParams = {
    attributes: optionsWithDefault.fields,
    offset: optionsWithDefault.skip,
    order: [[optionsWithDefault.order_by, optionsWithDefault.order_dir]],
    include: [
      {
        model: db.TagScene,
        as: 'tags',
        attributes: ['name'],
      },
    ],
  };

  if (optionsWithDefault.take !== undefined) {
    queryParams.limit = optionsWithDefault.take;
  }

  // search by scene selectors
  if (optionsWithDefault.selectors) {
    queryParams.where = {
      [Op.or]: optionsWithDefault.selectors.split(',').map((selector) => ({
        selector,
      })),
    };
  }

  const where = [];
  if (optionsWithDefault.search) {
    where.push(
      Sequelize.where(Sequelize.fn('lower', Sequelize.col('t_scene.name')), {
        [Op.like]: `%${optionsWithDefault.search}%`,
      }),
    );
  }

  if (optionsWithDefault.searchTags) {
    const tags = optionsWithDefault.searchTags.split(',');

    const sceneIdsAndNames = (
      await db.TagScene.findAll({
        fields: ['name', 'scene_id'],
        where: {
          [Op.or]: tags.map((tag) => ({ name: { [Op.like]: `%${tag}%` } })),
        },
      })
    ).map((tag) => tag.get({ plain: true }));

    const tagsWithSceneId = {};
    sceneIdsAndNames.forEach((sceneIdAndName) => {
      if (sceneIdAndName.name in tagsWithSceneId === false) {
        tagsWithSceneId[sceneIdAndName.name] = [];
      }
      tagsWithSceneId[sceneIdAndName.name].push(sceneIdAndName.scene_id);
    });

    const intersectionSceneId = intersection(...Object.values(tagsWithSceneId));

    where.push({
      [Op.or]: intersectionSceneId.map((sceneId) => ({ id: sceneId })),
    });
  }

  if (where.length > 0) {
    queryParams.where = {
      [Op.and]: where,
    };
  }

  const scenes = await db.Scene.findAll(queryParams);

  return scenes.map((scene) => scene.get({ plain: true }));
}

module.exports = {
  get,
};