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 () => {
|
it('should support object composed queries', async () => {
|
||||||
try {
|
try {
|
||||||
const someObjectFieldValue1 = {
|
const someObjectFieldValue1 = {
|
||||||
|
|||||||
@@ -91,6 +91,22 @@ const toPostgresValue = value => {
|
|||||||
return 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 => {
|
const transformValue = value => {
|
||||||
if (typeof value === 'object' && value.__type === 'Pointer') {
|
if (typeof value === 'object' && value.__type === 'Pointer') {
|
||||||
return value.objectId;
|
return value.objectId;
|
||||||
@@ -369,9 +385,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (fieldName.indexOf('.') >= 0) {
|
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(
|
patterns.push(
|
||||||
`(${constraintFieldName} <> $${index} OR ${constraintFieldName} IS NULL)`
|
`(${constraintFieldName} <> $${index + 1} OR ${constraintFieldName} IS NULL)`
|
||||||
);
|
);
|
||||||
} else if (typeof fieldValue.$ne === 'object' && fieldValue.$ne.$relativeTime) {
|
} else if (typeof fieldValue.$ne === 'object' && fieldValue.$ne.$relativeTime) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
@@ -401,8 +420,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
|||||||
index += 1;
|
index += 1;
|
||||||
} else {
|
} else {
|
||||||
if (fieldName.indexOf('.') >= 0) {
|
if (fieldName.indexOf('.') >= 0) {
|
||||||
|
const castType = toPostgresValueCastType(fieldValue.$eq);
|
||||||
|
const constraintFieldName = castType
|
||||||
|
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
||||||
|
: transformDotField(fieldName);
|
||||||
values.push(fieldValue.$eq);
|
values.push(fieldValue.$eq);
|
||||||
patterns.push(`${transformDotField(fieldName)} = $${index++}`);
|
patterns.push(`${constraintFieldName} = $${index++}`);
|
||||||
} else if (typeof fieldValue.$eq === 'object' && fieldValue.$eq.$relativeTime) {
|
} else if (typeof fieldValue.$eq === 'object' && fieldValue.$eq.$relativeTime) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
Parse.Error.INVALID_JSON,
|
Parse.Error.INVALID_JSON,
|
||||||
@@ -771,20 +794,11 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
|
|||||||
Object.keys(ParseToPosgresComparator).forEach(cmp => {
|
Object.keys(ParseToPosgresComparator).forEach(cmp => {
|
||||||
if (fieldValue[cmp] || fieldValue[cmp] === 0) {
|
if (fieldValue[cmp] || fieldValue[cmp] === 0) {
|
||||||
const pgComparator = ParseToPosgresComparator[cmp];
|
const pgComparator = ParseToPosgresComparator[cmp];
|
||||||
let postgresValue = toPostgresValue(fieldValue[cmp]);
|
|
||||||
let constraintFieldName;
|
let constraintFieldName;
|
||||||
|
let postgresValue = toPostgresValue(fieldValue[cmp]);
|
||||||
|
|
||||||
if (fieldName.indexOf('.') >= 0) {
|
if (fieldName.indexOf('.') >= 0) {
|
||||||
let castType;
|
const castType = toPostgresValueCastType(fieldValue[cmp]);
|
||||||
switch (typeof postgresValue) {
|
|
||||||
case 'number':
|
|
||||||
castType = 'double precision';
|
|
||||||
break;
|
|
||||||
case 'boolean':
|
|
||||||
castType = 'boolean';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
castType = undefined;
|
|
||||||
}
|
|
||||||
constraintFieldName = castType
|
constraintFieldName = castType
|
||||||
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
|
||||||
: transformDotField(fieldName);
|
: 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];
|
delete parentConstraints[parentFieldName];
|
||||||
parentConstraints[`${parentFieldName}.${fieldValue.key}`] = {
|
parentConstraints[`${parentFieldName}.${fieldValue.key}`] = {
|
||||||
...parentConstraints[`${parentFieldName}.${fieldValue.key}`],
|
...parentConstraints[`${parentFieldName}.${fieldValue.key}`],
|
||||||
|
|||||||
Reference in New Issue
Block a user