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

@@ -5273,7 +5273,10 @@ describe('ParseGraphQLServer', () => {
});
it('should support object values', async () => {
const someFieldValue = { foo: 'bar' };
const someFieldValue = {
foo: { bar: 'baz' },
number: 10,
};
const createResult = await apolloClient.mutate({
mutation: gql`
@@ -5314,30 +5317,179 @@ describe('ParseGraphQLServer', () => {
},
});
const getResult = await apolloClient.query({
const where = {
someField: {
_eq: { _key: 'foo.bar', _value: 'baz' },
_ne: { _key: 'foo.bar', _value: 'bat' },
_gt: { _key: 'number', _value: 9 },
_lt: { _key: 'number', _value: 11 },
},
};
const queryResult = await apolloClient.query({
query: gql`
query GetSomeObject($objectId: ID!) {
query GetSomeObject(
$objectId: ID!
$where: SomeClassConstraints
$genericWhere: Object
) {
objects {
get(className: "SomeClass", objectId: $objectId)
findSomeClass(where: { someField: { _exists: true } }) {
findSomeClass(where: $where) {
results {
objectId
someField
}
}
find(className: "SomeClass", where: $genericWhere) {
results
}
}
}
`,
variables: {
objectId: createResult.data.objects.create.objectId,
where,
genericWhere: where, // where and genericWhere types are different
},
});
const { someField } = getResult.data.objects.get;
const {
get: getResult,
findSomeClass,
find,
} = queryResult.data.objects;
const { someField } = getResult;
expect(typeof someField).toEqual('object');
expect(someField).toEqual(someFieldValue);
expect(getResult.data.objects.findSomeClass.results.length).toEqual(
2
);
// Checks class query results
expect(findSomeClass.results.length).toEqual(2);
expect(findSomeClass.results[0].someField).toEqual(someFieldValue);
expect(findSomeClass.results[1].someField).toEqual(someFieldValue);
// Checks generic query results
expect(find.results.length).toEqual(2);
expect(find.results[0].someField).toEqual(someFieldValue);
expect(find.results[1].someField).toEqual(someFieldValue);
});
it('should support object composed queries', async () => {
const someFieldValue = {
lorem: 'ipsum',
number: 10,
};
const someFieldValue2 = {
foo: {
test: 'bar',
},
number: 10,
};
const createResult = await apolloClient.mutate({
mutation: gql`
mutation CreateSomeObject($fields: Object, $fields2: Object) {
objects {
create1: create(className: "SomeClass", fields: $fields) {
objectId
}
create2: create(className: "SomeClass", fields: $fields2) {
objectId
}
}
}
`,
variables: {
fields: {
someField: someFieldValue,
},
fields2: {
someField: someFieldValue2,
},
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
const where = {
_and: [
{
someField: {
_gt: { _key: 'number', _value: 9 },
},
},
{
someField: {
_lt: { _key: 'number', _value: 11 },
},
},
{
_or: [
{
someField: {
_eq: { _key: 'lorem', _value: 'ipsum' },
},
},
{
someField: {
_eq: { _key: 'foo.test', _value: 'bar' },
},
},
],
},
],
};
const findResult = await apolloClient.query({
query: gql`
query FindSomeObject(
$where: SomeClassConstraints
$genericWhere: Object
) {
objects {
findSomeClass(where: $where) {
results {
objectId
someField
}
}
find(className: "SomeClass", where: $genericWhere) {
results
}
}
}
`,
variables: {
where,
genericWhere: where, // where and genericWhere types are different
},
});
const { create1, create2 } = createResult.data.objects;
const { findSomeClass, find } = findResult.data.objects;
// Checks class query results
const { results } = findSomeClass;
expect(results.length).toEqual(2);
expect(
results.find(result => result.objectId === create1.objectId)
.someField
).toEqual(someFieldValue);
expect(
results.find(result => result.objectId === create2.objectId)
.someField
).toEqual(someFieldValue2);
// Checks generic query results
const { results: genericResults } = find;
expect(genericResults.length).toEqual(2);
expect(
genericResults.find(result => result.objectId === create1.objectId)
.someField
).toEqual(someFieldValue);
expect(
genericResults.find(result => result.objectId === create2.objectId)
.someField
).toEqual(someFieldValue2);
});
it('should support array values', async () => {