function _UnsafeRestQuery(
  config,
  auth,
  className,
  restWhere = {},
  restOptions = {},
  clientSDK,
  runAfterFind = true,
  context
) {
  this.config = config;
  this.auth = auth;
  this.className = className;
  this.restWhere = restWhere;
  this.restOptions = restOptions;
  this.clientSDK = clientSDK;
  this.runAfterFind = runAfterFind;
  this.response = null;
  this.findOptions = {};
  this.context = context || {};
  if (!this.auth.isMaster) {
    if (this.className == '_Session') {
      if (!this.auth.user) {
        throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
      }
      this.restWhere = {
        $and: [
          this.restWhere,
          {
            user: {
              __type: 'Pointer',
              className: '_User',
              objectId: this.auth.user.id,
            },
          },
        ],
      };
    }
  }

  this.doCount = false;
  this.includeAll = false;

  // The format for this.include is not the same as the format for the
  // include option - it's the paths we should include, in order,
  // stored as arrays, taking into account that we need to include foo
  // before including foo.bar. Also it should dedupe.
  // For example, passing an arg of include=foo.bar,foo.baz could lead to
  // this.include = [['foo'], ['foo', 'baz'], ['foo', 'bar']]
  this.include = [];
  let keysForInclude = '';

  // If we have keys, we probably want to force some includes (n-1 level)
  // See issue: https://github.com/parse-community/parse-server/issues/3185
  if (Object.prototype.hasOwnProperty.call(restOptions, 'keys')) {
    keysForInclude = restOptions.keys;
  }

  // If we have keys, we probably want to force some includes (n-1 level)
  // in order to exclude specific keys.
  if (Object.prototype.hasOwnProperty.call(restOptions, 'excludeKeys')) {
    keysForInclude += ',' + restOptions.excludeKeys;
  }

  if (keysForInclude.length > 0) {
    keysForInclude = keysForInclude
      .split(',')
      .filter(key => {
        // At least 2 components
        return key.split('.').length > 1;
      })
      .map(key => {
        // Slice the last component (a.b.c -> a.b)
        // Otherwise we'll include one level too much.
        return key.slice(0, key.lastIndexOf('.'));
      })
      .join(',');

    // Concat the possibly present include string with the one from the keys
    // Dedup / sorting is handle in 'include' case.
    if (keysForInclude.length > 0) {
      if (!restOptions.include || restOptions.include.length == 0) {
        restOptions.include = keysForInclude;
      } else {
        restOptions.include += ',' + keysForInclude;
      }
    }
  }

  for (var option in restOptions) {
    switch (option) {
      case 'keys': {
        const keys = restOptions.keys
          .split(',')
          .filter(key => key.length > 0)
          .concat(AlwaysSelectedKeys);
        this.keys = Array.from(new Set(keys));
        break;
      }
      case 'excludeKeys': {
        const exclude = restOptions.excludeKeys
          .split(',')
          .filter(k => AlwaysSelectedKeys.indexOf(k) < 0);
        this.excludeKeys = Array.from(new Set(exclude));
        break;
      }
      case 'count':
        this.doCount = true;
        break;
      case 'includeAll':
        this.includeAll = true;
        break;
      case 'explain':
      case 'hint':
      case 'distinct':
      case 'pipeline':
      case 'skip':
      case 'limit':
      case 'readPreference':
      case 'comment':
        this.findOptions[option] = restOptions[option];
        break;
      case 'order':
        var fields = restOptions.order.split(',');
        this.findOptions.sort = fields.reduce((sortMap, field) => {
          field = field.trim();
          if (field === '$score' || field === '-$score') {
            sortMap.score = { $meta: 'textScore' };
          } else if (field[0] == '-') {
            sortMap[field.slice(1)] = -1;
          } else {
            sortMap[field] = 1;
          }
          return sortMap;
        }, {});
        break;
      case 'include': {
        const paths = restOptions.include.split(',');
        if (paths.includes('*')) {
          this.includeAll = true;
          break;
        }
        // Load the existing includes (from keys)
        const pathSet = paths.reduce((memo, path) => {
          // Split each paths on . (a.b.c -> [a,b,c])
          // reduce to create all paths
          // ([a,b,c] -> {a: true, 'a.b': true, 'a.b.c': true})
          return path.split('.').reduce((memo, path, index, parts) => {
            memo[parts.slice(0, index + 1).join('.')] = true;
            return memo;
          }, memo);
        }, {});

        this.include = Object.keys(pathSet)
          .map(s => {
            return s.split('.');
          })
          .sort((a, b) => {
            return a.length - b.length; // Sort by number of components
          });
        break;
      }
      case 'redirectClassNameForKey':
        this.redirectKey = restOptions.redirectClassNameForKey;
        this.redirectClassName = null;
        break;
      case 'includeReadPreference':
      case 'subqueryReadPreference':
        break;
      default:
        throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad option: ' + option);
    }
  }
}
_UnsafeRestQuery is meant for specific internal usage only. When you need to skip security checks or some triggers.
Don't use it if you don't know what you are doing.
@param config
@param auth
@param className
@param restWhere
@param restOptions
@param clientSDK
@param runAfterFind
@param context