GraphQL Object constraints (#5715)

* GraphQL Object constraints

Implements the GraphQL Object constraints, which allows us to filter queries results using the `$eq`, `$lt`, `$gt`, `$in`, and other Parse supported constraints.
Example:
```
query objects {
  findMyClass(where: {
    objField: {
      _eq: {
        key: 'foo.bar',
        value: 'hello'
      },
      _gt: {
        key: 'foo.number',
        value: 10
      },
      _lt: {
        key: 'anotherNumber',
        value: 5
      }
    }
  }) {
    results {
      objectId
    }
  }
}
```
In the example above, we have the `findMyClass` query (automatically generated for the `MyClass` class), and a field named `objField` whose type is Object. The object below represents a valid `objField` value and would satisfy all constraints:
```
{
  "foo": {
    "bar": "hello",
    "number": 11
  },
  "anotherNumber": 4
}
```
The Object constraint is applied only when using Parse class object type queries. When using "generic" queries such as `get` and `find`, this type of constraint is not available.

* Objects constraints not working on Postgres

Fixes the $eq, $ne, $gt, and $lt constraints when applied on an Object type field.

* Fix object constraint field name

* Fix Postgres constraints indexes

* fix: Object type composed constraints not working

* fix: Rename key and value fields

* refactor: Object constraints for generic queries

* fix: Object constraints not working on Postgres
This commit is contained in:
Douglas Muraoka
2019-08-02 16:18:08 -03:00
committed by Antonio Davi Macedo Coelho de Castro
parent e0690d0c56
commit ef14ca530d
14 changed files with 778 additions and 500 deletions

View File

@@ -846,15 +846,34 @@ const ARRAY_CONSTRAINT = new GraphQLInputObjectType({
},
});
const KEY_VALUE = new GraphQLInputObjectType({
name: 'KeyValue',
description: 'An entry from an object, i.e., a pair of key and value.',
fields: {
_key: {
description: 'The key used to retrieve the value of this entry.',
type: new GraphQLNonNull(GraphQLString),
},
_value: {
description: 'The value of the entry. Could be any type of scalar data.',
type: new GraphQLNonNull(ANY),
},
},
});
const OBJECT_CONSTRAINT = new GraphQLInputObjectType({
name: 'ObjectConstraint',
description:
'The ObjectConstraint input type is used in operations that involve filtering objects by a field of type Object.',
'The ObjectConstraint input type is used in operations that involve filtering result by a field of type Object.',
fields: {
_eq: _eq(OBJECT),
_ne: _ne(OBJECT),
_in: _in(OBJECT),
_nin: _nin(OBJECT),
_eq: _eq(KEY_VALUE),
_ne: _ne(KEY_VALUE),
_in: _in(KEY_VALUE),
_nin: _nin(KEY_VALUE),
_lt: _lt(KEY_VALUE),
_lte: _lte(KEY_VALUE),
_gt: _gt(KEY_VALUE),
_gte: _gte(KEY_VALUE),
_exists,
_select,
_dontSelect,

View File

@@ -96,13 +96,51 @@ const parseMap = {
_point: '$point',
};
const transformToParse = constraints => {
const transformToParse = (constraints, parentFieldName, parentConstraints) => {
if (!constraints || typeof constraints !== 'object') {
return;
}
Object.keys(constraints).forEach(fieldName => {
let fieldValue = constraints[fieldName];
if (parseMap[fieldName]) {
/**
* If we have a key-value pair, we need to change the way the constraint is structured.
*
* Example:
* From:
* {
* "someField": {
* "_lt": {
* "_key":"foo.bar",
* "_value": 100
* },
* "_gt": {
* "_key":"foo.bar",
* "_value": 10
* }
* }
* }
*
* To:
* {
* "someField.foo.bar": {
* "$lt": 100,
* "$gt": 10
* }
* }
*/
if (
fieldValue._key &&
fieldValue._value &&
parentConstraints &&
parentFieldName
) {
delete parentConstraints[parentFieldName];
parentConstraints[`${parentFieldName}.${fieldValue._key}`] = {
...parentConstraints[`${parentFieldName}.${fieldValue._key}`],
[parseMap[fieldName]]: fieldValue._value,
};
} else if (parseMap[fieldName]) {
delete constraints[fieldName];
fieldName = parseMap[fieldName];
constraints[fieldName] = fieldValue;
@@ -160,7 +198,7 @@ const transformToParse = constraints => {
break;
}
if (typeof fieldValue === 'object') {
transformToParse(fieldValue);
transformToParse(fieldValue, fieldName, constraints);
}
});
};