fix: graphQL query ignores condition equalTo with value false (#8032)
This commit is contained in:
@@ -9516,6 +9516,130 @@ describe('ParseGraphQLServer', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should support where argument on object field that contains false boolean value or 0 number value', async () => {
|
||||
try {
|
||||
const someObjectFieldValue1 = {
|
||||
foo: { bar: true, baz: 100 },
|
||||
};
|
||||
|
||||
const someObjectFieldValue2 = {
|
||||
foo: { bar: false, baz: 0 },
|
||||
};
|
||||
|
||||
const object1 = new Parse.Object('SomeClass');
|
||||
await object1.save({
|
||||
someObjectField: someObjectFieldValue1,
|
||||
});
|
||||
const object2 = new Parse.Object('SomeClass');
|
||||
await object2.save({
|
||||
someObjectField: someObjectFieldValue2,
|
||||
});
|
||||
|
||||
const whereToObject1 = {
|
||||
someObjectField: {
|
||||
equalTo: { key: 'foo.bar', value: true },
|
||||
notEqualTo: { key: 'foo.baz', value: 0 },
|
||||
},
|
||||
};
|
||||
const whereToObject2 = {
|
||||
someObjectField: {
|
||||
notEqualTo: { key: 'foo.bar', value: true },
|
||||
equalTo: { key: 'foo.baz', value: 0 },
|
||||
},
|
||||
};
|
||||
|
||||
const whereToAll = {
|
||||
someObjectField: {
|
||||
lessThan: { key: 'foo.baz', value: 101 },
|
||||
},
|
||||
};
|
||||
|
||||
const whereToNone = {
|
||||
someObjectField: {
|
||||
notEqualTo: { key: 'foo.bar', value: true },
|
||||
equalTo: { key: 'foo.baz', value: 1 },
|
||||
},
|
||||
};
|
||||
|
||||
const queryResult = await apolloClient.query({
|
||||
query: gql`
|
||||
query GetSomeObject(
|
||||
$id1: ID!
|
||||
$id2: ID!
|
||||
$whereToObject1: SomeClassWhereInput
|
||||
$whereToObject2: SomeClassWhereInput
|
||||
$whereToAll: SomeClassWhereInput
|
||||
$whereToNone: SomeClassWhereInput
|
||||
) {
|
||||
obj1: someClass(id: $id1) {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
obj2: someClass(id: $id2) {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
onlyObj1: someClasses(where: $whereToObject1) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
}
|
||||
}
|
||||
onlyObj2: someClasses(where: $whereToObject2) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
}
|
||||
}
|
||||
all: someClasses(where: $whereToAll) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
}
|
||||
}
|
||||
none: someClasses(where: $whereToNone) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
someObjectField
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
id1: object1.id,
|
||||
id2: object2.id,
|
||||
whereToObject1,
|
||||
whereToObject2,
|
||||
whereToAll,
|
||||
whereToNone,
|
||||
},
|
||||
});
|
||||
|
||||
const { obj1, obj2, onlyObj1, onlyObj2, all, none } = queryResult.data;
|
||||
|
||||
expect(obj1.someObjectField).toEqual(someObjectFieldValue1);
|
||||
expect(obj2.someObjectField).toEqual(someObjectFieldValue2);
|
||||
|
||||
// Checks class query results
|
||||
expect(onlyObj1.edges.length).toEqual(1);
|
||||
expect(onlyObj1.edges[0].node.someObjectField).toEqual(someObjectFieldValue1);
|
||||
expect(onlyObj2.edges.length).toEqual(1);
|
||||
expect(onlyObj2.edges[0].node.someObjectField).toEqual(someObjectFieldValue2);
|
||||
expect(all.edges.length).toEqual(2);
|
||||
expect(none.edges.length).toEqual(0);
|
||||
} catch (e) {
|
||||
handleError(e);
|
||||
}
|
||||
});
|
||||
|
||||
it('should support object composed queries', async () => {
|
||||
try {
|
||||
const someObjectFieldValue1 = {
|
||||
|
||||
@@ -91,6 +91,22 @@ const toPostgresValue = value => {
|
||||
return value;
|
||||
};
|
||||
|
||||
const toPostgresValueCastType = value => {
|
||||
const postgresValue = toPostgresValue(value);
|
||||
let castType;
|
||||
switch (typeof postgresValue) {
|
||||
case 'number':
|
||||
castType = 'double precision';
|
||||
break;
|
||||
case 'boolean':
|
||||
castType = 'boolean';
|
||||
break;
|
||||
default:
|
||||
castType = undefined;
|
||||
}
|
||||
return castType;
|
||||
};
|
||||
|
||||
const transformValue = value => {
|
||||
if (typeof value === 'object' && value.__type === 'Pointer') {
|
||||
return value.objectId;
|
||||
@@ -369,9 +385,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
||||
);
|
||||
} else {
|
||||
if (fieldName.indexOf('.') >= 0) {
|
||||
const constraintFieldName = transformDotField(fieldName);
|
||||
const castType = toPostgresValueCastType(fieldValue.$ne);
|
||||
const constraintFieldName = castType
|
||||
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
||||
: transformDotField(fieldName);
|
||||
patterns.push(
|
||||
`(${constraintFieldName} <> $${index} OR ${constraintFieldName} IS NULL)`
|
||||
`(${constraintFieldName} <> $${index + 1} OR ${constraintFieldName} IS NULL)`
|
||||
);
|
||||
} else if (typeof fieldValue.$ne === 'object' && fieldValue.$ne.$relativeTime) {
|
||||
throw new Parse.Error(
|
||||
@@ -401,8 +420,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
||||
index += 1;
|
||||
} else {
|
||||
if (fieldName.indexOf('.') >= 0) {
|
||||
const castType = toPostgresValueCastType(fieldValue.$eq);
|
||||
const constraintFieldName = castType
|
||||
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
||||
: transformDotField(fieldName);
|
||||
values.push(fieldValue.$eq);
|
||||
patterns.push(`${transformDotField(fieldName)} = $${index++}`);
|
||||
patterns.push(`${constraintFieldName} = $${index++}`);
|
||||
} else if (typeof fieldValue.$eq === 'object' && fieldValue.$eq.$relativeTime) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_JSON,
|
||||
@@ -771,20 +794,11 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
||||
Object.keys(ParseToPosgresComparator).forEach(cmp => {
|
||||
if (fieldValue[cmp] || fieldValue[cmp] === 0) {
|
||||
const pgComparator = ParseToPosgresComparator[cmp];
|
||||
let postgresValue = toPostgresValue(fieldValue[cmp]);
|
||||
let constraintFieldName;
|
||||
let postgresValue = toPostgresValue(fieldValue[cmp]);
|
||||
|
||||
if (fieldName.indexOf('.') >= 0) {
|
||||
let castType;
|
||||
switch (typeof postgresValue) {
|
||||
case 'number':
|
||||
castType = 'double precision';
|
||||
break;
|
||||
case 'boolean':
|
||||
castType = 'boolean';
|
||||
break;
|
||||
default:
|
||||
castType = undefined;
|
||||
}
|
||||
const castType = toPostgresValueCastType(fieldValue[cmp]);
|
||||
constraintFieldName = castType
|
||||
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
||||
: transformDotField(fieldName);
|
||||
|
||||
@@ -108,7 +108,7 @@ const transformQueryConstraintInputToParse = (
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
if (fieldValue.key && fieldValue.value && parentConstraints && parentFieldName) {
|
||||
if (fieldValue.key && fieldValue.value !== undefined && parentConstraints && parentFieldName) {
|
||||
delete parentConstraints[parentFieldName];
|
||||
parentConstraints[`${parentFieldName}.${fieldValue.key}`] = {
|
||||
...parentConstraints[`${parentFieldName}.${fieldValue.key}`],
|
||||
|
||||
Reference in New Issue
Block a user