BVB Source Codes

parse-server Show QueryTools.js Source code

Return Download parse-server: download QueryTools.js Source code - Download parse-server Source code - Type:.js
  1. var equalObjects = require('./equalObjects');
  2. var Id = require('./Id');
  3. var Parse = require('parse/node');
  4.  
  5. /**
  6.  * Query Hashes are deterministic hashes for Parse Queries.
  7.  * Any two queries that have the same set of constraints will produce the same
  8.  * hash. This lets us reliably group components by the queries they depend upon,
  9.  * and quickly determine if a query has changed.
  10.  */
  11.  
  12. /**
  13.  * Convert $or queries into an array of where conditions
  14.  */
  15. function flattenOrQueries(where) {
  16.   if (!where.hasOwnProperty('$or')) {
  17.     return where;
  18.   }
  19.   var accum = [];
  20.   for (var i = 0; i < where.$or.length; i++) {
  21.     accum = accum.concat(where.$or[i]);
  22.   }
  23.   return accum;
  24. }
  25.  
  26. /**
  27.  * Deterministically turns an object into a string. Disregards ordering
  28.  */
  29. function stringify(object): string {
  30.   if (typeof object !== 'object' || object === null) {
  31.     if (typeof object === 'string') {
  32.       return '"' + object.replace(/\|/g, '%|') + '"';
  33.     }
  34.     return object + '';
  35.   }
  36.   if (Array.isArray(object)) {
  37.     var copy = object.map(stringify);
  38.     copy.sort();
  39.     return '[' + copy.join(',') + ']';
  40.   }
  41.   var sections = [];
  42.   var keys = Object.keys(object);
  43.   keys.sort();
  44.   for (var k = 0; k < keys.length; k++) {
  45.     sections.push(stringify(keys[k]) + ':' + stringify(object[keys[k]]));
  46.   }
  47.   return '{' + sections.join(',') + '}';
  48. }
  49.  
  50. /**
  51.  * Generate a hash from a query, with unique fields for columns, values, order,
  52.  * skip, and limit.
  53.  */
  54. function queryHash(query) {
  55.   if (query instanceof Parse.Query) {
  56.     query = {
  57.       className: query.className,
  58.       where: query._where
  59.     }
  60.   }
  61.   var where = flattenOrQueries(query.where || {});
  62.   var columns = [];
  63.   var values = [];
  64.   var i;
  65.   if (Array.isArray(where)) {
  66.     var uniqueColumns = {};
  67.     for (i = 0; i < where.length; i++) {
  68.       var subValues = {};
  69.       var keys = Object.keys(where[i]);
  70.       keys.sort();
  71.       for (var j = 0; j < keys.length; j++) {
  72.         subValues[keys[j]] = where[i][keys[j]];
  73.         uniqueColumns[keys[j]] = true;
  74.       }
  75.       values.push(subValues);
  76.     }
  77.     columns = Object.keys(uniqueColumns);
  78.     columns.sort();
  79.   } else {
  80.     columns = Object.keys(where);
  81.     columns.sort();
  82.     for (i = 0; i < columns.length; i++) {
  83.       values.push(where[columns[i]]);
  84.     }
  85.   }
  86.  
  87.   var sections = [columns.join(','), stringify(values)];
  88.  
  89.   return query.className + ':' + sections.join('|');
  90. }
  91.  
  92. /**
  93.  * matchesQuery -- Determines if an object would be returned by a Parse Query
  94.  * It's a lightweight, where-clause only implementation of a full query engine.
  95.  * Since we find queries that match objects, rather than objects that match
  96.  * queries, we can avoid building a full-blown query tool.
  97.  */
  98. function matchesQuery(object: any, query: any): boolean {
  99.   if (query instanceof Parse.Query) {
  100.     var className =
  101.       (object.id instanceof Id) ? object.id.className : object.className;
  102.     if (className !== query.className) {
  103.       return false;
  104.     }
  105.     return matchesQuery(object, query._where);
  106.   }
  107.   for (var field in query) {
  108.     if (!matchesKeyConstraints(object, field, query[field])) {
  109.       return false;
  110.     }
  111.   }
  112.   return true;
  113. }
  114.  
  115. function equalObjectsGeneric(obj, compareTo, eqlFn) {
  116.   if (Array.isArray(obj)) {
  117.     for (var i = 0; i < obj.length; i++) {
  118.       if (eqlFn(obj[i], compareTo)) {
  119.         return true;
  120.       }
  121.     }
  122.     return false;
  123.   }
  124.  
  125.   return eqlFn(obj, compareTo);
  126. }
  127.  
  128.  
  129. /**
  130.  * Determines whether an object matches a single key's constraints
  131.  */
  132. function matchesKeyConstraints(object, key, constraints) {
  133.   if (constraints === null) {
  134.     return false;
  135.   }
  136.   if(key.indexOf(".") >= 0){
  137.     // Key references a subobject
  138.     var keyComponents = key.split(".");
  139.     var subObjectKey = keyComponents[0];
  140.     var keyRemainder = keyComponents.slice(1).join(".");
  141.     return matchesKeyConstraints(object[subObjectKey] || {}, keyRemainder, constraints);
  142.   }
  143.   var i;
  144.   if (key === '$or') {
  145.     for (i = 0; i < constraints.length; i++) {
  146.       if (matchesQuery(object, constraints[i])) {
  147.         return true;
  148.       }
  149.     }
  150.     return false;
  151.   }
  152.   if (key === '$relatedTo') {
  153.     // Bail! We can't handle relational queries locally
  154.     return false;
  155.   }
  156.   // Equality (or Array contains) cases
  157.   if (typeof constraints !== 'object') {
  158.     if (Array.isArray(object[key])) {
  159.       return object[key].indexOf(constraints) > -1;
  160.     }
  161.     return object[key] === constraints;
  162.   }
  163.   var compareTo;
  164.   if (constraints.__type) {
  165.     if (constraints.__type === 'Pointer') {
  166.       return equalObjectsGeneric(object[key], constraints, function(obj, ptr) {
  167.         return (
  168.           typeof obj !== 'undefined' &&
  169.           ptr.className === obj.className &&
  170.           ptr.objectId === obj.objectId
  171.         );
  172.       });
  173.     }
  174.  
  175.     return equalObjectsGeneric(object[key], Parse._decode(key, constraints), equalObjects);
  176.   }
  177.   // More complex cases
  178.   for (var condition in constraints) {
  179.     compareTo = constraints[condition];
  180.     if (compareTo.__type) {
  181.       compareTo = Parse._decode(key, compareTo);
  182.     }
  183.     switch (condition) {
  184.     case '$lt':
  185.       if (object[key] >= compareTo) {
  186.         return false;
  187.       }
  188.       break;
  189.     case '$lte':
  190.       if (object[key] > compareTo) {
  191.         return false;
  192.       }
  193.       break;
  194.     case '$gt':
  195.       if (object[key] <= compareTo) {
  196.         return false;
  197.       }
  198.       break;
  199.     case '$gte':
  200.       if (object[key] < compareTo) {
  201.         return false;
  202.       }
  203.       break;
  204.     case '$ne':
  205.       if (equalObjects(object[key], compareTo)) {
  206.         return false;
  207.       }
  208.       break;
  209.     case '$in':
  210.       if (compareTo.indexOf(object[key]) < 0) {
  211.         return false;
  212.       }
  213.       break;
  214.     case '$nin':
  215.       if (compareTo.indexOf(object[key]) > -1) {
  216.         return false;
  217.       }
  218.       break;
  219.     case '$all':
  220.       for (i = 0; i < compareTo.length; i++) {
  221.         if (object[key].indexOf(compareTo[i]) < 0) {
  222.           return false;
  223.         }
  224.       }
  225.       break;
  226.     case '$exists': {
  227.       const propertyExists = typeof object[key] !== 'undefined';
  228.       const existenceIsRequired = constraints['$exists'];
  229.       if (typeof constraints['$exists'] !== 'boolean') {
  230.           // The SDK will never submit a non-boolean for $exists, but if someone
  231.           // tries to submit a non-boolean for $exits outside the SDKs, just ignore it.
  232.         break;
  233.       }
  234.       if ((!propertyExists && existenceIsRequired) || (propertyExists && !existenceIsRequired)) {
  235.         return false;
  236.       }
  237.       break;
  238.     }
  239.     case '$regex':
  240.       if (typeof compareTo === 'object') {
  241.         return compareTo.test(object[key]);
  242.       }
  243.         // JS doesn't support perl-style escaping
  244.       var expString = '';
  245.       var escapeEnd = -2;
  246.       var escapeStart = compareTo.indexOf('\\Q');
  247.       while (escapeStart > -1) {
  248.           // Add the unescaped portion
  249.         expString += compareTo.substring(escapeEnd + 2, escapeStart);
  250.         escapeEnd = compareTo.indexOf('\\E', escapeStart);
  251.         if (escapeEnd > -1) {
  252.           expString += compareTo.substring(escapeStart + 2, escapeEnd)
  253.               .replace(/\\\\\\\\E/g, '\\E').replace(/\W/g, '\\$&');
  254.         }
  255.  
  256.         escapeStart = compareTo.indexOf('\\Q', escapeEnd);
  257.       }
  258.       expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2));
  259.       var exp = new RegExp(expString, constraints.$options || '');
  260.       if (!exp.test(object[key])) {
  261.         return false;
  262.       }
  263.       break;
  264.     case '$nearSphere':
  265.       var distance = compareTo.radiansTo(object[key]);
  266.       var max = constraints.$maxDistance || Infinity;
  267.       return distance <= max;
  268.     case '$within':
  269.       var southWest = compareTo.$box[0];
  270.       var northEast = compareTo.$box[1];
  271.       if (southWest.latitude > northEast.latitude ||
  272.             southWest.longitude > northEast.longitude) {
  273.           // Invalid box, crosses the date line
  274.         return false;
  275.       }
  276.       return (
  277.           object[key].latitude > southWest.latitude &&
  278.           object[key].latitude < northEast.latitude &&
  279.           object[key].longitude > southWest.longitude &&
  280.           object[key].longitude < northEast.longitude
  281.       );
  282.     case '$options':
  283.         // Not a query type, but a way to add options to $regex. Ignore and
  284.         // avoid the default
  285.       break;
  286.     case '$maxDistance':
  287.         // Not a query type, but a way to add a cap to $nearSphere. Ignore and
  288.         // avoid the default
  289.       break;
  290.     case '$select':
  291.       return false;
  292.     case '$dontSelect':
  293.       return false;
  294.     default:
  295.       return false;
  296.     }
  297.   }
  298.   return true;
  299. }
  300.  
  301. var QueryTools = {
  302.   queryHash: queryHash,
  303.   matchesQuery: matchesQuery
  304. };
  305.  
  306. module.exports = QueryTools;
  307.  
downloadQueryTools.js Source code - Download parse-server Source code
Related Source Codes/Software:
react-boilerplate - 2017-06-07
webtorrent - Streaming torrent client for the web ... 2017-06-06
machine-learning-for-software-engineers - A complete daily plan for studying to become a mac... 2017-06-06
upterm - A terminal emulator for the 21st century. 2017-06-06
lottie-android - Render After Effects animations natively on Androi... 2017-06-07
AsyncDisplayKit - Smooth asynchronous user interfaces for iOS apps. ... 2017-06-07
ionicons - The premium icon font for Ionic ... 2017-06-07
storybook - 2017-06-07
prettier - Prettier is an opinionated JavaScript formatter. ... 2017-06-08
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top