GraphQL: DX Relational Where Query (#6255)

* DX Relational Where Query

* Remove WherePointer & fix tests

* Add have, haveNot, exists on Pointer/Relation where input

* Merge branch 'master' into gql-relational-query

* Enable inQueryKey

* better descrption
This commit is contained in:
Antoine Cormouls
2019-12-05 19:14:16 +01:00
committed by Antonio Davi Macedo Coelho de Castro
parent afe49cb1f7
commit 5d76b2f354
7 changed files with 519 additions and 160 deletions

View File

@@ -1,7 +1,6 @@
import { fromGlobalId } from 'graphql-relay';
const parseQueryMap = {
id: 'objectId',
OR: '$or',
AND: '$and',
NOR: '$nor',
@@ -47,13 +46,44 @@ const parseConstraintMap = {
const transformQueryConstraintInputToParse = (
constraints,
fields,
parentFieldName,
parentConstraints
className,
parentConstraints,
parseClasses
) => {
const fields = parseClasses.find(
parseClass => parseClass.className === className
).fields;
if (parentFieldName === 'id' && className) {
Object.keys(constraints).forEach(constraintName => {
const constraintValue = constraints[constraintName];
if (typeof constraintValue === 'string') {
const globalIdObject = fromGlobalId(constraintValue);
if (globalIdObject.type === className) {
constraints[constraintName] = globalIdObject.id;
}
} else if (Array.isArray(constraintValue)) {
constraints[constraintName] = constraintValue.map(value => {
const globalIdObject = fromGlobalId(value);
if (globalIdObject.type === className) {
return globalIdObject.id;
}
return value;
});
}
});
parentConstraints.objectId = constraints;
delete parentConstraints.id;
}
Object.keys(constraints).forEach(fieldName => {
let fieldValue = constraints[fieldName];
if (parseConstraintMap[fieldName]) {
constraints[parseConstraintMap[fieldName]] = constraints[fieldName];
delete constraints[fieldName];
}
/**
* If we have a key-value pair, we need to change the way the constraint is structured.
*
@@ -91,30 +121,65 @@ const transformQueryConstraintInputToParse = (
...parentConstraints[`${parentFieldName}.${fieldValue.key}`],
[parseConstraintMap[fieldName]]: fieldValue.value,
};
} else if (parseConstraintMap[fieldName]) {
delete constraints[fieldName];
fieldName = parseConstraintMap[fieldName];
constraints[fieldName] = fieldValue;
// If parent field type is Pointer, changes constraint value to format expected
// by Parse.
if (
fields[parentFieldName] &&
fields[parentFieldName].type === 'Pointer' &&
typeof fieldValue === 'string'
) {
const { targetClass } = fields[parentFieldName];
let objectId = fieldValue;
const globalIdObject = fromGlobalId(objectId);
if (globalIdObject.type === targetClass) {
objectId = globalIdObject.id;
} else if (
fields[parentFieldName] &&
(fields[parentFieldName].type === 'Pointer' ||
fields[parentFieldName].type === 'Relation')
) {
const { targetClass } = fields[parentFieldName];
if (fieldName === 'exists') {
if (fields[parentFieldName].type === 'Relation') {
const whereTarget = fieldValue ? 'where' : 'notWhere';
if (constraints[whereTarget]) {
if (constraints[whereTarget].objectId) {
constraints[whereTarget].objectId = {
...constraints[whereTarget].objectId,
$exists: fieldValue,
};
} else {
constraints[whereTarget].objectId = {
$exists: fieldValue,
};
}
} else {
const parseWhereTarget = fieldValue ? '$inQuery' : '$notInQuery';
parentConstraints[parentFieldName][parseWhereTarget] = {
where: { objectId: { $exists: true } },
className: targetClass,
};
}
delete constraints.$exists;
} else {
parentConstraints[parentFieldName].$exists = fieldValue;
}
constraints[fieldName] = {
__type: 'Pointer',
className: targetClass,
objectId,
};
return;
}
switch (fieldName) {
case 'have':
parentConstraints[parentFieldName].$inQuery = {
where: fieldValue,
className: targetClass,
};
transformQueryInputToParse(
parentConstraints[parentFieldName].$inQuery.where,
targetClass,
parseClasses
);
break;
case 'haveNot':
parentConstraints[parentFieldName].$notInQuery = {
where: fieldValue,
className: targetClass,
};
transformQueryInputToParse(
parentConstraints[parentFieldName].$notInQuery.where,
targetClass,
parseClasses
);
break;
}
delete constraints[fieldName];
return;
}
switch (fieldName) {
case '$point':
@@ -170,20 +235,21 @@ const transformQueryConstraintInputToParse = (
}
if (typeof fieldValue === 'object') {
if (fieldName === 'where') {
transformQueryInputToParse(fieldValue);
transformQueryInputToParse(fieldValue, className, parseClasses);
} else {
transformQueryConstraintInputToParse(
fieldValue,
fields,
fieldName,
constraints
className,
constraints,
parseClasses
);
}
}
});
};
const transformQueryInputToParse = (constraints, fields, className) => {
const transformQueryInputToParse = (constraints, className, parseClasses) => {
if (!constraints || typeof constraints !== 'object') {
return;
}
@@ -195,42 +261,17 @@ const transformQueryInputToParse = (constraints, fields, className) => {
delete constraints[fieldName];
fieldName = parseQueryMap[fieldName];
constraints[fieldName] = fieldValue;
if (fieldName !== 'objectId') {
fieldValue.forEach(fieldValueItem => {
transformQueryInputToParse(fieldValueItem, fields, className);
});
return;
} else if (className) {
Object.keys(fieldValue).forEach(constraintName => {
const constraintValue = fieldValue[constraintName];
if (typeof constraintValue === 'string') {
const globalIdObject = fromGlobalId(constraintValue);
if (globalIdObject.type === className) {
fieldValue[constraintName] = globalIdObject.id;
}
} else if (Array.isArray(constraintValue)) {
fieldValue[constraintName] = constraintValue.map(value => {
const globalIdObject = fromGlobalId(value);
if (globalIdObject.type === className) {
return globalIdObject.id;
}
return value;
});
}
});
}
}
if (typeof fieldValue === 'object') {
fieldValue.forEach(fieldValueItem => {
transformQueryInputToParse(fieldValueItem, className, parseClasses);
});
return;
} else {
transformQueryConstraintInputToParse(
fieldValue,
fields,
fieldName,
constraints
className,
constraints,
parseClasses
);
}
});