I've extended a Parse.Object. Now I want to unset a nested property before saving an object. This nested property settings is an object.
So my hook looks like this:
Parse.Cloud.beforeSave('MyObject', req => {
if (req.object.get('settings').propertyToUnset) {
req.object.unset('settings.propertyToUnset');
}
});
However, that produces the error Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How does unset work for nested properties?
You can try something like this:
Parse.Cloud.beforeSave('MyObject', async req => {
const settings = req.object.get('settings');
await settings.fetch();
if (settings.get('propertyToUnset')) {
settings.unset('propertyToUnset');
await settings.save();
}
});
The solution is to use the plain JavaScript command delete to delete a property of nested object settings:
Parse.Cloud.beforeSave('MyObject', req => {
if (req.object.get('settings').propertyToUnset) {
delete req.object.get('settings').propertyToUnset;
}
});
Related
I have a custom hook that looks something like this:
import { useQuery, useQueryClient } from 'react-query'
import { get } from '#/util/api' // Custom API utility
import produce from 'immer' // Using immer for deep object mutation
export function useData() {
const queryClient = useQueryClient()
const { data, isSuccess } = useQuery(
'myData', () => get('data')
)
function addData(moreData) {
const updatedData = produce(data.results, (draft) => {
draft.push(moreData)
})
setData(updatedData)
}
function setData(newData) {
queryClient.setQueryData('myData', newData)
}
return {
data: data && data.results,
setData,
addData,
}
}
My data in data.results is an array of objects. When I call addData it creates a copy of my current data, mutates it, then calls setData where queryClient.setQueryData is called with a new array of objects passed in as my second argument. But my cached data either doesn't update or becomes undefined in the component hooked up to the useData() hook. Does anyone know what I'm doing wrong?
code looks good from react-query perspective, but I'm not sure if that's how immer works. I think with your code, you will get back the same data instance with just a new data.results object on it. I would do:
const updatedData = produce(data, (draft) => {
draft.results.push(moreData)
})
Is there a way to catch and modify response globally on the fly? I can do this for one query like below, but I want to do it for all queries.
apollo: {
post: {
query: Post,
update(data) {
return data.map(item => Object.assign(item, {foo: 'bar'})
}
}
}
It's simplified for this question, but under the hood I'd like to apply a constructor (class) to all objects...
I'm using nuxt-apollo. I searched for a way to do that in clientConfig or elsewhere so the solution may be related to apollo...
Thanks for your advice!
edit:
OK, I found to do that with apollo-link, but I can't modify response. Here the code:
const constructorMiddleware = new ApolloLink((operation, forward) => {
return forward(operation).map(response => {
Object.keys(response.data).map(key => {
if (!Array.isArray(response.data[key])) return;
const newResponse = response.data[key].map(item => {
return item.__typename === 'post'
? Object.assign(item, { foo: 'bar' })
: item
})
console.log(newResponse)
response.data[key] = newResponse
})
return response
})
})
I can see foo: bar in the newResponse, but the graphql returning by nuxt-apollo doesn't contains this newResponse, only original.
Do ApolloLink override response? Does apollo cache change this?
edit 2:
I tried to chain links and the newResponse of the constructorMiddleware is well in the next link. So the problem seems come from nuxt-apollo, or more vue-apollo...
I am making a request using observable. and trying to subcribe the value. But getting error on typescript. any on help me?
I like to do this:
public getCountry(lat,lan):Observable<any>{
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false').subscribe(data => {
return this.genertedData(data);
} );
}
But getting error as follows:
UPDATES
public getCountry(lat,lan):Observable<any>{
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false').map( data => {
data.results.map( array => {
let details = array.address_components.find( obj => obj.types.includes("country") );
this.countryDetails.countryLongName = details.long_name;
this.countryDetails.countryShortName = details.short_name;
})
return this.countryDetails;
})
}
The problem is that your return type states Observable<any>, where as you actually return whatever this.genertedData(data) returns (Hint: Sounds like a typo in your function. Guess it should be called generatedData ?).
Best practice would be to move the http call into a service and subscribe to its returned Observable within your component.
So to speak:
// => service.ts
public getCountryObservable(lat,lan):Observable<any> {
return this.http.get(this.googleApi+lat+','+lan+'&sensor=false');
}
Your component would look something like:
// => component.ts
export class YourComponent {
constructor(public yourService: YourService) {}
getCountry(lat, lan): whateverDataTypeYourGeneratedDataReturns {
this.yourService.getCountryObservable(lat, lan).subscribe((data) => {
this.data = this.generatedData(data);
});
}
}
Since the return type of the function is Observable<any>, I guess it should just return this.http.get(this.googleApi+lat+','+lan+'&sensor=false')
I am trying to write a component that exposes the data from an AJAX call in Polymer. I would like to end with something like.
<get-db data={{data}}></get-db>
<template is="dom-repeat" items="{{data}}">
<div>{{item}}</div>
</template>
However, when I expose the data property from get-db component in another element, the data doesn't bind to the dom-repeat template.
The get-db component parts are as follows
<iron-ajax id="ajax"
url="https://api/endpoint"
method="post"
handle-as="json"
content-type="application/json"
body="[[request]]"
last-response="{{response}}"></iron-ajax>
...
static get properties() {
return {
response: Object,
request: Object,
username: String,
data: Object
}
}
getResponse() {
if (this.username && this.apiKey) {
this.request = {
"body": "bodyText"
};
let request = this.$.ajax.generateRequest();
request.completes.then(req => {
this.setResponse();
})
.catch(rejected => {
console.log(rejected.request);
console.log(rejected.error);
})
}
}
setResponse() {
if(this.response[0]) {
this.data = this.response[0];
}
}
The data property needs to be set to notify.
data: {
type: Object,
notify: true
}
You need to add notify but also you need to use this.set method in order to get observable changes for data properties. Also you are setting only one item to data properties (assuming you have a array at response properties.) I guess you need all array instead only 0. index as you are looping in dom-repeat. That's why this below code may help:
static get properties() {
return {
response:{
type:Object,
observer:'checkResponce'},
request: Object,
username: String,
data: {
type:Array,
notify:true}
}
}
static get observers() { return [ 'checkUserNApi(username,apiKey)']}
checkUserNApi(u,a){
if (u && a) this.$.ajax.generateRequest();
}
checkResponce(d) {
if (d) {
this.set('data',d); //with this method data property at parent will change upon you received responce
}
}
Finally, you may add to iron-ajax a line check error on-error="{{error}}" if you want to see an error report.
DEMO
I've followed the documentation about using graphql-tools to mock a GraphQL server, however this throws an error for custom types, such as:
Expected a value of type "JSON" but received: [object Object]
The graphql-tools documentation about mocking explicitly states that they support custom types, and even provide an example of using the GraphQLJSON custom type from the graphql-type-json project.
I've provided a demo of a solution on github which uses graphql-tools to successfully mock a GraphQL server, but this relies on monkey-patching the built schema:
// Here we Monkey-patch the schema, as otherwise it will fall back
// to the default serialize which simply returns null.
schema._typeMap.JSON._scalarConfig.serialize = () => {
return { result: 'mocking JSON monkey-patched' }
}
schema._typeMap.MyCustomScalar._scalarConfig.serialize = () => {
return mocks.MyCustomScalar()
}
Possibly I'm doing something wrong in my demo, but without the monkey-patched code above I get the error regarding custom types mentioned above.
Does anyone have a better solution than my demo, or any clues as to what I might be doing wrong, and how I can change the code so that the demo works without monkey-patching the schema?
The relevant code in the demo index.js is as follows:
/*
** As per:
** http://dev.apollodata.com/tools/graphql-tools/mocking.html
** Note that there are references on the web to graphql-tools.mockServer,
** but these seem to be out of date.
*/
const { graphql, GraphQLScalarType } = require('graphql');
const { makeExecutableSchema, addMockFunctionsToSchema } = require('graphql-tools');
const GraphQLJSON = require('graphql-type-json');
const myCustomScalarType = new GraphQLScalarType({
name: 'MyCustomScalar',
description: 'Description of my custom scalar type',
serialize(value) {
let result;
// Implement your own behavior here by setting the 'result' variable
result = value || "I am the results of myCustomScalarType.serialize";
return result;
},
parseValue(value) {
let result;
// Implement your own behavior here by setting the 'result' variable
result = value || "I am the results of myCustomScalarType.parseValue";
return result;
},
parseLiteral(ast) {
switch (ast.kind) {
// Implement your own behavior here by returning what suits your needs
// depending on ast.kind
}
}
});
const schemaString = `
scalar MyCustomScalar
scalar JSON
type Foo {
aField: MyCustomScalar
bField: JSON
cField: String
}
type Query {
foo: Foo
}
`;
const resolverFunctions = {
Query: {
foo: {
aField: () => {
return 'I am the result of resolverFunctions.Query.foo.aField'
},
bField: () => ({ result: 'of resolverFunctions.Query.foo.bField' }),
cField: () => {
return 'I am the result of resolverFunctions.Query.foo.cField'
}
},
},
};
const mocks = {
Foo: () => ({
// aField: () => mocks.MyCustomScalar(),
// bField: () => ({ result: 'of mocks.foo.bField' }),
cField: () => {
return 'I am the result of mocks.foo.cField'
}
}),
cField: () => {
return 'mocking cField'
},
MyCustomScalar: () => {
return 'mocking MyCustomScalar'
},
JSON: () => {
return { result: 'mocking JSON'}
}
}
const query = `
{
foo {
aField
bField
cField
}
}
`;
const schema = makeExecutableSchema({
typeDefs: schemaString,
resolvers: resolverFunctions
})
addMockFunctionsToSchema({
schema,
mocks
});
// Here we Monkey-patch the schema, as otherwise it will fall back
// to the default serialize which simply returns null.
schema._typeMap.JSON._scalarConfig.serialize = () => {
return { result: 'mocking JSON monkey-patched' }
}
schema._typeMap.MyCustomScalar._scalarConfig.serialize = () => {
return mocks.MyCustomScalar()
}
graphql(schema, query).then((result) => console.log('Got result', JSON.stringify(result, null, 4)));
I and a few others are seeing a similar issue with live data sources (in my case MongoDB/Mongoose). I suspect it is something internal to the graphql-tools makeExecutableSchema and the way it ingests text-based schemas with custom types.
Here's another post on the issue: How to use graphql-type-json package with GraphQl
I haven't tried the suggestion to build the schema in code, so can't confirm whether it works or not.
My current workaround is to stringify the JSON fields (in the connector) when serving them to the client (and parsing on the client side) and vice-versa. A little clunky but I'm not really using GraphQL to query and/or selectively extract the properties within the JSON object. This wouldn't be optimal for large JSON objects I suspect.
If anyone else comes here from Google results, the solution for me was to add the JSON resolver as parameter to the makeExecutableSchema call. It's described here:
https://github.com/apollographql/apollo-test-utils/issues/28#issuecomment-377794825
That made the mocking work for me.