View with MultiValueEncoded returns only one element - elrond

My view should return multiple elements, but I always got only one.
I am calling my view with /vm-values/query.
Should I use another gateway endpoint for the MultiValueEncoded view?

To resolve this issue, I used the queryContract function from the class ApiNetworkProvider in the erdjs npm package.
const apiNetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com");
const output = await apiNetworkProvider.queryContract({
address: "erd1....",
func: {
toString(): string {
return "myFunc";
}
},
getEncodedArguments() {
return []; // I don't need args
},
});
The returnData is encoded in base64, so I decoded like so:
const decodedData = output.returnData.map(data => Buffer.from(data, "base64").toString());

Related

How to output a file in i18next via custom plugin?

I tried creating a custom plugin to download data from backend using i18next plugin, however, is stuck at data dumping process. I am using NextJS for frontend.
Here is the configuration file for NextJS.
const { i18n } = require('./next-i18next.config.js/index.js')
module.exports = {
reactStrictMode: true,
i18n
}
Here is the next-18next.config.js file content.
const getDefault = ()=>{
return {
parse: data => JSON.parse(data),
addPath: '/locales/{{lng}}/{{ns}}',
}
}
class Backend {
constructor(services, backendOptions, i18nextOptions){
this.init(services,backendOptions,i18nextOptions)
}
init (services,options={},allOptions={}){
this.services = services;
this.options = {...getDefault(),...options};
this.allOptions = allOptions;
}
async read(language, namespace, callback) {
const payloadUrl = this.options.payloadUrl;
this.data = null;
try {
const response = await fetch(payloadUrl);
const payloadData = await response.json();
this.data = payloadData;
}
catch(err){
return callback(err,this.data)
}
this.loadUrl(language,namespace,callback);
}
async loadUrl (language,namespace,callback){
const loadPath = this.options.loadPath;
const url = this.services.interpolator.interpolate(loadPath, { lng: language, ns: namespace});
try {
const response = await fetch(url);
const data = await response.json();
return callback(language,namespace,data)
}
catch(err){
console.log("Error while fetching payload ", err)
callback(err,null)
}
}
save (language, namespace, data) {
console.log(language,namespace,data);
}
create (language, namespace, key, fallbackValue) {
console.log(language,namespace,key,fallbackValue)
}
dumpData(language,namespace,data){
const filePath = this.services.interpolator.interpolate(this.options.addPath, { lng: language, ns: namespace});
// need to find a way to dump the file into the given filePath, (right now
// I cannot find proper way to use fs library)
console.log(filePath, "is the file path")
console.log("data we dumping ", data);
}
}
Backend.type = "backend";
module.exports = Backend;
I am following https://github.com/i18next/i18next-http-backend and have no idea how they are dumping the payload we get from backend to specific folder. I tried doing it manually adding fs library, however we are using NextJS and using fs gives me error Can't resolve 'fs'. How can we dump the data we receive from backend into its required location?
The callback signature is wrong, callback(language,namespace,data) is not correct. The signature should be callback(error, result) => this means you may change it to: callback(null, data)
Additionally, all these are not async functions, plain old callback based functions, like described here: https://www.i18next.com/misc/creating-own-plugins#backend
btw: if you're fetching data from your backend, why do you not simply use i18next-http-backend and adapt the loadPath and or the parse option and/or the request option: https://github.com/i18next/i18next-http-backend#backend-options ?

How to get data stored as subject rxjs

