* Execute database function calls
(functionName, args, appContext, operationLog = [], permissions = {})
| 583 | * Execute database function calls |
| 584 | */ |
| 585 | async function executeDatabaseFunction(functionName, args, appContext, operationLog = [], permissions = {}) { |
| 586 | // Check permissions before executing write operations |
| 587 | const writeOperations = ['deleteObject', 'deleteClass', 'updateObject', 'createObject', 'createClass']; |
| 588 | |
| 589 | if (writeOperations.includes(functionName)) { |
| 590 | // Handle both boolean and string values for permissions |
| 591 | const permissionValue = permissions && permissions[functionName]; |
| 592 | const hasPermission = permissionValue === true || permissionValue === 'true'; |
| 593 | |
| 594 | if (!hasPermission) { |
| 595 | throw new Error(`Permission denied: The "${functionName}" operation is currently disabled in the permissions settings. Please enable this permission in the Parse Dashboard Permissions menu if you want to allow this operation.`); |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | // Configure Parse for this app context |
| 600 | Parse.initialize(appContext.appId, undefined, appContext.masterKey); |
| 601 | Parse.serverURL = appContext.serverURL; |
| 602 | Parse.masterKey = appContext.masterKey; |
| 603 | |
| 604 | try { |
| 605 | switch (functionName) { |
| 606 | case 'queryClass': { |
| 607 | const { className, where = {}, limit = 100, skip = 0, order, include = [], select = [] } = args; |
| 608 | const query = new Parse.Query(className); |
| 609 | |
| 610 | // Apply constraints |
| 611 | Object.keys(where).forEach(key => { |
| 612 | const value = where[key]; |
| 613 | if (typeof value === 'object' && value !== null) { |
| 614 | // Handle complex queries like {$gte: 18} |
| 615 | Object.keys(value).forEach(op => { |
| 616 | switch (op) { |
| 617 | case '$gt': query.greaterThan(key, value[op]); break; |
| 618 | case '$gte': query.greaterThanOrEqualTo(key, value[op]); break; |
| 619 | case '$lt': query.lessThan(key, value[op]); break; |
| 620 | case '$lte': query.lessThanOrEqualTo(key, value[op]); break; |
| 621 | case '$ne': query.notEqualTo(key, value[op]); break; |
| 622 | case '$in': query.containedIn(key, value[op]); break; |
| 623 | case '$nin': query.notContainedIn(key, value[op]); break; |
| 624 | case '$exists': |
| 625 | if (value[op]) {query.exists(key);} |
| 626 | else {query.doesNotExist(key);} |
| 627 | break; |
| 628 | case '$regex': query.matches(key, new RegExp(value[op], value.$options || '')); break; |
| 629 | } |
| 630 | }); |
| 631 | } else { |
| 632 | query.equalTo(key, value); |
| 633 | } |
| 634 | }); |
| 635 | |
| 636 | if (limit) {query.limit(Math.min(limit, 1000));} |
| 637 | if (skip) {query.skip(skip);} |
| 638 | if (order) { |
| 639 | if (order.startsWith('-')) { |
| 640 | query.descending(order.substring(1)); |
| 641 | } else { |
| 642 | query.ascending(order); |