Began migration of queries to nested sets

This commit is contained in:
Thaum Rystra
2023-10-03 16:28:20 +02:00
parent 28a19f2037
commit f63d2ad254
41 changed files with 242 additions and 392 deletions

View File

@@ -10,8 +10,8 @@ import {
assertCopyPermission
} from '/imports/api/sharing/sharingPermissions';
import {
setLineageOfDocs,
getAncestry,
fetchDocByRef,
getFilter,
renewDocIds
} from '/imports/api/parenting/parentingFunctions';
import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions';
@@ -40,20 +40,20 @@ const copyPropertyToLibrary = new ValidatedMethod({
},
run({ propId, parentRef, order }) {
// get the new ancestry for the properties
let { parentDoc, ancestors } = getAncestry({ parentRef });
const parentDoc = fetchDocByRef(parentRef);
// Check permission to edit the destination
let rootLibrary;
if (parentRef.collection === 'libraries') {
rootLibrary = parentDoc;
} else if (parentRef.collection === 'libraryNodes') {
rootLibrary = Libraries.findOne(parentDoc.ancestors[0].id)
rootLibrary = Libraries.findOne(parentDoc.root.id)
} else {
throw `${parentRef.collection} is not a valid parent collection`
}
assertEditPermission(rootLibrary, this.userId);
const insertedRootNode = insertNodeFromProperty(propId, ancestors, order, this);
const insertedRootNode = insertNodeFromProperty(propId, order, this);
// Tree structure changed by inserts, reorder the tree
rebuildNestedSets(LibraryNodes, rootLibrary._id);
@@ -63,7 +63,7 @@ const copyPropertyToLibrary = new ValidatedMethod({
},
});
function insertNodeFromProperty(propId, ancestors, order, method) {
function insertNodeFromProperty(propId, order, method) {
// Fetch the property and its descendants, provided they have not been
// removed
let prop = CreatureProperties.findOne({
@@ -83,9 +83,9 @@ function insertNodeFromProperty(propId, ancestors, order, method) {
// Make sure we can edit this property
assertDocEditPermission(prop, method.userId);
let oldParent = prop.parent;
let oldParentId = prop.parentId;
const propCursor = CreatureProperties.find({
'ancestors.id': propId,
...getFilter.descendants(prop),
removed: { $ne: true },
});
@@ -105,13 +105,6 @@ function insertNodeFromProperty(propId, ancestors, order, method) {
// properties
assertSourceLibraryCopyPermission(props, method);
// re-map all the ancestors
setLineageOfDocs({
docArray: props,
newAncestry: ancestors,
oldParent,
});
// Give the docs new IDs without breaking internal references
renewDocIds({
docArray: props,
@@ -119,11 +112,8 @@ function insertNodeFromProperty(propId, ancestors, order, method) {
});
// Order the root node
if (order === undefined) {
rebuildNestedSets(LibraryNodes, prop.root.id);
} else {
prop.order = order;
}
prop.left = Number.MAX_SAFE_INTEGER - 1;
prop.right = Number.MAX_SAFE_INTEGER;
// Clean the props
props = cleanProps(props);
@@ -135,8 +125,8 @@ function insertNodeFromProperty(propId, ancestors, order, method) {
/**
*
* @param {[Property]} props The properties to check
* @param {String} userId The userId trying to copy these properties to a library
* @param props The properties to check
* @param userId The userId trying to copy these properties to a library
* Checks that every property can be copied out of the library that originated it by this user
*/
function assertSourceLibraryCopyPermission(props, method) {
@@ -155,9 +145,9 @@ function assertSourceLibraryCopyPermission(props, method) {
LibraryNodes.find({
_id: { $in: libraryNodeIds }
}, {
fields: { ancestors: 1 }
fields: { root: 1 }
}).forEach(node => {
sourceLibIds.add(node.ancestors?.[0]?.id);
sourceLibIds.add(node.root.id);
});
// Assert copy permission on each of those libraries

View File

@@ -28,7 +28,7 @@ const damageProperty = new ValidatedMethod({
if (!prop) throw new Meteor.Error(
'Damage property failed', 'Property doesn\'t exist'
);
const creatureId = prop.ancestors[0].id;
const creatureId = prop.root.id;
const actionContext = new ActionContext(creatureId, [creatureId], this);
// Check permissions

View File

@@ -5,7 +5,7 @@ import CreatureProperties from '/imports/api/creature/creatureProperties/Creatur
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions';
import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor';
import {
setLineageOfDocs,
getFilter,
renewDocIds
} from '/imports/api/parenting/parentingFunctions';
import { rebuildNestedSets } from '/imports/api/parenting/parentingFunctions';
@@ -33,6 +33,8 @@ const duplicateProperty = new ValidatedMethod({
},
run({ _id }) {
let property = CreatureProperties.findOne(_id);
if (!property) throw new Meteor.Error('not-found', 'The source property was not found');
let creature = getRootCreatureAncestor(property);
assertEditPermission(creature, this.userId);
@@ -49,7 +51,7 @@ const duplicateProperty = new ValidatedMethod({
// Get all the descendants
let nodes = CreatureProperties.find({
'ancestors.id': _id,
...getFilter.descendants(property),
removed: { $ne: true },
}, {
limit: DUPLICATE_CHILDREN_LIMIT + 1,
@@ -66,22 +68,13 @@ const duplicateProperty = new ValidatedMethod({
}
}
// re-map all the ancestors
setLineageOfDocs({
docArray: nodes,
newAncestry: [
...property.ancestors,
{ id: propertyId, collection: 'creatureProperties' }
],
oldParent: { id: _id, collection: 'creatureProperties' },
});
// Give the docs new IDs without breaking internal references
const allNodes = [property, ...nodes];
renewDocIds({ docArray: allNodes });
// Order the root node
property.order += 0.5;
property.left = Number.MAX_SAFE_INTEGER - 1;
property.right = Number.MAX_SAFE_INTEGER;
// Mark the sheet as needing recompute
property.dirty = true;

View File

@@ -17,7 +17,7 @@ const flipToggle = new ValidatedMethod({
run({ _id }) {
// Permission
let property = CreatureProperties.findOne(_id, {
fields: { type: 1, ancestors: 1, enabled: 1, disabled: 1 }
fields: { type: 1, root: 1, enabled: 1, disabled: 1 }
});
if (property.type !== 'toggle') {
throw new Meteor.Error('wrong property',

View File

@@ -1,8 +1,9 @@
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
import { getFilter } from '/imports/api/parenting/parentingFunctions';
export default function getParentRefByTag(creatureId, tag) {
let prop = CreatureProperties.findOne({
'ancestors.id': creatureId,
...getFilter.descendantsOfRoot(creatureId),
removed: { $ne: true },
inactive: { $ne: true },
tags: tag,

View File

@@ -1,3 +1,5 @@
import { getFilter } from "/imports/api/parenting/parentingFunctions";
export default function getSlotFillFilter({ slot, libraryIds }) {
if (!slot) throw 'Slot is required for getSlotFillFilter';
@@ -6,9 +8,14 @@ export default function getSlotFillFilter({ slot, libraryIds }) {
let filter = {
fillSlots: true,
removed: { $ne: true },
$and: []
$and: [],
};
filter['ancestors.id'] = { $in: libraryIds };
if (libraryIds.length) {
Object.assign(
filter,
getFilter.descendantsOfAllRoots(libraryIds)
);
}
if (slot.slotType) {
filter.$and.push({
$or: [{

View File

@@ -33,7 +33,7 @@ describe('Slot fill filter', function () {
$or: [{
libraryTags: { $all: ['tag1', 'tag2'] }
}],
'ancestors.id': { $in: ['libraryId1', 'libraryId2'] },
'root.id': { $in: ['libraryId1', 'libraryId2'] },
removed: { $ne: true },
fillSlots: true,
});
@@ -76,7 +76,7 @@ describe('Slot fill filter', function () {
$and: [
{ libraryTags: { $nin: ['tag5', 'tag6', 'tag7', 'tag8'] } },
],
'ancestors.id': { $in: ['libraryId1', 'libraryId2'] },
'root.id': { $in: ['libraryId1', 'libraryId2'] },
removed: { $ne: true },
fillSlots: true,
});

View File

@@ -14,6 +14,8 @@ const updateCreatureProperty = new ValidatedMethod({
case 'order':
case 'parent':
case 'ancestors':
case 'root':
case 'parentId':
case 'damage':
throw new Meteor.Error('Permission denied',
'This property can\'t be updated directly');
@@ -27,7 +29,7 @@ const updateCreatureProperty = new ValidatedMethod({
run({ _id, path, value }) {
// Permission
let property = CreatureProperties.findOne(_id, {
fields: { type: 1, ancestors: 1 }
fields: { type: 1, root: 1 }
});
let rootCreature = getRootCreatureAncestor(property);
assertEditPermission(rootCreature, this.userId);