I am working on displaying the details of event clicked. I have stored all the events inside an array.
When the user clicks on the event then its id is passed which checks inside the array and it passes the result into service.
showDetail(id){
let obj = this.events;
let newArr = Object.values(obj);
let result = newArr.filter(function(el) {
return el["id"] == id;
});
this.articleService.sendMessage(result);
let url = `/article/${id}`;
this.router.navigate([url]);
}
service
private detailSubject = new Subject<any>();
sendMessage(formData: any) {
this.detailSubject.next({formData});
}
getMessage(): Observable<any> {
return this.detailSubject.asObservable();
}
Now in my article/id page.
I am not being able to retrieve this passed array.
I have following code
ngOnInit() {
this.articleService.getMessage().subscribe(
res => {
this.loadArticleDetail(res["formData"]);
},
error => {
console.log("Error loading data");
}
);
}
this.articleService.sendMessage(result); // <-- Subject.next()
let url = `/article/${id}`;
this.router.navigate([url]); // <-- Subject.subscribe() after Subject.next(), so value already emitted
You already added BehaviorSubject tag. So use it. Also, getMessage(): Observable<any> { doesnt do anything except returns Observable. Feels redundant:
private detailSubject = new BehaviorSubject<any>(null);
message$ = this.detailSubject.asObservable();
sendMessage(formData: any) {
this.detailSubject.next({formData});
}
And
ngOnInit() {
this.articleService.message$.subscribe(...

Issue while updating store from updater function of commitMutation

I have a mutation
mutation createQuoteLineMutation {
createQuoteLine {
quoteLine {
name
price
product {
name
}
}
}
}
My updater function is as below.
updater: (store) => {
const payload = store.getRootField('createQuoteLine');
const newQuoteLine = payload.getLinkedRecord('quoteLine');
const quote = store.getRoot().getLinkedRecord('getQuote');
const quoteLines = quote.getLinkedRecords('quoteLines') || [];
const newQuoteLines = [...quoteLines, newQuoteLine];
quote.setLinkedRecords(newQuoteLines, 'quoteLines');
}
This works fine for the first time, but the consequent mutations all the previously added quoteLines change to new one I'm assuming this is because newQuoteLine points to same object all the time.
adding below line at the end of updater function unlink quoteLine from createQuoteLine also does not work.
payload.setValue(null, 'quoteLine');
Any help in this regard is highly appreciated.
I have seen a quite similar problem, but I am not sure if it's the same. Try to pass an clientMutationId to the mutation, and increment it along.
const commit = (
input,
onCompleted: (response) => void,
) => {
const variables = {
input: {
...input,
clientMutationId: temp++,
},
};
commitMutation(Environment, {
mutation,
variables,
onCompleted,
onError: null,
updater: store => {
// ....
},
});
};
Try something like this and let me know if it fixes :).

Apollo GraphQL server: filter (or sort) by a field that is resolved separately

I might be facing a design limitation of Apollo GraphQL server and I'd like to ask if there is a workaround.
My schema contains type Thing, that has field flag. I'd like to be able to filter things by the value of flag, but there is appears to be impossible if this field is resolved separately. The same problem would arise if I wanted to sort things. Here’s an example:
type Thing {
id: String!
flag Boolean!
}
type Query {
things(onlyWhereFlagIsTrue: Boolean): [Thing!]!
}
const resolvers = {
Thing: {
flag: async ({id}) => {
const value = await getFlagForThing(id);
return value;
}
},
Query: {
async things(obj, {onlyWhereFlagIsTrue = false}) {
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue) {
// ↓ this does not work, because flag is still undefined
result = _.filter(result, ['flag', true]);
}
return result;
}
}
}
Is there any way of filtering things after all the async fields are resolved? I know I can call getFlagForThing(id) inside things resolver, but won't that be just repeating myself? The logic behind resolving flag can be a bit more complex than just calling one function.
UPD: This is the best solution I could find so far. Pretty ugly and hard to scale to other fields:
const resolvers = {
Thing: {
flag: async ({id, flag}) => {
// need to check if flag has already been resolved
// to avoid calling getThingsWithoutFlags() twice
if (!_.isUndefined(flag)) {
return flag;
}
const value = await getFlagForThing(id);
return value;
}
},
Query: {
async things(obj, {onlyWhereFlagIsTrue = false}) {
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue) {
// asynchroniously resolving flags when needed
const promises = _.map(result, ({id}) =>
getFlagForThing(id)
);
const flags = await Promise.all(promises);
for (let i = 0; i < flags.length; i += 1) {
result[i].flag = flags[i];
}
// ↓ this line works now
result = _.filter(result, ['flag', true]);
}
return result;
}
},
};
I think that the issue here is not really a limitation of Apollo server, and more to do with the fact that you have a primitive field with a resolver. Generally, it's best to use resolvers for fields only when that field is going to return a separate type:
Thing {
id: ID!
flag: Boolean!
otherThings: OtherThing
}
Query {
things(onlyWhereFlag: Boolean): [Thing!]!
}
In this example, it would be fine to have a separate resolver for otherThings, but if a field is a primitive, then I would just resolve that field along with Thing.
Using your original schema:
const filterByKeyValuePair = ([key, value]) => obj => obj[key] === value;
const resolvers = {
Query: {
async things(parent, { onlyWhereFlag }) {
const things = await Promise.all(
(await getThings()).map(
thing =>
new Promise(async resolve =>
resolve({
...thing,
flag: await getFlagForThing(thing)
})
)
)
);
if (onlyWhereFlag) {
return things.filter(filterByKeyValuePair(['flag', true]));
} else {
return things;
}
}
}
};
What if flag wasn't a primitive? Well, if you want to filter by it, then you would have a couple of different options. These options really depend on how you are fetching the "flag" data. I'd be happy to elaborate if you can provide more details about your schema and data models.

Angular2 Async Form Validator (return Promise)

I'm trying to update the Angular2 Forms Validation example to handle an Async Validation response. This way I can hit an HTTP endpoint to validate a username.
Looking at their code they currently aren't currently using a Promise and it's working just fine:
/** A hero's name can't match the given regular expression */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const name = control.value;
const no = nameRe.test(name);
return no ? {'forbiddenName': {name}} : null;
};
}
I'm trying to update to return a Promise. Something like:
/** A hero's name can't match the given regular expression */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl) => {
const name = control.value;
return new Promise( resolve => {
resolve({'forbiddenName': {name}});
});
};
}
However, the result I get doesn't display the error message, it's showing undefined.
My thought is it has something to do with the way they are handling displaying the errors:
onValueChanged(data?: any) {
if (!this.heroForm) { return; }
const form = this.heroForm;
for (const field in this.formErrors) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
However I'm not sure of a better way of doing this.
Angular2 example:
https://angular.io/docs/ts/latest/cookbook/form-validation.html#!#live-example
Link to my example attempting to return Promise:
https://plnkr.co/edit/sDs9pNQ1Bs2knp6tasgI?p=preview
The problem is that you add the AsyncValidator to the SyncValidator Array. AsyncValidators are added in a separate array after the SyncValidators:
this.heroForm = this.fb.group({
'name': [this.hero.name, [
Validators.required,
Validators.minLength(4),
Validators.maxLength(24)
],
[forbiddenNameValidator(/bob/i)] // << separate array
],
'alterEgo': [this.hero.alterEgo],
'power': [this.hero.power, Validators.required]
});

Resources