GraphQL DX: Relation/Pointer (#5946)
* Add a test on deep complex GraphQL Query * Relation/Pointer new DX + deep nested mutations * Fix lint * Review * Remove unnecessary code * Fix objectId on update
This commit is contained in:
committed by
Antonio Davi Macedo Coelho de Castro
parent
89e8868a85
commit
5b3a492965
@@ -1643,7 +1643,6 @@ describe('ParseGraphQLServer', () => {
|
||||
obj2.set('someClassField', 'imSomeClassTwo');
|
||||
await obj2.save();
|
||||
|
||||
//const obj3Relation = obj3.relation('manyRelations')
|
||||
obj3.set('manyRelations', [obj1, obj2]);
|
||||
await obj3.save();
|
||||
|
||||
@@ -1704,6 +1703,119 @@ describe('ParseGraphQLServer', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it_only_db('mongo')(
|
||||
'should return many child objects in allow cyclic query',
|
||||
async () => {
|
||||
const obj1 = new Parse.Object('Employee');
|
||||
const obj2 = new Parse.Object('Team');
|
||||
const obj3 = new Parse.Object('Company');
|
||||
const obj4 = new Parse.Object('Country');
|
||||
|
||||
obj1.set('name', 'imAnEmployee');
|
||||
await obj1.save();
|
||||
|
||||
obj2.set('name', 'imATeam');
|
||||
obj2.set('employees', [obj1]);
|
||||
await obj2.save();
|
||||
|
||||
obj3.set('name', 'imACompany');
|
||||
obj3.set('teams', [obj2]);
|
||||
obj3.set('employees', [obj1]);
|
||||
await obj3.save();
|
||||
|
||||
obj4.set('name', 'imACountry');
|
||||
obj4.set('companies', [obj3]);
|
||||
await obj4.save();
|
||||
|
||||
obj1.set('country', obj4);
|
||||
await obj1.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const result = (await apolloClient.query({
|
||||
query: gql`
|
||||
query DeepComplexGraphQLQuery($objectId: ID!) {
|
||||
country(objectId: $objectId) {
|
||||
objectId
|
||||
name
|
||||
companies {
|
||||
... on Company {
|
||||
objectId
|
||||
name
|
||||
employees {
|
||||
... on Employee {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
teams {
|
||||
... on Team {
|
||||
objectId
|
||||
name
|
||||
employees {
|
||||
... on Employee {
|
||||
objectId
|
||||
name
|
||||
country {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: obj4.id,
|
||||
},
|
||||
})).data.country;
|
||||
|
||||
const expectedResult = {
|
||||
objectId: obj4.id,
|
||||
name: 'imACountry',
|
||||
__typename: 'Country',
|
||||
companies: [
|
||||
{
|
||||
objectId: obj3.id,
|
||||
name: 'imACompany',
|
||||
__typename: 'Company',
|
||||
employees: [
|
||||
{
|
||||
objectId: obj1.id,
|
||||
name: 'imAnEmployee',
|
||||
__typename: 'Employee',
|
||||
},
|
||||
],
|
||||
teams: [
|
||||
{
|
||||
objectId: obj2.id,
|
||||
name: 'imATeam',
|
||||
__typename: 'Team',
|
||||
employees: [
|
||||
{
|
||||
objectId: obj1.id,
|
||||
name: 'imAnEmployee',
|
||||
__typename: 'Employee',
|
||||
country: {
|
||||
objectId: obj4.id,
|
||||
name: 'imACountry',
|
||||
__typename: 'Country',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(result).toEqual(expectedResult);
|
||||
}
|
||||
);
|
||||
|
||||
it('should respect level permissions', async () => {
|
||||
await prepareData();
|
||||
|
||||
@@ -3321,6 +3433,41 @@ describe('ParseGraphQLServer', () => {
|
||||
expect(obj.get('someField2')).toEqual('someField2Value1');
|
||||
});
|
||||
|
||||
it('should return only objectId using class specific mutation', async () => {
|
||||
const obj = new Parse.Object('Customer');
|
||||
obj.set('someField1', 'someField1Value1');
|
||||
obj.set('someField2', 'someField2Value1');
|
||||
await obj.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const result = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation UpdateCustomer(
|
||||
$objectId: ID!
|
||||
$fields: UpdateCustomerFieldsInput
|
||||
) {
|
||||
updateCustomer(objectId: $objectId, fields: $fields) {
|
||||
objectId
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: obj.id,
|
||||
fields: {
|
||||
someField1: 'someField1Value2',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.data.updateCustomer.objectId).toEqual(obj.id);
|
||||
|
||||
await obj.fetch();
|
||||
|
||||
expect(obj.get('someField1')).toEqual('someField1Value2');
|
||||
expect(obj.get('someField2')).toEqual('someField2Value1');
|
||||
});
|
||||
|
||||
it('should respect level permissions', async () => {
|
||||
await prepareData();
|
||||
|
||||
@@ -4759,255 +4906,541 @@ describe('ParseGraphQLServer', () => {
|
||||
expect(Date.parse(getResult.data.get.updatedAt)).not.toEqual(NaN);
|
||||
});
|
||||
|
||||
it('should support pointer values', async () => {
|
||||
const parent = new Parse.Object('ParentClass');
|
||||
await parent.save();
|
||||
it('should support pointer on create', async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const pointerFieldValue = {
|
||||
__type: 'Pointer',
|
||||
className: 'ParentClass',
|
||||
objectId: parent.id,
|
||||
};
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.set('company', company);
|
||||
await country.save();
|
||||
|
||||
const createResult = await apolloClient.mutate({
|
||||
const company2 = new Parse.Object('Company');
|
||||
company2.set('name', 'imACompany2');
|
||||
await company2.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { createCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateChildObject($fields: Object) {
|
||||
create(className: "ChildClass", fields: $fields) {
|
||||
mutation Create($fields: CreateCountryFieldsInput) {
|
||||
createCountry(fields: $fields) {
|
||||
objectId
|
||||
company {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
pointerField: pointerFieldValue,
|
||||
name: 'imCountry2',
|
||||
company: { link: { objectId: company2.id } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const schema = await new Parse.Schema('ChildClass').get();
|
||||
expect(schema.fields.pointerField.type).toEqual('Pointer');
|
||||
expect(schema.fields.pointerField.targetClass).toEqual('ParentClass');
|
||||
|
||||
await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateChildObject(
|
||||
$fields1: CreateChildClassFieldsInput
|
||||
$fields2: CreateChildClassFieldsInput
|
||||
) {
|
||||
createChildClass1: createChildClass(fields: $fields1) {
|
||||
objectId
|
||||
}
|
||||
createChildClass2: createChildClass(fields: $fields2) {
|
||||
objectId
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields1: {
|
||||
pointerField: pointerFieldValue,
|
||||
},
|
||||
fields2: {
|
||||
pointerField: pointerFieldValue.objectId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const getResult = await apolloClient.query({
|
||||
query: gql`
|
||||
query GetChildObject(
|
||||
$objectId: ID!
|
||||
$pointerFieldValue1: ParentClassPointer
|
||||
$pointerFieldValue2: ParentClassPointer
|
||||
) {
|
||||
get(className: "ChildClass", objectId: $objectId)
|
||||
findChildClass1: childClasses(
|
||||
where: { pointerField: { _eq: $pointerFieldValue1 } }
|
||||
) {
|
||||
results {
|
||||
pointerField {
|
||||
objectId
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
findChildClass2: childClasses(
|
||||
where: { pointerField: { _eq: $pointerFieldValue2 } }
|
||||
) {
|
||||
results {
|
||||
pointerField {
|
||||
objectId
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: createResult.data.create.objectId,
|
||||
pointerFieldValue1: pointerFieldValue,
|
||||
pointerFieldValue2: pointerFieldValue.objectId,
|
||||
},
|
||||
});
|
||||
|
||||
expect(typeof getResult.data.get.pointerField).toEqual('object');
|
||||
expect(getResult.data.get.pointerField).toEqual(pointerFieldValue);
|
||||
expect(getResult.data.findChildClass1.results.length).toEqual(3);
|
||||
expect(getResult.data.findChildClass2.results.length).toEqual(3);
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.company.objectId).toEqual(company2.id);
|
||||
expect(result.company.name).toEqual('imACompany2');
|
||||
});
|
||||
|
||||
it_only_db('mongo')('should support relation', async () => {
|
||||
const someObject1 = new Parse.Object('SomeClass');
|
||||
await someObject1.save();
|
||||
const someObject2 = new Parse.Object('SomeClass');
|
||||
await someObject2.save();
|
||||
it('should support nested pointer on create', async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const pointerValue1 = {
|
||||
__type: 'Pointer',
|
||||
className: 'SomeClass',
|
||||
objectId: someObject1.id,
|
||||
};
|
||||
const pointerValue2 = {
|
||||
__type: 'Pointer',
|
||||
className: 'SomeClass',
|
||||
objectId: someObject2.id,
|
||||
};
|
||||
|
||||
const createResult = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateMainObject($fields: Object) {
|
||||
create(className: "MainClass", fields: $fields) {
|
||||
objectId
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
relationField: {
|
||||
__op: 'Batch',
|
||||
ops: [
|
||||
{
|
||||
__op: 'AddRelation',
|
||||
objects: [pointerValue1],
|
||||
},
|
||||
{
|
||||
__op: 'AddRelation',
|
||||
objects: [pointerValue2],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.set('company', company);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const schema = await new Parse.Schema('MainClass').get();
|
||||
expect(schema.fields.relationField.type).toEqual('Relation');
|
||||
expect(schema.fields.relationField.targetClass).toEqual('SomeClass');
|
||||
|
||||
await apolloClient.mutate({
|
||||
const {
|
||||
data: { createCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateMainObject($fields: CreateMainClassFieldsInput) {
|
||||
createMainClass(fields: $fields) {
|
||||
mutation Create($fields: CreateCountryFieldsInput) {
|
||||
createCountry(fields: $fields) {
|
||||
objectId
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
relationField: {
|
||||
_op: 'Batch',
|
||||
ops: [
|
||||
{
|
||||
_op: 'AddRelation',
|
||||
objects: [pointerValue1],
|
||||
},
|
||||
{
|
||||
_op: 'RemoveRelation',
|
||||
objects: [pointerValue1],
|
||||
},
|
||||
{
|
||||
_op: 'AddRelation',
|
||||
objects: [pointerValue2],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const getResult = await apolloClient.query({
|
||||
query: gql`
|
||||
query GetMainObject($objectId: ID!) {
|
||||
get(className: "MainClass", objectId: $objectId)
|
||||
mainClass(objectId: $objectId) {
|
||||
relationField {
|
||||
results {
|
||||
objectId
|
||||
createdAt
|
||||
}
|
||||
count
|
||||
company {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: createResult.data.create.objectId,
|
||||
},
|
||||
});
|
||||
|
||||
expect(typeof getResult.data.get.relationField).toEqual('object');
|
||||
expect(getResult.data.get.relationField).toEqual({
|
||||
__type: 'Relation',
|
||||
className: 'SomeClass',
|
||||
});
|
||||
expect(getResult.data.mainClass.relationField.results.length).toEqual(
|
||||
2
|
||||
);
|
||||
expect(getResult.data.mainClass.relationField.count).toEqual(2);
|
||||
|
||||
const findResult = await apolloClient.query({
|
||||
query: gql`
|
||||
query FindSomeObjects($where: Object) {
|
||||
find(className: "SomeClass", where: $where) {
|
||||
results
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
where: {
|
||||
$relatedTo: {
|
||||
object: {
|
||||
__type: 'Pointer',
|
||||
className: 'MainClass',
|
||||
objectId: createResult.data.create.objectId,
|
||||
fields: {
|
||||
name: 'imCountry2',
|
||||
company: {
|
||||
createAndLink: {
|
||||
name: 'imACompany2',
|
||||
},
|
||||
key: 'relationField',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const compare = (obj1, obj2) =>
|
||||
obj1.createdAt > obj2.createdAt ? 1 : -1;
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.company.objectId).toBeDefined();
|
||||
expect(result.company.name).toEqual('imACompany2');
|
||||
});
|
||||
|
||||
expect(findResult.data.find.results).toEqual(jasmine.any(Array));
|
||||
expect(findResult.data.find.results.sort(compare)).toEqual(
|
||||
[
|
||||
{
|
||||
objectId: someObject1.id,
|
||||
createdAt: someObject1.createdAt.toISOString(),
|
||||
updatedAt: someObject1.updatedAt.toISOString(),
|
||||
it('should support pointer on update', async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.set('company', company);
|
||||
await country.save();
|
||||
|
||||
const company2 = new Parse.Object('Company');
|
||||
company2.set('name', 'imACompany2');
|
||||
await company2.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { updateCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation Update(
|
||||
$objectId: ID!
|
||||
$fields: UpdateCountryFieldsInput
|
||||
) {
|
||||
updateCountry(objectId: $objectId, fields: $fields) {
|
||||
objectId
|
||||
company {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: country.id,
|
||||
fields: {
|
||||
company: { link: { objectId: company2.id } },
|
||||
},
|
||||
{
|
||||
objectId: someObject2.id,
|
||||
createdAt: someObject2.createdAt.toISOString(),
|
||||
updatedAt: someObject2.updatedAt.toISOString(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.company.objectId).toEqual(company2.id);
|
||||
expect(result.company.name).toEqual('imACompany2');
|
||||
});
|
||||
|
||||
it('should support nested pointer on update', async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.set('company', company);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { updateCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation Update(
|
||||
$objectId: ID!
|
||||
$fields: UpdateCountryFieldsInput
|
||||
) {
|
||||
updateCountry(objectId: $objectId, fields: $fields) {
|
||||
objectId
|
||||
company {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: country.id,
|
||||
fields: {
|
||||
company: {
|
||||
createAndLink: {
|
||||
name: 'imACompany2',
|
||||
},
|
||||
},
|
||||
},
|
||||
].sort(compare)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.company.objectId).toBeDefined();
|
||||
expect(result.company.name).toEqual('imACompany2');
|
||||
});
|
||||
|
||||
it_only_db('mongo')(
|
||||
'should support relation and nested relation on create',
|
||||
async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.relation('companies').add(company);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { createCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateCountry($fields: CreateCountryFieldsInput) {
|
||||
createCountry(fields: $fields) {
|
||||
objectId
|
||||
name
|
||||
companies {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
name: 'imACountry2',
|
||||
companies: {
|
||||
add: [{ objectId: company.id }],
|
||||
createAndAdd: [
|
||||
{
|
||||
name: 'imACompany2',
|
||||
},
|
||||
{
|
||||
name: 'imACompany3',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.name).toEqual('imACountry2');
|
||||
expect(result.companies.results.length).toEqual(3);
|
||||
expect(
|
||||
result.companies.results.some(o => o.objectId === company.id)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.companies.results.some(o => o.name === 'imACompany2')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.companies.results.some(o => o.name === 'imACompany3')
|
||||
).toBeTruthy();
|
||||
}
|
||||
);
|
||||
|
||||
it_only_db('mongo')('should support deep nested creation', async () => {
|
||||
const team = new Parse.Object('Team');
|
||||
team.set('name', 'imATeam1');
|
||||
await team.save();
|
||||
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
company.relation('teams').add(team);
|
||||
await company.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.relation('companies').add(company);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { createCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateCountry($fields: CreateCountryFieldsInput) {
|
||||
createCountry(fields: $fields) {
|
||||
objectId
|
||||
name
|
||||
companies {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
teams {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
fields: {
|
||||
name: 'imACountry2',
|
||||
companies: {
|
||||
createAndAdd: [
|
||||
{
|
||||
name: 'imACompany2',
|
||||
teams: {
|
||||
createAndAdd: {
|
||||
name: 'imATeam2',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'imACompany3',
|
||||
teams: {
|
||||
createAndAdd: {
|
||||
name: 'imATeam3',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.name).toEqual('imACountry2');
|
||||
expect(result.companies.results.length).toEqual(2);
|
||||
expect(
|
||||
result.companies.results.some(
|
||||
c =>
|
||||
c.name === 'imACompany2' &&
|
||||
c.teams.results.some(t => t.name === 'imATeam2')
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.companies.results.some(
|
||||
c =>
|
||||
c.name === 'imACompany3' &&
|
||||
c.teams.results.some(t => t.name === 'imATeam3')
|
||||
)
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it_only_db('mongo')(
|
||||
'should support relation and nested relation on update',
|
||||
async () => {
|
||||
const company1 = new Parse.Object('Company');
|
||||
company1.set('name', 'imACompany1');
|
||||
await company1.save();
|
||||
|
||||
const company2 = new Parse.Object('Company');
|
||||
company2.set('name', 'imACompany2');
|
||||
await company2.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.relation('companies').add(company1);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { updateCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation UpdateCountry(
|
||||
$objectId: ID!
|
||||
$fields: UpdateCountryFieldsInput
|
||||
) {
|
||||
updateCountry(objectId: $objectId, fields: $fields) {
|
||||
objectId
|
||||
companies {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: country.id,
|
||||
fields: {
|
||||
companies: {
|
||||
add: [{ objectId: company2.id }],
|
||||
remove: [{ objectId: company1.id }],
|
||||
createAndAdd: [
|
||||
{
|
||||
name: 'imACompany3',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toEqual(country.id);
|
||||
expect(result.companies.results.length).toEqual(2);
|
||||
expect(
|
||||
result.companies.results.some(o => o.objectId === company2.id)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.companies.results.some(o => o.name === 'imACompany3')
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result.companies.results.some(o => o.objectId === company1.id)
|
||||
).toBeFalsy();
|
||||
}
|
||||
);
|
||||
|
||||
it_only_db('mongo')(
|
||||
'should support nested relation on create with filter',
|
||||
async () => {
|
||||
const company = new Parse.Object('Company');
|
||||
company.set('name', 'imACompany1');
|
||||
await company.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.relation('companies').add(company);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
const {
|
||||
data: { createCountry: result },
|
||||
} = await apolloClient.mutate({
|
||||
mutation: gql`
|
||||
mutation CreateCountry(
|
||||
$fields: CreateCountryFieldsInput
|
||||
$where: CompanyWhereInput
|
||||
) {
|
||||
createCountry(fields: $fields) {
|
||||
objectId
|
||||
name
|
||||
companies(where: $where) {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
where: {
|
||||
name: {
|
||||
_eq: 'imACompany2',
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
name: 'imACountry2',
|
||||
companies: {
|
||||
add: [{ objectId: company.id }],
|
||||
createAndAdd: [
|
||||
{
|
||||
name: 'imACompany2',
|
||||
},
|
||||
{
|
||||
name: 'imACompany3',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.objectId).toBeDefined();
|
||||
expect(result.name).toEqual('imACountry2');
|
||||
expect(result.companies.results.length).toEqual(1);
|
||||
expect(
|
||||
result.companies.results.some(o => o.name === 'imACompany2')
|
||||
).toBeTruthy();
|
||||
}
|
||||
);
|
||||
|
||||
it_only_db('mongo')('should support relation on query', async () => {
|
||||
const company1 = new Parse.Object('Company');
|
||||
company1.set('name', 'imACompany1');
|
||||
await company1.save();
|
||||
|
||||
const company2 = new Parse.Object('Company');
|
||||
company2.set('name', 'imACompany2');
|
||||
await company2.save();
|
||||
|
||||
const country = new Parse.Object('Country');
|
||||
country.set('name', 'imACountry');
|
||||
country.relation('companies').add([company1, company2]);
|
||||
await country.save();
|
||||
|
||||
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
|
||||
|
||||
// Without where
|
||||
const {
|
||||
data: { country: result1 },
|
||||
} = await apolloClient.query({
|
||||
query: gql`
|
||||
query getCountry($objectId: ID!) {
|
||||
country(objectId: $objectId) {
|
||||
objectId
|
||||
companies {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: country.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result1.objectId).toEqual(country.id);
|
||||
expect(result1.companies.results.length).toEqual(2);
|
||||
expect(
|
||||
result1.companies.results.some(o => o.objectId === company1.id)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
result1.companies.results.some(o => o.objectId === company2.id)
|
||||
).toBeTruthy();
|
||||
|
||||
// With where
|
||||
const {
|
||||
data: { country: result2 },
|
||||
} = await apolloClient.query({
|
||||
query: gql`
|
||||
query getCountry($objectId: ID!, $where: CompanyWhereInput) {
|
||||
country(objectId: $objectId) {
|
||||
objectId
|
||||
companies(where: $where) {
|
||||
results {
|
||||
objectId
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
objectId: country.id,
|
||||
where: {
|
||||
name: { _eq: 'imACompany1' },
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result2.objectId).toEqual(country.id);
|
||||
expect(result2.companies.results.length).toEqual(1);
|
||||
expect(result2.companies.results[0].objectId).toEqual(company1.id);
|
||||
});
|
||||
|
||||
it('should support files', async () => {
|
||||
|
||||
@@ -395,14 +395,14 @@ const POLYGON_INPUT = new GraphQLList(new GraphQLNonNull(GEO_POINT_INPUT));
|
||||
|
||||
const POLYGON = new GraphQLList(new GraphQLNonNull(GEO_POINT));
|
||||
|
||||
const RELATION_OP = new GraphQLEnumType({
|
||||
name: 'RelationOp',
|
||||
description:
|
||||
'The RelationOp enum type is used to specify which kind of operation should be executed to a relation.',
|
||||
values: {
|
||||
Batch: { value: 'Batch' },
|
||||
AddRelation: { value: 'AddRelation' },
|
||||
RemoveRelation: { value: 'RemoveRelation' },
|
||||
const RELATION_INPUT = new GraphQLInputObjectType({
|
||||
name: 'RelationInput',
|
||||
description: 'Object involved into a relation',
|
||||
fields: {
|
||||
objectId: {
|
||||
description: 'Id of the object involved.',
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -491,6 +491,17 @@ const INCLUDE_ATT = {
|
||||
type: GraphQLString,
|
||||
};
|
||||
|
||||
const POINTER_INPUT = new GraphQLInputObjectType({
|
||||
name: 'PointerInput',
|
||||
description: 'Allow to link an object to another object',
|
||||
fields: {
|
||||
objectId: {
|
||||
description: 'Id of the object involved.',
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const READ_PREFERENCE = new GraphQLEnumType({
|
||||
name: 'ReadPreference',
|
||||
description:
|
||||
@@ -1080,7 +1091,6 @@ const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.addGraphQLType(FILE_INFO, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_POINT_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(GEO_POINT, true);
|
||||
parseGraphQLSchema.addGraphQLType(RELATION_OP, true);
|
||||
parseGraphQLSchema.addGraphQLType(CREATE_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(UPDATE_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(CLASS, true);
|
||||
@@ -1108,6 +1118,8 @@ const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.addGraphQLType(FIND_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(SIGN_UP_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ELEMENT, true);
|
||||
parseGraphQLSchema.addGraphQLType(RELATION_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(POINTER_INPUT, true);
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -1133,7 +1145,6 @@ export {
|
||||
GEO_POINT,
|
||||
POLYGON_INPUT,
|
||||
POLYGON,
|
||||
RELATION_OP,
|
||||
CLASS_NAME_ATT,
|
||||
FIELDS_ATT,
|
||||
OBJECT_ID_ATT,
|
||||
@@ -1195,6 +1206,8 @@ export {
|
||||
SIGN_UP_RESULT,
|
||||
ARRAY_RESULT,
|
||||
ELEMENT,
|
||||
POINTER_INPUT,
|
||||
RELATION_INPUT,
|
||||
load,
|
||||
loadArrayResult,
|
||||
};
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { GraphQLNonNull, GraphQLBoolean } from 'graphql';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import rest from '../../rest';
|
||||
import { transformMutationInputToParse } from '../transformers/mutation';
|
||||
|
||||
const createObject = async (className, fields, config, auth, info) => {
|
||||
if (!fields) {
|
||||
fields = {};
|
||||
}
|
||||
|
||||
transformMutationInputToParse(fields);
|
||||
|
||||
return (await rest.create(config, auth, className, fields, info.clientSDK))
|
||||
.response;
|
||||
};
|
||||
@@ -26,8 +23,6 @@ const updateObject = async (
|
||||
fields = {};
|
||||
}
|
||||
|
||||
transformMutationInputToParse(fields);
|
||||
|
||||
return (await rest.update(
|
||||
config,
|
||||
auth,
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import { GraphQLNonNull } from 'graphql';
|
||||
import getFieldNames from 'graphql-list-fields';
|
||||
import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import { extractKeysAndInclude } from '../parseGraphQLUtils';
|
||||
import {
|
||||
extractKeysAndInclude,
|
||||
getParseClassMutationConfig,
|
||||
} from '../parseGraphQLUtils';
|
||||
import * as objectsMutations from './objectsMutations';
|
||||
import * as objectsQueries from './objectsQueries';
|
||||
import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController';
|
||||
import { transformClassNameToGraphQL } from '../transformers/className';
|
||||
|
||||
const getParseClassMutationConfig = function(
|
||||
parseClassConfig: ?ParseGraphQLClassConfig
|
||||
) {
|
||||
return (parseClassConfig && parseClassConfig.mutation) || {};
|
||||
};
|
||||
import { transformTypes } from '../transformers/mutation';
|
||||
|
||||
const getOnlyRequiredFields = (
|
||||
updatedFields,
|
||||
@@ -55,43 +53,6 @@ const load = function(
|
||||
classGraphQLOutputType,
|
||||
} = parseGraphQLSchema.parseClassTypes[className];
|
||||
|
||||
const transformTypes = (inputType: 'create' | 'update', fields) => {
|
||||
if (fields) {
|
||||
const classGraphQLCreateTypeFields =
|
||||
isCreateEnabled && classGraphQLCreateType
|
||||
? classGraphQLCreateType.getFields()
|
||||
: null;
|
||||
const classGraphQLUpdateTypeFields =
|
||||
isUpdateEnabled && classGraphQLUpdateType
|
||||
? classGraphQLUpdateType.getFields()
|
||||
: null;
|
||||
Object.keys(fields).forEach(field => {
|
||||
let inputTypeField;
|
||||
if (inputType === 'create' && classGraphQLCreateTypeFields) {
|
||||
inputTypeField = classGraphQLCreateTypeFields[field];
|
||||
} else if (classGraphQLUpdateTypeFields) {
|
||||
inputTypeField = classGraphQLUpdateTypeFields[field];
|
||||
}
|
||||
if (inputTypeField) {
|
||||
switch (inputTypeField.type) {
|
||||
case defaultGraphQLTypes.GEO_POINT_INPUT:
|
||||
fields[field].__type = 'GeoPoint';
|
||||
break;
|
||||
case defaultGraphQLTypes.POLYGON_INPUT:
|
||||
fields[field] = {
|
||||
__type: 'Polygon',
|
||||
coordinates: fields[field].map(geoPoint => [
|
||||
geoPoint.latitude,
|
||||
geoPoint.longitude,
|
||||
]),
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (isCreateEnabled) {
|
||||
const createGraphQLMutationName = `create${graphQLClassName}`;
|
||||
parseGraphQLSchema.addGraphQLMutation(createGraphQLMutationName, {
|
||||
@@ -110,10 +71,16 @@ const load = function(
|
||||
let { fields } = args;
|
||||
if (!fields) fields = {};
|
||||
const { config, auth, info } = context;
|
||||
transformTypes('create', fields);
|
||||
|
||||
const parseFields = await transformTypes('create', fields, {
|
||||
className,
|
||||
parseGraphQLSchema,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
const createdObject = await objectsMutations.createObject(
|
||||
className,
|
||||
fields,
|
||||
parseFields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
@@ -172,12 +139,16 @@ const load = function(
|
||||
const { objectId, fields } = args;
|
||||
const { config, auth, info } = context;
|
||||
|
||||
transformTypes('update', fields);
|
||||
const parseFields = await transformTypes('update', fields, {
|
||||
className,
|
||||
parseGraphQLSchema,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
|
||||
const updatedObject = await objectsMutations.updateObject(
|
||||
className,
|
||||
objectId,
|
||||
fields,
|
||||
parseFields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
@@ -205,7 +176,12 @@ const load = function(
|
||||
info
|
||||
);
|
||||
}
|
||||
return { ...updatedObject, ...fields, ...optimizedObject };
|
||||
return {
|
||||
objectId: objectId,
|
||||
...updatedObject,
|
||||
...fields,
|
||||
...optimizedObject,
|
||||
};
|
||||
} catch (e) {
|
||||
parseGraphQLSchema.handleError(e);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ import * as defaultGraphQLTypes from './defaultGraphQLTypes';
|
||||
import * as objectsQueries from './objectsQueries';
|
||||
import { ParseGraphQLClassConfig } from '../../Controllers/ParseGraphQLController';
|
||||
import { transformClassNameToGraphQL } from '../transformers/className';
|
||||
import { extractKeysAndInclude } from '../parseGraphQLUtils';
|
||||
import {
|
||||
extractKeysAndInclude,
|
||||
getParseClassMutationConfig,
|
||||
} from '../parseGraphQLUtils';
|
||||
|
||||
const mapInputType = (parseType, targetClass, parseClassTypes) => {
|
||||
switch (parseType) {
|
||||
@@ -34,18 +37,18 @@ const mapInputType = (parseType, targetClass, parseClassTypes) => {
|
||||
case 'Pointer':
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLScalarType
|
||||
parseClassTypes[targetClass].classGraphQLPointerType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLScalarType;
|
||||
return parseClassTypes[targetClass].classGraphQLPointerType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
}
|
||||
case 'Relation':
|
||||
if (
|
||||
parseClassTypes[targetClass] &&
|
||||
parseClassTypes[targetClass].classGraphQLRelationOpType
|
||||
parseClassTypes[targetClass].classGraphQLRelationType
|
||||
) {
|
||||
return parseClassTypes[targetClass].classGraphQLRelationOpType;
|
||||
return parseClassTypes[targetClass].classGraphQLRelationType;
|
||||
} else {
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
}
|
||||
@@ -259,6 +262,11 @@ const load = (
|
||||
classSortFields,
|
||||
} = getInputFieldsAndConstraints(parseClass, parseClassConfig);
|
||||
|
||||
const {
|
||||
create: isCreateEnabled = true,
|
||||
update: isUpdateEnabled = true,
|
||||
} = getParseClassMutationConfig(parseClassConfig);
|
||||
|
||||
const classGraphQLScalarTypeName = `${graphQLClassName}Pointer`;
|
||||
const parseScalarValue = value => {
|
||||
if (typeof value === 'string') {
|
||||
@@ -339,31 +347,6 @@ const load = (
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLScalarType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLRelationOpTypeName = `${graphQLClassName}RelationOpInput`;
|
||||
let classGraphQLRelationOpType = new GraphQLInputObjectType({
|
||||
name: classGraphQLRelationOpTypeName,
|
||||
description: `The ${classGraphQLRelationOpTypeName} type is used in operations that involve relations with the ${graphQLClassName} class.`,
|
||||
fields: () => ({
|
||||
_op: {
|
||||
description: 'This is the operation to be executed.',
|
||||
type: new GraphQLNonNull(defaultGraphQLTypes.RELATION_OP),
|
||||
},
|
||||
ops: {
|
||||
description:
|
||||
'In the case of a Batch operation, this is the list of operations to be executed.',
|
||||
type: new GraphQLList(new GraphQLNonNull(classGraphQLRelationOpType)),
|
||||
},
|
||||
objects: {
|
||||
description:
|
||||
'In the case of a AddRelation or RemoveRelation operation, this is the list of objects to be added/removed.',
|
||||
type: new GraphQLList(new GraphQLNonNull(classGraphQLScalarType)),
|
||||
},
|
||||
}),
|
||||
});
|
||||
classGraphQLRelationOpType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLRelationOpType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLCreateTypeName = `Create${graphQLClassName}FieldsInput`;
|
||||
let classGraphQLCreateType = new GraphQLInputObjectType({
|
||||
name: classGraphQLCreateTypeName,
|
||||
@@ -430,6 +413,62 @@ const load = (
|
||||
classGraphQLUpdateType
|
||||
);
|
||||
|
||||
const classGraphQLPointerTypeName = `${graphQLClassName}PointerInput`;
|
||||
let classGraphQLPointerType = new GraphQLInputObjectType({
|
||||
name: classGraphQLPointerTypeName,
|
||||
description: `Allow to link OR add and link an object of the ${graphQLClassName} class.`,
|
||||
fields: () => {
|
||||
const fields = {
|
||||
link: {
|
||||
description: `Link an existing object from ${graphQLClassName} class.`,
|
||||
type: defaultGraphQLTypes.POINTER_INPUT,
|
||||
},
|
||||
};
|
||||
if (isCreateEnabled) {
|
||||
fields['createAndLink'] = {
|
||||
description: `Create and link an object from ${graphQLClassName} class.`,
|
||||
type: classGraphQLCreateType,
|
||||
};
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
});
|
||||
classGraphQLPointerType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLPointerType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLRelationTypeName = `${graphQLClassName}RelationInput`;
|
||||
let classGraphQLRelationType = new GraphQLInputObjectType({
|
||||
name: classGraphQLRelationTypeName,
|
||||
description: `Allow to add, remove, createAndAdd objects of the ${graphQLClassName} class into a relation field.`,
|
||||
fields: () => {
|
||||
const fields = {
|
||||
add: {
|
||||
description: `Add an existing object from the ${graphQLClassName} class into the relation.`,
|
||||
type: new GraphQLList(
|
||||
new GraphQLNonNull(defaultGraphQLTypes.RELATION_INPUT)
|
||||
),
|
||||
},
|
||||
remove: {
|
||||
description: `Remove an existing object from the ${graphQLClassName} class out of the relation.`,
|
||||
type: new GraphQLList(
|
||||
new GraphQLNonNull(defaultGraphQLTypes.RELATION_INPUT)
|
||||
),
|
||||
},
|
||||
};
|
||||
if (isCreateEnabled) {
|
||||
fields['createAndAdd'] = {
|
||||
description: `Create and add an object of the ${graphQLClassName} class into the relation.`,
|
||||
type: new GraphQLList(new GraphQLNonNull(classGraphQLCreateType)),
|
||||
};
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
});
|
||||
classGraphQLRelationType =
|
||||
parseGraphQLSchema.addGraphQLType(classGraphQLRelationType) ||
|
||||
defaultGraphQLTypes.OBJECT;
|
||||
|
||||
const classGraphQLConstraintTypeName = `${graphQLClassName}PointerWhereInput`;
|
||||
let classGraphQLConstraintType = new GraphQLInputObjectType({
|
||||
name: classGraphQLConstraintTypeName,
|
||||
@@ -700,8 +739,9 @@ const load = (
|
||||
);
|
||||
|
||||
parseGraphQLSchema.parseClassTypes[className] = {
|
||||
classGraphQLPointerType,
|
||||
classGraphQLRelationType,
|
||||
classGraphQLScalarType,
|
||||
classGraphQLRelationOpType,
|
||||
classGraphQLCreateType,
|
||||
classGraphQLUpdateType,
|
||||
classGraphQLConstraintType,
|
||||
@@ -709,6 +749,11 @@ const load = (
|
||||
classGraphQLFindArgs,
|
||||
classGraphQLOutputType,
|
||||
classGraphQLFindResultType,
|
||||
config: {
|
||||
parseClassConfig,
|
||||
isCreateEnabled,
|
||||
isUpdateEnabled,
|
||||
},
|
||||
};
|
||||
|
||||
if (className === '_User') {
|
||||
|
||||
@@ -39,3 +39,7 @@ export const extractKeysAndInclude = selectedFields => {
|
||||
}
|
||||
return { keys, include };
|
||||
};
|
||||
|
||||
export const getParseClassMutationConfig = function(parseClassConfig) {
|
||||
return (parseClassConfig && parseClassConfig.mutation) || {};
|
||||
};
|
||||
|
||||
@@ -1,21 +1,184 @@
|
||||
const parseMap = {
|
||||
_op: '__op',
|
||||
};
|
||||
import * as defaultGraphQLTypes from '../loaders/defaultGraphQLTypes';
|
||||
import * as objectsMutations from '../loaders/objectsMutations';
|
||||
|
||||
const transformMutationInputToParse = fields => {
|
||||
if (!fields || typeof fields !== 'object') {
|
||||
return;
|
||||
const transformTypes = async (
|
||||
inputType: 'create' | 'update',
|
||||
fields,
|
||||
{ className, parseGraphQLSchema, req }
|
||||
) => {
|
||||
const {
|
||||
classGraphQLCreateType,
|
||||
classGraphQLUpdateType,
|
||||
config: { isCreateEnabled, isUpdateEnabled },
|
||||
} = parseGraphQLSchema.parseClassTypes[className];
|
||||
const parseClass = parseGraphQLSchema.parseClasses.find(
|
||||
clazz => clazz.className === className
|
||||
);
|
||||
if (fields) {
|
||||
const classGraphQLCreateTypeFields =
|
||||
isCreateEnabled && classGraphQLCreateType
|
||||
? classGraphQLCreateType.getFields()
|
||||
: null;
|
||||
const classGraphQLUpdateTypeFields =
|
||||
isUpdateEnabled && classGraphQLUpdateType
|
||||
? classGraphQLUpdateType.getFields()
|
||||
: null;
|
||||
const promises = Object.keys(fields).map(async field => {
|
||||
let inputTypeField;
|
||||
if (inputType === 'create' && classGraphQLCreateTypeFields) {
|
||||
inputTypeField = classGraphQLCreateTypeFields[field];
|
||||
} else if (classGraphQLUpdateTypeFields) {
|
||||
inputTypeField = classGraphQLUpdateTypeFields[field];
|
||||
}
|
||||
if (inputTypeField) {
|
||||
switch (true) {
|
||||
case inputTypeField.type === defaultGraphQLTypes.GEO_POINT_INPUT:
|
||||
fields[field] = transformers.geoPoint(fields[field]);
|
||||
break;
|
||||
case inputTypeField.type === defaultGraphQLTypes.POLYGON_INPUT:
|
||||
fields[field] = transformers.polygon(fields[field]);
|
||||
break;
|
||||
case parseClass.fields[field].type === 'Relation':
|
||||
fields[field] = await transformers.relation(
|
||||
parseClass.fields[field].targetClass,
|
||||
field,
|
||||
fields[field],
|
||||
parseGraphQLSchema,
|
||||
req
|
||||
);
|
||||
break;
|
||||
case parseClass.fields[field].type === 'Pointer':
|
||||
fields[field] = await transformers.pointer(
|
||||
parseClass.fields[field].targetClass,
|
||||
field,
|
||||
fields[field],
|
||||
parseGraphQLSchema,
|
||||
req
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
Object.keys(fields).forEach(fieldName => {
|
||||
const fieldValue = fields[fieldName];
|
||||
if (parseMap[fieldName]) {
|
||||
delete fields[fieldName];
|
||||
fields[parseMap[fieldName]] = fieldValue;
|
||||
}
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformMutationInputToParse(fieldValue);
|
||||
}
|
||||
});
|
||||
return fields;
|
||||
};
|
||||
|
||||
export { transformMutationInputToParse };
|
||||
const transformers = {
|
||||
polygon: value => ({
|
||||
__type: 'Polygon',
|
||||
coordinates: value.map(geoPoint => [geoPoint.latitude, geoPoint.longitude]),
|
||||
}),
|
||||
geoPoint: value => ({
|
||||
...value,
|
||||
__type: 'GeoPoint',
|
||||
}),
|
||||
relation: async (
|
||||
targetClass,
|
||||
field,
|
||||
value,
|
||||
parseGraphQLSchema,
|
||||
{ config, auth, info }
|
||||
) => {
|
||||
if (Object.keys(value) === 0)
|
||||
throw new Error(
|
||||
`You need to provide atleast one operation on the relation mutation of field ${field}`
|
||||
);
|
||||
|
||||
const op = {
|
||||
__op: 'Batch',
|
||||
ops: [],
|
||||
};
|
||||
let nestedObjectsToAdd = [];
|
||||
|
||||
if (value.createAndAdd) {
|
||||
nestedObjectsToAdd = (await Promise.all(
|
||||
value.createAndAdd.map(async input => {
|
||||
const parseFields = await transformTypes('create', input, {
|
||||
className: targetClass,
|
||||
parseGraphQLSchema,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
return objectsMutations.createObject(
|
||||
targetClass,
|
||||
parseFields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
})
|
||||
)).map(object => ({
|
||||
__type: 'Pointer',
|
||||
className: targetClass,
|
||||
objectId: object.objectId,
|
||||
}));
|
||||
}
|
||||
|
||||
if (value.add || nestedObjectsToAdd.length > 0) {
|
||||
if (!value.add) value.add = [];
|
||||
value.add = value.add.map(input => ({
|
||||
__type: 'Pointer',
|
||||
className: targetClass,
|
||||
objectId: input.objectId,
|
||||
}));
|
||||
op.ops.push({
|
||||
__op: 'AddRelation',
|
||||
objects: [...value.add, ...nestedObjectsToAdd],
|
||||
});
|
||||
}
|
||||
|
||||
if (value.remove) {
|
||||
op.ops.push({
|
||||
__op: 'RemoveRelation',
|
||||
objects: value.remove.map(input => ({
|
||||
__type: 'Pointer',
|
||||
className: targetClass,
|
||||
objectId: input.objectId,
|
||||
})),
|
||||
});
|
||||
}
|
||||
return op;
|
||||
},
|
||||
pointer: async (
|
||||
targetClass,
|
||||
field,
|
||||
value,
|
||||
parseGraphQLSchema,
|
||||
{ config, auth, info }
|
||||
) => {
|
||||
if (Object.keys(value) > 1 || Object.keys(value) === 0)
|
||||
throw new Error(
|
||||
`You need to provide link OR createLink on the pointer mutation of field ${field}`
|
||||
);
|
||||
|
||||
let nestedObjectToAdd;
|
||||
if (value.createAndLink) {
|
||||
const parseFields = await transformTypes('create', value.createAndLink, {
|
||||
className: targetClass,
|
||||
parseGraphQLSchema,
|
||||
req: { config, auth, info },
|
||||
});
|
||||
nestedObjectToAdd = await objectsMutations.createObject(
|
||||
targetClass,
|
||||
parseFields,
|
||||
config,
|
||||
auth,
|
||||
info
|
||||
);
|
||||
return {
|
||||
__type: 'Pointer',
|
||||
className: targetClass,
|
||||
objectId: nestedObjectToAdd.objectId,
|
||||
};
|
||||
}
|
||||
if (value.link && value.link.objectId) {
|
||||
return {
|
||||
__type: 'Pointer',
|
||||
className: targetClass,
|
||||
objectId: value.link.objectId,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export { transformTypes };
|
||||
|
||||
Reference in New Issue
Block a user