Continued migration to nested sets

This commit is contained in:
Thaum Rystra
2023-10-04 14:27:06 +02:00
parent f63d2ad254
commit b4993b86b5
11 changed files with 35 additions and 172 deletions

View File

@@ -1,6 +1,7 @@
import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation';
import { assert } from 'chai'; import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
let computation = buildComputationFromProps(testProperties); let computation = buildComputationFromProps(testProperties);
@@ -53,30 +54,22 @@ var testProperties = [
_id: 'itemUnequippedId', _id: 'itemUnequippedId',
type: 'item', type: 'item',
parentId: 'charId', parentId: 'charId',
left: 1,
right: 4,
}), }),
clean({ clean({
_id: 'itemUnequippedChildId', _id: 'itemUnequippedChildId',
type: 'folder', type: 'folder',
parentId: 'itemUnequippedId', parentId: 'itemUnequippedId',
left: 2,
right: 3,
}), }),
clean({ clean({
_id: 'itemEquippedId', _id: 'itemEquippedId',
type: 'item', type: 'item',
equipped: true, equipped: true,
parentId: 'charId', parentId: 'charId',
left: 5,
right: 8,
}), }),
clean({ clean({
_id: 'itemEquippedChildId', _id: 'itemEquippedChildId',
type: 'folder', type: 'folder',
parentId: 'itemEquippedId', parentId: 'itemEquippedId',
left: 6,
right: 7,
}), }),
// Spells // Spells
clean({ clean({
@@ -84,58 +77,44 @@ var testProperties = [
type: 'spell', type: 'spell',
parentId: 'charId', parentId: 'charId',
prepared: true, prepared: true,
left: 9,
right: 12,
}), }),
clean({ clean({
_id: 'spellPreparedChildId', _id: 'spellPreparedChildId',
type: 'folder', type: 'folder',
parentId: 'spellPreparedId', parentId: 'spellPreparedId',
left: 10,
right: 11,
}), }),
clean({ clean({
_id: 'spellAlwaysPreparedId', _id: 'spellAlwaysPreparedId',
type: 'spell', type: 'spell',
parentId: 'charId', parentId: 'charId',
alwaysPrepared: true, alwaysPrepared: true,
left: 13,
right: 16,
}), }),
clean({ clean({
_id: 'spellAlwaysPreparedChildId', _id: 'spellAlwaysPreparedChildId',
type: 'folder', type: 'folder',
parentId: 'spellAlwaysPreparedId', parentId: 'spellAlwaysPreparedId',
left: 14,
right: 15,
}), }),
clean({ clean({
_id: 'spellUnpreparedId', _id: 'spellUnpreparedId',
type: 'spell', type: 'spell',
parentId: 'charId', parentId: 'charId',
left: 17,
right: 20,
}), }),
clean({ clean({
_id: 'spellUnpreparedChildId', _id: 'spellUnpreparedChildId',
type: 'folder', type: 'folder',
parentId: 'spellUnpreparedId', parentId: 'spellUnpreparedId',
left: 18,
right: 19,
}), }),
// Notes // Notes
clean({ clean({
_id: 'NoteId', _id: 'NoteId',
type: 'note', type: 'note',
parentId: 'charId', parentId: 'charId',
left: 21,
right: 24,
}), }),
clean({ clean({
_id: 'NoteChildId', _id: 'NoteChildId',
type: 'folder', type: 'folder',
parentId: 'NoteId', parentId: 'NoteId',
left: 22,
right: 23,
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -1,6 +1,7 @@
import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation';
import { assert } from 'chai'; import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
const computation = buildComputationFromProps(testProperties); const computation = buildComputationFromProps(testProperties);
@@ -13,8 +14,6 @@ var testProperties = [
clean({ clean({
_id: 'slotId', _id: 'slotId',
type: 'propertySlot', type: 'propertySlot',
left: 1,
right: 8,
}), }),
// Children // Children
clean({ clean({
@@ -23,21 +22,17 @@ var testProperties = [
slotQuantityFilled: 3, slotQuantityFilled: 3,
slotFillerType: 'item', slotFillerType: 'item',
parentId: 'slotId', parentId: 'slotId',
left: 2,
right: 3,
}), }),
clean({ clean({
_id: 'slotChildId', _id: 'slotChildId',
type: 'item', type: 'item',
parentId: 'slotId', parentId: 'slotId',
left: 4,
right: 7,
}), }),
clean({ clean({
_id: 'slotGrandchildId', _id: 'slotGrandchildId',
type: 'effect', type: 'effect',
parentId: 'slotChildId', parentId: 'slotChildId',
left: 5,
right: 6,
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -1,6 +1,7 @@
import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation';
import { assert } from 'chai'; import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
const computation = buildComputationFromProps(testProperties); const computation = buildComputationFromProps(testProperties);
@@ -37,38 +38,37 @@ var testProperties = [
_id: 'enabledToggleId', _id: 'enabledToggleId',
type: 'toggle', type: 'toggle',
enabled: true, enabled: true,
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'disabledToggleId', _id: 'disabledToggleId',
type: 'toggle', type: 'toggle',
disabled: true, disabled: true,
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'conditionToggleId', _id: 'conditionToggleId',
type: 'toggle', type: 'toggle',
ancestors: [{ id: 'charId' }],
}), }),
// Children // Children
clean({ clean({
_id: 'enabledToggleChildId', _id: 'enabledToggleChildId',
type: 'folder', type: 'folder',
ancestors: [{ id: 'charId' }, { id: 'enabledToggleId' }], parentId: 'enabledToggleId',
}), }),
clean({ clean({
_id: 'disabledToggleChildId', _id: 'disabledToggleChildId',
type: 'folder', type: 'folder',
ancestors: [{ id: 'charId' }, { id: 'disabledToggleId' }], parentId: 'disabledToggleId',
}), }),
clean({ clean({
_id: 'conditionToggleChildId', _id: 'conditionToggleChildId',
type: 'folder', type: 'folder',
ancestors: [{ id: 'charId' }, { id: 'conditionToggleId' }], parentId: 'conditionToggleId',
}), }),
clean({ clean({
_id: 'conditionToggleGrandChildId', _id: 'conditionToggleGrandChildId',
type: 'folder', type: 'folder',
ancestors: [{ id: 'charId' }, { id: 'conditionToggleId' }, { id: 'conditionToggleChildId' }], parentId: 'conditionToggleChildId',
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -1,6 +1,7 @@
import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation'; import { buildComputationFromProps } from '/imports/api/engine/computation/buildCreatureComputation';
import { assert } from 'chai'; import { assert } from 'chai';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
const computation = buildComputationFromProps(testProperties); const computation = buildComputationFromProps(testProperties);
@@ -32,8 +33,6 @@ var testProperties = [
clean({ clean({
_id: 'spellListId', _id: 'spellListId',
type: 'spellList', type: 'spellList',
left: 1,
right: 6,
}), }),
clean({ clean({
_id: 'childId', _id: 'childId',
@@ -42,8 +41,6 @@ var testProperties = [
text: 'DC {#spellList.dc} save or suck' text: 'DC {#spellList.dc} save or suck'
}, },
parentId: 'spellListId', parentId: 'spellListId',
left: 2,
right: 5,
}), }),
clean({ clean({
_id: 'grandchildId', _id: 'grandchildId',
@@ -52,8 +49,6 @@ var testProperties = [
calculation: '#spellList.dc + strength + wisdom.modifier' calculation: '#spellList.dc + strength + wisdom.modifier'
}, },
parentId: 'childId', parentId: 'childId',
left: 3,
right: 4,
}), }),
clean({ clean({
_id: 'strengthId', _id: 'strengthId',
@@ -62,7 +57,7 @@ var testProperties = [
baseValue: { baseValue: {
calculation: '15 + ', calculation: '15 + ',
}, },
left: 7,
right: 8,
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -22,6 +22,5 @@ var testProperties = [
_id: 'strengthId', _id: 'strengthId',
type: 'attribute', type: 'attribute',
variableName: 'strength', variableName: 'strength',
ancestors: [{ id: 'charId' }],
}), }),
]; ];

View File

@@ -2,6 +2,7 @@ import { buildComputationFromProps } from '/imports/api/engine/computation/build
import { assert } from 'chai'; import { assert } from 'chai';
import computeCreatureComputation from '../../computeCreatureComputation'; import computeCreatureComputation from '../../computeCreatureComputation';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
const computation = buildComputationFromProps(testProperties); const computation = buildComputationFromProps(testProperties);
@@ -20,41 +21,37 @@ var testProperties = [
type: 'class', type: 'class',
variableName: 'wizard', variableName: 'wizard',
classType: 'startingClass', classType: 'startingClass',
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'rangerId', _id: 'rangerId',
type: 'class', type: 'class',
variableName: 'ranger', variableName: 'ranger',
classType: 'multiClass', classType: 'multiClass',
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'wiz1Id', _id: 'wiz1Id',
type: 'classLevel', type: 'classLevel',
variableName: 'wizard', variableName: 'wizard',
level: 1, level: 1,
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'wiz2Id', _id: 'wiz2Id',
type: 'classLevel', type: 'classLevel',
variableName: 'wizard', variableName: 'wizard',
level: 2, level: 2,
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'wiz4Id', _id: 'wiz4Id',
type: 'classLevel', type: 'classLevel',
variableName: 'wizard', variableName: 'wizard',
level: 4, level: 4,
ancestors: [{ id: 'charId' }],
}), }),
clean({ clean({
_id: 'rang1Id', _id: 'rang1Id',
type: 'classLevel', type: 'classLevel',
variableName: 'ranger', variableName: 'ranger',
level: 1, level: 1,
ancestors: [{ id: 'charId' }],
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -2,6 +2,7 @@ import { buildComputationFromProps } from '/imports/api/engine/computation/build
import { assert } from 'chai'; import { assert } from 'chai';
import computeCreatureComputation from '../../computeCreatureComputation'; import computeCreatureComputation from '../../computeCreatureComputation';
import clean from '../../utility/cleanProp.testFn'; import clean from '../../utility/cleanProp.testFn';
import { applyNestedSetProperties } from '/imports/api/parenting/parentingFunctions';
export default function () { export default function () {
const computation = buildComputationFromProps(testProperties); const computation = buildComputationFromProps(testProperties);
@@ -23,6 +24,7 @@ var testProperties = [
baseValue: { baseValue: {
calculation: 'arrayConstant[3]', calculation: 'arrayConstant[3]',
}, },
ancestors: [{ id: 'charId' }],
}), }),
]; ];
applyNestedSetProperties(testProperties);

View File

@@ -44,7 +44,6 @@ var testProperties = [
clean({ clean({
_id: 'actionId', _id: 'actionId',
type: 'action', type: 'action',
ancestors: [{ id: 'charId' }],
attackRoll: { attackRoll: {
calculation: 'strength.modifier', calculation: 'strength.modifier',
}, },
@@ -54,7 +53,6 @@ var testProperties = [
_id: 'profBonusId', _id: 'profBonusId',
type: 'attribute', type: 'attribute',
variableName: 'proficiencyBonus', variableName: 'proficiencyBonus',
ancestors: [{ id: 'charId' }],
baseValue: { baseValue: {
calculation: '13' calculation: '13'
}, },

View File

@@ -1,102 +0,0 @@
import SimpleSchema from 'simpl-schema';
import { union } from 'lodash';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
import { changeParent, fetchDocByRef, getCollectionByName } from '/imports/api/parenting/parentingFunctions';
import { RefSchema } from '/imports/api/parenting/ChildSchema';
import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions';
import Creatures from '/imports/api/creature/creatures/Creatures';
const organizeDoc = new ValidatedMethod({
name: 'organize.organizeDoc',
validate: new SimpleSchema({
docRef: RefSchema,
parentRef: RefSchema,
order: {
type: Number,
// Should end in 0.5 to place it reliably between two existing documents
},
skipRecompute: {
type: Boolean,
optional: true,
},
skipClient: {
type: Boolean,
optional: true,
},
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
timeInterval: 5000,
},
async run({ docRef, parentId, order, skipRecompute, skipClient }) {
if (skipClient && this.isSimulation) {
return;
}
const collection = getCollectionByName(docRef.collection);
const [doc, parent] = await Promise.all([
collection.findOneAsync(docRef.id),
collection.findOneAsync(parentId),
]);
if (!doc) throw new Meteor.Error('Document not found', 'The property to move could not be found');
if (!parent) throw new Meteor.Error('Document not found', 'The new parent could not be found');
// The user must be able to edit both the doc and its parent to move it
// successfully
await Promise.all([
assertDocEditPermission(doc, this.userId),
// Only check parent if it has a different root
doc.root.id !== parent.root.id && assertDocEditPermission(parent, this.userId),
]);
// Change the doc's parent
await changeParent(doc, parent, collection, order);
// Figure out which creatures need to be recalculated after this move
if (!skipRecompute && docRef.collection === 'creatures') {
const creaturesToRecompute = union[doc.root.id, parent.root.id];
// Mark the creatures for recompute
await Creatures.updateAsync({
_id: { $in: creaturesToRecompute }
}, {
$set: { dirty: true },
}, {
multi: true
});
}
},
});
// TODO, rewrite
const reorderDoc = new ValidatedMethod({
name: 'organize.reorderDoc',
validate: new SimpleSchema({
docRef: RefSchema,
order: {
type: Number,
// Should end in 0.5 to place it reliably between two existing documents
},
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
timeInterval: 5000,
},
run({ docRef, order }) {
let doc = fetchDocByRef(docRef);
assertDocEditPermission(doc, this.userId);
safeUpdateDocOrder({ docRef, order });
// Recompute the affected creatures
const ancestors = getCreatureAncestors(doc);
if (ancestors.length) {
Creatures.update({
_id: { $in: ancestors }
}, {
$set: { dirty: true },
});
}
},
});
export { organizeDoc, reorderDoc };

View File

@@ -42,6 +42,7 @@ import ColumnLayout from '/imports/client/ui/components/ColumnLayout.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties'; import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
import PrintedSpell from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedSpell.vue'; import PrintedSpell from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedSpell.vue';
import PrintedSpellList from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedSpellList.vue'; import PrintedSpellList from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedSpellList.vue';
import { getFilter } from '/imports/api/parenting/parentingFunctions';
export default { export default {
components: { components: {
@@ -60,23 +61,22 @@ export default {
organize: false, organize: false,
} }
}, },
// @ts-ignore-error Meteor not defined on vue
meteor: { meteor: {
spellLists() { spellLists() {
return CreatureProperties.find({ return CreatureProperties.find({
'ancestors.id': this.creatureId, ...getFilter.descendantsOfRoot(this.creatureId),
type: 'spellList', type: 'spellList',
removed: { $ne: true }, removed: { $ne: true },
inactive: { $ne: true }, inactive: { $ne: true },
}, { }, {
sort: { order: 1 } sort: { order: 1 }
}); }).fetch();
}, },
spellsWithoutList() { spellsWithoutList() {
return CreatureProperties.find({ return CreatureProperties.find({
'ancestors.id': { ...getFilter.descendantsOfRoot(this.creatureId),
$eq: this.creatureId, $not: getFilter.descendantsOfAll(this.spellLists),
$nin: this.spellListIds,
},
type: 'spell', type: 'spell',
removed: { $ne: true }, removed: { $ne: true },
deactivatedByAncestor: { $ne: true }, deactivatedByAncestor: { $ne: true },
@@ -90,10 +90,8 @@ export default {
}, },
spellListsWithoutAncestorSpellLists() { spellListsWithoutAncestorSpellLists() {
return CreatureProperties.find({ return CreatureProperties.find({
'ancestors.id': { ...getFilter.descendantsOfRoot(this.creatureId),
$eq: this.creatureId, $not: getFilter.descendantsOfAll(this.spellLists),
$nin: this.spellListIds,
},
type: 'spellList', type: 'spellList',
removed: { $ne: true }, removed: { $ne: true },
inactive: { $ne: true }, inactive: { $ne: true },
@@ -101,7 +99,7 @@ export default {
sort: { order: 1 } sort: { order: 1 }
}).map(sl => { }).map(sl => {
sl.spells = CreatureProperties.find({ sl.spells = CreatureProperties.find({
'ancestors.id': sl._id, ...getFilter.descendants(sl),
type: 'spell', type: 'spell',
removed: { $ne: true }, removed: { $ne: true },
inactive: { $ne: true }, inactive: { $ne: true },

View File

@@ -360,6 +360,7 @@ import PrintedSkill from '/imports/client/ui/creature/character/printedCharacter
import PrintedDamageMultipliers from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedDamageMultipliers.vue'; import PrintedDamageMultipliers from '/imports/client/ui/creature/character/printedCharacterSheet/components/PrintedDamageMultipliers.vue';
import PropertyDescription from '/imports/client/ui/properties/viewers/shared/PropertyDescription.vue'; import PropertyDescription from '/imports/client/ui/properties/viewers/shared/PropertyDescription.vue';
import { uniqBy } from 'lodash'; import { uniqBy } from 'lodash';
import { getFilter } from '/imports/api/parenting/parentingFunctions';
const getProperties = function (creature, filter, options = { const getProperties = function (creature, filter, options = {
sort: { order: 1 } sort: { order: 1 }
@@ -368,7 +369,7 @@ const getProperties = function (creature, filter, options = {
if (creature.settings.hideUnusedStats) { if (creature.settings.hideUnusedStats) {
filter.hide = { $ne: true }; filter.hide = { $ne: true };
} }
filter['ancestors.id'] = creature._id; filter['root.id'] = creature._id;
filter.removed = { $ne: true }; filter.removed = { $ne: true };
filter.inactive = { $ne: true }; filter.inactive = { $ne: true };
filter.overridden = { $ne: true }; filter.overridden = { $ne: true };
@@ -413,6 +414,7 @@ export default {
doCheckLoading: false, doCheckLoading: false,
} }
}, },
//@ts-ignore-error Meteor not defined
meteor: { meteor: {
creature() { creature() {
return Creatures.findOne(this.creatureId, { fields: { settings: 1 } }); return Creatures.findOne(this.creatureId, { fields: { settings: 1 } });
@@ -425,7 +427,7 @@ export default {
}, },
toggles() { toggles() {
return CreatureProperties.find({ return CreatureProperties.find({
'ancestors.id': this.creatureId, ...getFilter.descendantsOfRoot(this.creatureId),
type: 'toggle', type: 'toggle',
removed: { $ne: true }, removed: { $ne: true },
deactivatedByAncestor: { $ne: true }, deactivatedByAncestor: { $ne: true },