Skip to content

Commit ee40bda

Browse files
committed
fix: casting a value type of nested filed name
1 parent 32c7ab6 commit ee40bda

File tree

2 files changed

+91
-68
lines changed

2 files changed

+91
-68
lines changed

spec/ParseGraphQLServer.spec.js

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9518,84 +9518,92 @@ describe('ParseGraphQLServer', () => {
95189518

95199519
it('should support where argument on object field that contains false boolean value or 0 number value', async () => {
95209520
try {
9521-
const someObjectFieldValue = {
9522-
foo: { bar: 'baz', qux: true, quux: 100 },
9523-
number: 10,
9521+
const someObjectFieldValue1 = {
9522+
foo: { bar: true, baz: 100 },
95249523
};
95259524

9526-
const object = new Parse.Object('SomeClass');
9527-
await object.save({
9528-
someObjectField: someObjectFieldValue,
9525+
const someObjectFieldValue2 = {
9526+
foo: { bar: false, baz: 0 },
9527+
};
9528+
9529+
const object1 = new Parse.Object('SomeClass');
9530+
await object1.save({
9531+
someObjectField: someObjectFieldValue1,
9532+
});
9533+
const object2 = new Parse.Object('SomeClass');
9534+
await object2.save({
9535+
someObjectField: someObjectFieldValue2,
95299536
});
95309537

9531-
const whereWithQuxFalse = {
9538+
const whereToObject1 = {
95329539
someObjectField: {
9533-
notEqualTo: { key: 'foo.bar', value: 'bat' },
9534-
greaterThan: { key: 'number', value: 9 },
9535-
lessThan: { key: 'number', value: 11 },
9536-
equalTo: { key: 'foo.qux', value: false },
9540+
equalTo: { key: 'foo.bar', value: true },
9541+
notEqualTo: { key: 'foo.baz', value: 0 },
95379542
},
95389543
};
9539-
const whereWithQuxTrue = {
9544+
const whereToObject2 = {
95409545
someObjectField: {
9541-
...whereWithQuxFalse.someObjectField,
9542-
equalTo: { key: 'foo.qux', value: true },
9546+
notEqualTo: { key: 'foo.bar', value: true },
9547+
equalTo: { key: 'foo.baz', value: 0 },
95439548
},
95449549
};
9545-
const whereWithQuux0 = {
9550+
9551+
const whereToAll = {
95469552
someObjectField: {
9547-
notEqualTo: { key: 'foo.bar', value: 'bat' },
9548-
greaterThan: { key: 'number', value: 9 },
9549-
lessThan: { key: 'number', value: 11 },
9550-
equalTo: { key: 'foo.quux', value: 0 },
9553+
lessThan: { key: 'foo.baz', value: 101 },
95519554
},
95529555
};
9553-
const whereWithQuux100 = {
9556+
9557+
const whereToNone = {
95549558
someObjectField: {
9555-
notEqualTo: { key: 'foo.bar', value: 'bat' },
9556-
greaterThan: { key: 'number', value: 9 },
9557-
lessThan: { key: 'number', value: 11 },
9558-
equalTo: { key: 'foo.quux', value: 100 },
9559+
notEqualTo: { key: 'foo.bar', value: true },
9560+
equalTo: { key: 'foo.baz', value: 1 },
95599561
},
95609562
};
9563+
95619564
const queryResult = await apolloClient.query({
95629565
query: gql`
95639566
query GetSomeObject(
9564-
$id: ID!
9565-
$whereWithQuxFalse: SomeClassWhereInput
9566-
$whereWithQuxTrue: SomeClassWhereInput
9567-
$whereWithQuux0: SomeClassWhereInput
9568-
$whereWithQuux100: SomeClassWhereInput
9567+
$id1: ID!
9568+
$id2: ID!
9569+
$whereToObject1: SomeClassWhereInput
9570+
$whereToObject2: SomeClassWhereInput
9571+
$whereToAll: SomeClassWhereInput
9572+
$whereToNone: SomeClassWhereInput
95699573
) {
9570-
someClass(id: $id) {
9574+
obj1: someClass(id: $id1) {
95719575
id
95729576
someObjectField
95739577
}
9574-
someClasses(where: $whereWithQuxFalse) {
9578+
obj2: someClass(id: $id2) {
9579+
id
9580+
someObjectField
9581+
}
9582+
onlyObj1: someClasses(where: $whereToObject1) {
95759583
edges {
95769584
node {
95779585
id
95789586
someObjectField
95799587
}
95809588
}
95819589
}
9582-
someClassesWithQuxTrue: someClasses(where: $whereWithQuxTrue) {
9590+
onlyObj2: someClasses(where: $whereToObject2) {
95839591
edges {
95849592
node {
95859593
id
95869594
someObjectField
95879595
}
95889596
}
95899597
}
9590-
someClassesWithQuux0: someClasses(where: $whereWithQuux0) {
9598+
all: someClasses(where: $whereToAll) {
95919599
edges {
95929600
node {
95939601
id
95949602
someObjectField
95959603
}
95969604
}
95979605
}
9598-
someClassesWithQuux100: someClasses(where: $whereWithQuux100) {
9606+
none: someClasses(where: $whereToNone) {
95999607
edges {
96009608
node {
96019609
id
@@ -9606,31 +9614,27 @@ describe('ParseGraphQLServer', () => {
96069614
}
96079615
`,
96089616
variables: {
9609-
id: object.id,
9610-
whereWithQuxFalse,
9611-
whereWithQuxTrue,
9612-
whereWithQuux0,
9613-
whereWithQuux100,
9617+
id1: object1.id,
9618+
id2: object2.id,
9619+
whereToObject1,
9620+
whereToObject2,
9621+
whereToAll,
9622+
whereToNone,
96149623
},
96159624
});
96169625

9617-
const {
9618-
someClass: getResult,
9619-
someClasses,
9620-
someClassesWithQuxTrue,
9621-
someClassesWithQuux0,
9622-
someClassesWithQuux100,
9623-
} = queryResult.data;
9626+
const { obj1, obj2, onlyObj1, onlyObj2, all, none } = queryResult.data;
96249627

9625-
const { someObjectField } = getResult;
9626-
expect(someObjectField).toEqual(someObjectFieldValue);
9628+
expect(obj1.someObjectField).toEqual(someObjectFieldValue1);
9629+
expect(obj2.someObjectField).toEqual(someObjectFieldValue2);
96279630

96289631
// Checks class query results
9629-
expect(someClasses.edges.length).toEqual(0);
9630-
expect(someClassesWithQuxTrue.edges.length).toEqual(1);
9631-
9632-
expect(someClassesWithQuux0.edges.length).toEqual(0);
9633-
expect(someClassesWithQuux100.edges.length).toEqual(1);
9632+
expect(onlyObj1.edges.length).toEqual(1);
9633+
expect(onlyObj1.edges[0].node.someObjectField).toEqual(someObjectFieldValue1);
9634+
expect(onlyObj2.edges.length).toEqual(1);
9635+
expect(onlyObj2.edges[0].node.someObjectField).toEqual(someObjectFieldValue2);
9636+
expect(all.edges.length).toEqual(2);
9637+
expect(none.edges.length).toEqual(0);
96349638
} catch (e) {
96359639
handleError(e);
96369640
}

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ const toPostgresValue = value => {
9191
return value;
9292
};
9393

94+
const toPostgresValueCastType = value => {
95+
const postgresValue = toPostgresValue(value);
96+
let castType;
97+
switch (typeof postgresValue) {
98+
case 'number':
99+
castType = 'double precision';
100+
break;
101+
case 'boolean':
102+
castType = 'boolean';
103+
break;
104+
default:
105+
castType = undefined;
106+
}
107+
return castType;
108+
};
109+
94110
const transformValue = value => {
95111
if (typeof value === 'object' && value.__type === 'Pointer') {
96112
return value.objectId;
@@ -191,6 +207,10 @@ const transformDotFieldToComponents = fieldName => {
191207
if (index === 0) {
192208
return `"${cmpt}"`;
193209
}
210+
if (parseInt(cmpt).toString() === cmpt) {
211+
return `${cmpt}`;
212+
}
213+
194214
return `'${cmpt}'`;
195215
});
196216
};
@@ -369,9 +389,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
369389
);
370390
} else {
371391
if (fieldName.indexOf('.') >= 0) {
372-
const constraintFieldName = transformDotField(fieldName);
392+
const castType = toPostgresValueCastType(fieldValue.$ne);
393+
const constraintFieldName = castType
394+
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
395+
: transformDotField(fieldName);
373396
patterns.push(
374-
`(${constraintFieldName} <> $${index} OR ${constraintFieldName} IS NULL)`
397+
`(${constraintFieldName} <> $${index + 1} OR ${constraintFieldName} IS NULL)`
375398
);
376399
} else if (typeof fieldValue.$ne === 'object' && fieldValue.$ne.$relativeTime) {
377400
throw new Parse.Error(
@@ -401,8 +424,12 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
401424
index += 1;
402425
} else {
403426
if (fieldName.indexOf('.') >= 0) {
427+
const castType = toPostgresValueCastType(fieldValue.$eq);
428+
const constraintFieldName = castType
429+
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
430+
: transformDotField(fieldName);
404431
values.push(fieldValue.$eq);
405-
patterns.push(`${transformDotField(fieldName)} = $${index++}`);
432+
patterns.push(`${constraintFieldName} = $${index++}`);
406433
} else if (typeof fieldValue.$eq === 'object' && fieldValue.$eq.$relativeTime) {
407434
throw new Parse.Error(
408435
Parse.Error.INVALID_JSON,
@@ -771,20 +798,11 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
771798
Object.keys(ParseToPosgresComparator).forEach(cmp => {
772799
if (fieldValue[cmp] || fieldValue[cmp] === 0) {
773800
const pgComparator = ParseToPosgresComparator[cmp];
774-
let postgresValue = toPostgresValue(fieldValue[cmp]);
775801
let constraintFieldName;
802+
let postgresValue = toPostgresValue(fieldValue[cmp]);
803+
776804
if (fieldName.indexOf('.') >= 0) {
777-
let castType;
778-
switch (typeof postgresValue) {
779-
case 'number':
780-
castType = 'double precision';
781-
break;
782-
case 'boolean':
783-
castType = 'boolean';
784-
break;
785-
default:
786-
castType = undefined;
787-
}
805+
const castType = toPostgresValueCastType(fieldValue[cmp]);
788806
constraintFieldName = castType
789807
? `CAST ((${transformDotField(fieldName)}) AS ${castType})`
790808
: transformDotField(fieldName);
@@ -823,6 +841,7 @@ const buildWhereClause = ({ schema, query, index, caseInsensitive }): WhereClaus
823841
}
824842
}
825843
values = values.map(transformValue);
844+
826845
return { pattern: patterns.join(' AND '), values, sorts };
827846
};
828847

0 commit comments

Comments
 (0)