Skip to content

Commit

Permalink
feat: Add name filter to GraphQL endpoint (#325)
Browse files Browse the repository at this point in the history
* feat: Add name filter to GraphQL endpoint

* Make it easier to update filters in the future

* Make contains string resolver more generic

* Inline filters
  • Loading branch information
SleeplessOne1917 authored Aug 19, 2022
1 parent 3c7fe47 commit af69524
Show file tree
Hide file tree
Showing 15 changed files with 478 additions and 177 deletions.
10 changes: 7 additions & 3 deletions src/graphql/resolvers/abilityScoreResolver.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import SkillModel from '../../models/skill/index.js';
import { getMongoSortDirection } from './common.js';
import { coalesceFilters, getMongoSortDirection, resolveContainsStringFilter } from './common.js';

const AbilityScoreResolver = {
skills: async (abilityScore, args) => {
const search = { index: { $in: abilityScore.skills.map(s => s.index) } };
const filters = [{ index: { $in: abilityScore.skills.map(s => s.index) } }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

const sort = {};
if (args.order_direction) {
sort.name = getMongoSortDirection(args.order_direction);
}

return await SkillModel.find(search)
return await SkillModel.find(coalesceFilters(filters))
.sort(sort)
.lean();
},
Expand Down
35 changes: 26 additions & 9 deletions src/graphql/resolvers/backgroundResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,41 @@ import EquipmentCategoryModel from '../../models/equipmentCategory/index.js';
import EquipmentModel from '../../models/equipment/index.js';
import LanguageModel from '../../models/language/index.js';
import ProficiencyModel from '../../models/proficiency/index.js';
import { resolveChoice } from './common.js';
import { coalesceFilters, resolveChoice, resolveContainsStringFilter } from './common.js';

const Background = {
starting_equipment: async background => {
starting_equipment: async (background, args) => {
const starting_equipment = background.starting_equipment;
const equipment = await EquipmentModel.find({
index: { $in: starting_equipment.map(se => se.equipment.index) },
}).lean();
const filters = [
{
index: { $in: starting_equipment.map(se => se.equipment.index) },
},
];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

const equipment = await EquipmentModel.find(coalesceFilters(filters)).lean();

return starting_equipment.map(se => ({
...se,
equipment: equipment.find(e => e.index === se.equipment.index),
}));
},
starting_proficiencies: async background =>
await ProficiencyModel.find({
index: { $in: background.starting_proficiencies.map(sp => sp.index) },
}).lean(),
starting_proficiencies: async (background, args) => {
const filters = [
{
index: { $in: background.starting_proficiencies.map(sp => sp.index) },
},
];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

return await ProficiencyModel.find(coalesceFilters(filters)).lean();
},
language_options: async background =>
resolveChoice(
background.language_options,
Expand Down
33 changes: 28 additions & 5 deletions src/graphql/resolvers/classResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import EquipmentModel from '../../models/equipment/index.js';
import LevelModel from '../../models/level/index.js';
import ProficiencyModel from '../../models/proficiency/index.js';
import SubclassModel from '../../models/subclass/index.js';
import { resolveChoice, resolveSpells } from './common.js';
import {
coalesceFilters,
resolveChoice,
resolveContainsStringFilter,
resolveSpells,
} from './common.js';

const resolveEquipmentOption = async option => {
if (option.option_type === 'counted_reference') {
Expand Down Expand Up @@ -36,8 +41,19 @@ const resolveEquipmentOption = async option => {
};

const Class = {
proficiencies: async klass =>
await ProficiencyModel.find({ index: { $in: klass.proficiencies.map(p => p.index) } }).lean(),
proficiencies: async (klass, args) => {
const filters = [
{
index: { $in: klass.proficiencies.map(p => p.index) },
},
];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

return await ProficiencyModel.find(coalesceFilters(filters)).lean();
},
saving_throws: async klass =>
await AbilityScoreModel.find({
index: { $in: klass.saving_throws.map(st => st.index) },
Expand Down Expand Up @@ -65,8 +81,15 @@ const Class = {
}));
},
class_levels: async klass => await LevelModel.find({ 'class.index': klass.index }).lean(),
subclasses: async klass =>
await SubclassModel.find({ index: { $in: klass.subclasses.map(s => s.index) } }).lean(),
subclasses: async (klass, args) => {
const filters = [{ index: { $in: klass.subclasses.map(s => s.index) } }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

return await SubclassModel.find(coalesceFilters(filters)).lean();
},
multi_classing: async klass => {
const multiclassingToReturn = {};
const { multi_classing } = klass;
Expand Down
42 changes: 20 additions & 22 deletions src/graphql/resolvers/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,69 +39,63 @@ const resolveSpellOrderBy = value =>

export const resolveSpells = async (args, baseFilters) => {
const filters = [...baseFilters];
if (args.school) {
const filter = { 'school.index': { $in: args.school } };
if (args.name) {
const filter = resolveContainsStringFilter(args.name);
filters.push(filter);
}

if (args.school) {
filters.push({ 'school.index': { $in: args.school } });
}

if (args.level) {
filters.push(resolveNumberFilter(args.level, 'level'));
}

if (args.class) {
const filter = { classes: { $elemMatch: { index: { $in: args.class } } } };
filters.push(filter);
filters.push({ classes: { $elemMatch: { index: { $in: args.class } } } });
}

if (args.subclass) {
const filter = { subclasses: { $elemMatch: { index: { $in: args.subclass } } } };
filters.push(filter);
filters.push({ subclasses: { $elemMatch: { index: { $in: args.subclass } } } });
}

if (args.concentration !== undefined) {
const filter = { concentration: args.concentration };
filters.push(filter);
filters.push({ concentration: args.concentration });
}

if (args.ritual !== undefined) {
const filter = { ritual: args.ritual };
filters.push(filter);
filters.push({ ritual: args.ritual });
}

if (args.attack_type) {
const filter = { attack_type: { $in: args.attack_type } };
filters.push(filter);
filters.push({ attack_type: { $in: args.attack_type } });
}

if (args.casting_time) {
const filter = { casting_time: { $in: args.casting_time } };
filters.push(filter);
filters.push({ casting_time: { $in: args.casting_time } });
}

if (args.area_of_effect) {
const { area_of_effect } = args;
if (area_of_effect.type) {
const filter = { 'area_of_effect.type': { $in: area_of_effect.type } };
filters.push(filter);
filters.push({ 'area_of_effect.type': { $in: area_of_effect.type } });
}
if (area_of_effect.size) {
filters.push(resolveNumberFilter(area_of_effect.size, 'area_of_effect.size'));
}
}

if (args.damage_type) {
const filter = { 'damage.damage_type.index': { $in: args.damage_type } };
filters.push(filter);
filters.push({ 'damage.damage_type.index': { $in: args.damage_type } });
}

if (args.dc_type) {
const filter = { 'dc.dc_type.index': { $in: args.dc_type } };
filters.push(filter);
filters.push({ 'dc.dc_type.index': { $in: args.dc_type } });
}

if (args.range) {
const filter = { range: { $in: args.range } };
filters.push(filter);
filters.push({ range: { $in: args.range } });
}

let sort = {};
Expand Down Expand Up @@ -221,3 +215,7 @@ export const resolveAreaOfEffect = areaOfEffect => ({
...areaOfEffect,
type: areaOfEffect.type.toUpperCase(),
});

export const resolveContainsStringFilter = (val, prop = 'name') => ({
[prop]: new RegExp(val, 'i'),
});
12 changes: 9 additions & 3 deletions src/graphql/resolvers/equipmentCategoryResolver.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import EquipmentModel from '../../models/equipment/index.js';
import MagicItemModel from '../../models/magicItem/index.js';
import { coalesceSort } from './common.js';
import { coalesceFilters, coalesceSort, resolveContainsStringFilter } from './common.js';

const EquipmentCategory = {
equipment: async (equipmentCategory, args) => {
const indexes = equipmentCategory.equipment.map(e => e.index);
const equipment = await EquipmentModel.find({ index: { $in: indexes } }).lean();
const magicItems = await MagicItemModel.find({ index: { $in: indexes } }).lean();
const filters = [{ index: { $in: indexes } }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

const equipment = await EquipmentModel.find(coalesceFilters(filters)).lean();
const magicItems = await MagicItemModel.find(coalesceFilters(filters)).lean();
const equipmentToReturn = equipment.concat(magicItems);

let sort = {};
Expand Down
10 changes: 8 additions & 2 deletions src/graphql/resolvers/levelResolver.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import ClassModel from '../../models/class/index.js';
import FeatureModel from '../../models/feature/index.js';
import SubclassModel from '../../models/subclass/index.js';
import { getMongoSortDirection } from './common.js';
import { coalesceFilters, getMongoSortDirection, resolveContainsStringFilter } from './common.js';

const Level = {
class: async level => await ClassModel.findOne({ index: level.class.index }).lean(),
subclass: async level =>
level.subclass ? await SubclassModel.findOne({ index: level.subclass.index }).lean() : null,
features: async (level, args) => {
const sort = {};
const filters = [{ index: { $in: level.features.map(f => f.index) } }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

if (args.order_direction) {
sort.name = getMongoSortDirection(args.order_direction);
}

return await FeatureModel.find({ index: { $in: level.features.map(f => f.index) } })
return await FeatureModel.find(coalesceFilters(filters))
.sort(sort)
.lean();
},
Expand Down
24 changes: 19 additions & 5 deletions src/graphql/resolvers/proficiencyResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,31 @@ import EquipmentModel from '../../models/equipment/index.js';
import RaceModel from '../../models/race/index.js';
import SkillModel from '../../models/skill/index.js';
import SubraceModel from '../../models/subrace/index.js';
import { coalesceFilters, resolveContainsStringFilter } from './common.js';

const Proficiency = {
classes: async proficiency =>
await ClassModel.find({ index: { $in: proficiency.classes.map(c => c.index) } }).lean(),
races: async proficiency => {
classes: async (proficiency, args) => {
const filters = [{ index: { $in: proficiency.classes.map(c => c.index) } }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

return await ClassModel.find(coalesceFilters(filters)).lean();
},
races: async (proficiency, args) => {
const races = [];
for (const { url, index } of proficiency.races) {
const filters = [{ index }];

if (args.name) {
filters.push(resolveContainsStringFilter(args.name));
}

if (url.includes('subrace')) {
races.push(await SubraceModel.findOne({ index: index }).lean());
races.push(await SubraceModel.findOne(coalesceFilters(filters)).lean());
} else {
races.push(await RaceModel.findOne({ index: index }).lean());
races.push(await RaceModel.findOne(coalesceFilters(filters)).lean());
}
}

Expand Down
Loading

0 comments on commit af69524

Please sign in to comment.