Relay Spec (#6089)
* Install graphql-relay * Add relayNodeInterface to ParseGraphQLSchema * Add support to global id * Add support to global id in other operations * Fix sort by glboal id * Fix where by global id * Introduce IdWhereInput * Add Relay object identification tests * Client mutation id on createFile mutation * Client mutation id on callCloudCode mutation * Client mutation id on signUp mutation * Client mutation id on logIn mutation * Client mutation id on logOut mutation * Client mutation id on createClass mutation * Client mutation id on updateClass mutation * Client mutation id on deleteClass mutation * Client mutation id on create object mutation * Improve Viewer type * Client mutation id on update object mutation * Client mutation id on delete object mutation * Introducing connections * Fix tests * Add pagination test * Fix file location * Fix postgres tests * Add comments * Tests to calculateSkipAndLimit
This commit is contained in:
committed by
GitHub
parent
67e3c33ffe
commit
a9066e20dc
@@ -1,4 +1,5 @@
|
||||
import Parse from 'parse/node';
|
||||
import { offsetToCursor, cursorToOffset } from 'graphql-relay';
|
||||
import rest from '../../rest';
|
||||
import { transformQueryInputToParse } from '../transformers/query';
|
||||
|
||||
@@ -51,8 +52,11 @@ const findObjects = async (
|
||||
className,
|
||||
where,
|
||||
order,
|
||||
skip,
|
||||
limit,
|
||||
skipInput,
|
||||
first,
|
||||
after,
|
||||
last,
|
||||
before,
|
||||
keys,
|
||||
include,
|
||||
includeAll,
|
||||
@@ -68,11 +72,52 @@ const findObjects = async (
|
||||
if (!where) {
|
||||
where = {};
|
||||
}
|
||||
transformQueryInputToParse(where, fields);
|
||||
transformQueryInputToParse(where, fields, className);
|
||||
|
||||
const skipAndLimitCalculation = calculateSkipAndLimit(
|
||||
skipInput,
|
||||
first,
|
||||
after,
|
||||
last,
|
||||
before,
|
||||
config.maxLimit
|
||||
);
|
||||
let { skip } = skipAndLimitCalculation;
|
||||
const { limit, needToPreCount } = skipAndLimitCalculation;
|
||||
let preCount = undefined;
|
||||
if (needToPreCount) {
|
||||
const preCountOptions = {
|
||||
limit: 0,
|
||||
count: true,
|
||||
};
|
||||
if (readPreference) {
|
||||
preCountOptions.readPreference = readPreference;
|
||||
}
|
||||
if (Object.keys(where).length > 0 && subqueryReadPreference) {
|
||||
preCountOptions.subqueryReadPreference = subqueryReadPreference;
|
||||
}
|
||||
preCount = (
|
||||
await rest.find(
|
||||
config,
|
||||
auth,
|
||||
className,
|
||||
where,
|
||||
preCountOptions,
|
||||
info.clientSDK
|
||||
)
|
||||
).count;
|
||||
if ((skip || 0) + limit < preCount) {
|
||||
skip = preCount - limit;
|
||||
}
|
||||
}
|
||||
|
||||
const options = {};
|
||||
|
||||
if (selectedFields.includes('results')) {
|
||||
if (
|
||||
selectedFields.find(
|
||||
field => field.startsWith('edges.') || field.startsWith('pageInfo.')
|
||||
)
|
||||
) {
|
||||
if (limit || limit === 0) {
|
||||
options.limit = limit;
|
||||
}
|
||||
@@ -104,7 +149,12 @@ const findObjects = async (
|
||||
options.limit = 0;
|
||||
}
|
||||
|
||||
if (selectedFields.includes('count')) {
|
||||
if (
|
||||
(selectedFields.includes('count') ||
|
||||
selectedFields.includes('pageInfo.hasPreviousPage') ||
|
||||
selectedFields.includes('pageInfo.hasNextPage')) &&
|
||||
!needToPreCount
|
||||
) {
|
||||
options.count = true;
|
||||
}
|
||||
|
||||
@@ -115,7 +165,151 @@ const findObjects = async (
|
||||
options.subqueryReadPreference = subqueryReadPreference;
|
||||
}
|
||||
|
||||
return rest.find(config, auth, className, where, options, info.clientSDK);
|
||||
let results, count;
|
||||
if (options.count || !options.limit || (options.limit && options.limit > 0)) {
|
||||
const findResult = await rest.find(
|
||||
config,
|
||||
auth,
|
||||
className,
|
||||
where,
|
||||
options,
|
||||
info.clientSDK
|
||||
);
|
||||
results = findResult.results;
|
||||
count = findResult.count;
|
||||
}
|
||||
|
||||
let edges = null;
|
||||
let pageInfo = null;
|
||||
if (results) {
|
||||
edges = results.map((result, index) => ({
|
||||
cursor: offsetToCursor((skip || 0) + index),
|
||||
node: result,
|
||||
}));
|
||||
|
||||
pageInfo = {
|
||||
hasPreviousPage:
|
||||
((preCount && preCount > 0) || (count && count > 0)) &&
|
||||
skip !== undefined &&
|
||||
skip > 0,
|
||||
startCursor: offsetToCursor(skip || 0),
|
||||
endCursor: offsetToCursor((skip || 0) + (results.length || 1) - 1),
|
||||
hasNextPage: (preCount || count) > (skip || 0) + results.length,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
edges,
|
||||
pageInfo,
|
||||
count: preCount || count,
|
||||
};
|
||||
};
|
||||
|
||||
export { getObject, findObjects };
|
||||
const calculateSkipAndLimit = (
|
||||
skipInput,
|
||||
first,
|
||||
after,
|
||||
last,
|
||||
before,
|
||||
maxLimit
|
||||
) => {
|
||||
let skip = undefined;
|
||||
let limit = undefined;
|
||||
let needToPreCount = false;
|
||||
|
||||
// Validates the skip input
|
||||
if (skipInput || skipInput === 0) {
|
||||
if (skipInput < 0) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'Skip should be a positive number'
|
||||
);
|
||||
}
|
||||
skip = skipInput;
|
||||
}
|
||||
|
||||
// Validates the after param
|
||||
if (after) {
|
||||
after = cursorToOffset(after);
|
||||
if ((!after && after !== 0) || after < 0) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'After is not a valid cursor'
|
||||
);
|
||||
}
|
||||
|
||||
// If skip and after are passed, a new skip is calculated by adding them
|
||||
skip = (skip || 0) + (after + 1);
|
||||
}
|
||||
|
||||
// Validates the first param
|
||||
if (first || first === 0) {
|
||||
if (first < 0) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'First should be a positive number'
|
||||
);
|
||||
}
|
||||
|
||||
// The first param is translated to the limit param of the Parse legacy API
|
||||
limit = first;
|
||||
}
|
||||
|
||||
// Validates the before param
|
||||
if (before || before === 0) {
|
||||
// This method converts the cursor to the index of the object
|
||||
before = cursorToOffset(before);
|
||||
if ((!before && before !== 0) || before < 0) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'Before is not a valid cursor'
|
||||
);
|
||||
}
|
||||
|
||||
if ((skip || 0) >= before) {
|
||||
// If the before index is less then the skip, no objects will be returned
|
||||
limit = 0;
|
||||
} else if ((!limit && limit !== 0) || (skip || 0) + limit > before) {
|
||||
// If there is no limit set, the limit is calculated. Or, if the limit (plus skip) is bigger than the before index, the new limit is set.
|
||||
limit = before - (skip || 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Validates the last param
|
||||
if (last || last === 0) {
|
||||
if (last < 0) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
'Last should be a positive number'
|
||||
);
|
||||
}
|
||||
|
||||
if (last > maxLimit) {
|
||||
// Last can't be bigger than Parse server maxLimit config.
|
||||
last = maxLimit;
|
||||
}
|
||||
|
||||
if (limit || limit === 0) {
|
||||
// If there is a previous limit set, it may be adjusted
|
||||
if (last < limit) {
|
||||
// if last is less than the current limit
|
||||
skip = (skip || 0) + (limit - last); // The skip is adjusted
|
||||
limit = last; // the limit is adjusted
|
||||
}
|
||||
} else if (last === 0) {
|
||||
// No objects will be returned
|
||||
limit = 0;
|
||||
} else {
|
||||
// No previous limit set, the limit will be equal to last and pre count is needed.
|
||||
limit = last;
|
||||
needToPreCount = true;
|
||||
}
|
||||
}
|
||||
return {
|
||||
skip,
|
||||
limit,
|
||||
needToPreCount,
|
||||
};
|
||||
};
|
||||
|
||||
export { getObject, findObjects, calculateSkipAndLimit };
|
||||
|
||||
Reference in New Issue
Block a user