Use Either with Future - asynchronous

I want to use dartz functional style and do something like this:
Either<Failure, Response> result = await remoteDataSource.request() // Future<Response> request();
.then((response) => Right(response))
.catchError((failure) => Left(failure));
But it seems that I can't do this:
error: A value of type 'Right< dynamic, Response>' can't be assigned to
a variable of type 'Either< Failure, Response>'.
So, how can I use Either with Future this way?

It's all about <generics>.
.then((response) => Right(response)) // this is of type Right<dynamic,User>
You got to give the compiler all the proper information:
.then((response) => Right<Failure, Response>(response))
// or
.then((response) => right(response)) // a helper function which returns an Either

Related

Vue 3: StopHandle for computed()?

In Vue 3, watchEffect() and watch() returns StopHandle which allows the caller to stop watching.
I think that computed() should have a kind of StopHandle since computed() uses (it's my guess) a kind of 'watch' internally to track dirtiness, but there is none.
Is there a reason that computed() has no StopHandle-like thing? Or is there a function that works similarly to StopHandle?
Thanks.
You can use effectScope to manually dispose effects like computed or watch like this:
const scope = effectScope()
scope.run(() => {
const doubled = computed(() => counter.value * 2)
watch(doubled, () => console.log(doubled.value))
watchEffect(() => console.log('Count: ', doubled.value))
})
// to dispose all effects in the scope
scope.stop()
An unofficial way is calling the stop function directly from the computed variable:
const doubled = computed(() => counter.value * 2)
doubled.effect.stop()

Flow type refine mixed to function

I'm using koa which has middleware props typed as mixed, so I'm trying to do something along the lines of the following below but I'm getting an error that Cannot call `ctx.render` because mixed [1] is not a function.Flow(not-a-function)
app.use(async (ctx, next) => {
// some other code above it
await ctx.render('index');
});
My question is, what's the correct way to do a type refinement that this is a function and then allow me to call it?
You can refine this to a function, but calling it is another matter.
app.use(async (ctx, next) => {
if (typeof ctx.render === 'function') {
// Now we know that `ctx.render` is a function.
}
});
Flow actually has a special case for this, this is called an "unknown function." We know that ctx.render is a function, but we don't know anything about its arguments or return type so we can't safely do anything with it except pass it around. How can we safely call ctx.render(1) if we don't know that ctx.render takes a number?
What's more, we can't know anything about it. There is no reflection mechanism provided by JavaScript that we could interrogate for enough information about this function to be able to safely call it. The only thing we can find is the static arity (ctx.render.length) but this by itself is not reliable or sufficient.
If we had more information, like say if this were a union type instead of mixed, then we could use type refinement to do what we want:
(arg: boolean | (number => void)) => {
if (typeof arg === 'function') {
arg(1); // safe because if this is a function, we know it takes a number
}
};
In this case the most reasonable solution is to type through any. Assuming that we know that we should only ever receive one type of render function, then we just forcibly cast it to that type with all the blaring caveats one would expect:
// I don't know what the type of your render function is, but you would put it
// here:
type RenderFunction = string => void;
app.use(async (ctx, next) => {
// some other code above it
if (typeof ctx.render === 'function') {
// DANGER: We make a hard assumption here that the render function is
// always of this specific type. If it is ever of any other type then
// behavior is undefined!
await ((ctx.render: any): RenderFunction)('index');
}
});
Also it sounds to me like the koa libdef could probably be improved upon.

Lookup items in firebase then lookup docId from the first returned items then merge

I need to lookup the location for each product.
First searchCollection returns array of object with one of the property anotherTblDocIs as a json string.
In this json string, which is firebase docId, I need to lookup the name. Then I need to merge it back.
How can I achieve this properly?
this.firebaseService
.searchCollection('product', 'shopId', this.shopId)
.pipe(
mergeMap((products: any) => {
let observableBatch = [];
products.map(product => {
const docIds = JSON.parse(product['anotherTblDocIs']);
docIds.forEach(doc =>{
observableBatch.push(this.firebaseService.readCollectionByDocId('doc', doc ).pipe(map(u => {return { doc, ...u}})))
});
});
return forkJoin(observableBatch);
})
)
.subscribe(products => {
});
When you write a stream it's often better to break things into small steps, and you keep transforming the stream until what you need.
Maybe this won't be exactly equivalent in terms of orders of subscriptions, but I think it would look better with something like:
this.firebaseService.searchCollection('product', 'shopId', this.shopId).pipe(
// Here we have Observable<Product[]>
mergeMap(products => products)
// Now we have Observable<Product>
mergeMap(product => JSON.parse(product['anotherTblDocIds']))
// Now we have Observable<DocIds> (for each product)
mergeMap(docId => this.firebaseService.readCollectionByDocId('doc', doc).pipe(
// We need to this map inside this stream to have the reference to `docId`
map(u => ({ doc: docId, ...u }))
))
)
mergeMap will flatten both Observables and arrays, so it can be used this way.

Data validation using RxJS

I have the following function that validates that rangeFrom is not superior to rangeTo and that the rangeFrom does not already exist in the list of ranges.
How can rewrite this using RxJS?
const isTagAlreadyExist = (tags, currentTag) => _(tags)
.filter(x => x.id !== currentTag.id)
.some(x => _.inRange(currentTag.rangeTo, x.rangeFrom, x.rangeTo))
.value();
const validateRangeFrom = (tags, currentTag) => {
const errors = {};
if (isNumeric(currentTag.rangeFrom)) {
if (!_.inRange(currentTag.rangeFrom, 0, currentTag.rangeTo)) {
errors.rangeFrom = 'FROM_TAG_CANNOT_BE_GREATER_THAN_TO_TAG';
} else if (isTagAlreadyExist(tags, currentTag)) {
errors.rangeFrom ='TAG_ALREADY_EXISTS';
}
}
return {
errors
};
};
The question is: what parts do you want to rewrite to rxjs? Those are two pure functions that run synchronously from what I can see, I do not really see much a usecase for rxjs here - of course you could always utilize your functions within an rxjs stream:
const validateRangeFrom$ = (tags, currentTag) => {
return Observable.of(currentTag)
.map(tag => validateRangeFrom(tags, tag));
}
validateRangeFrom$(myTags, currentTag)
.subscribe(errors => console.log(errors));
But as you can see, this does not make much sense if you simply wrap it inside a stream, the essence of useful reactive programming is, that everything is reactive, not just some small parts, so for your example, you should start with having tags$ and currentTag$ as observables - let's assume that you have that, then you could do something like:
const tags$: Observable<ITag[]>... // is set somewhere, and emits a new array whenever it is changed
const currentTag$: Observable<ITag>... // is set somewhere and emits the tag whenever a new currentTag is set
const validateRangeFrom$ = Observable
.combineLatest(tags$, currentTag$, (tags, tag) => ({tags, tag}))
.map(({tags, tag}) => validateRangeFrom(tags, tag));
validateRangeFrom$.subscribe(errors => console.log(errors));
This will automatically trigger the validation for you whenever a new tags-array is emitted or a new currentTag is selected/set - but again: your validation-method is kept the same - as even in reactive programming you have to do validation and logic-operations at some point, the reactive part usually just concerns the flow of the data (see: tags$ and currentTag$)

Rxjs: add data to elements of array returned from http response

Following this question: Add data to http response using rxjs
I've tried to adapt this code to my use case where the result of the first http call yields an array instead of a value... but I can't get my head around it.
How do I write in rxjs (Typescript) the following pseudo code?
call my server
obtain an array of objects with the following properties: (external id, name)
for each object, call another server passing the external id
for each response from the external server, obtain another object and merge some of its properties into the object from my server with the same id
finally, subscribe and obtain an array of augmented objects with the following structure: (external id, name, augmented prop1, augmented prop2, ...)
So far the only thing I was able to do is:
this._appService
.getUserGames()
.subscribe(games => {
this._userGames = _.map(games, game => ({ id: game.id, externalGameId: game.externalGameId, name: game.name }));
_.forEach(this._userGames, game => {
this._externalService
.getExternalGameById(game.externalGameId)
.subscribe(externalThing => {
(<any>game).thumbnail = externalThing.thumbnail;
(<any>game).name = externalThing.name;
});
});
});
Thanks in advance
I found a way to make it work. I'll comment the code to better explain what it does, especially to myself :D
this._appService
.getUserGames() // Here we have an observable that emits only 1 value: an any[]
.mergeMap(games => _.map(games, game => this._externalService.augmentGame(game))) // Here we map the any[] to an Observable<any>[]. The external service takes the object and enriches it with more properties
.concatAll() // This will take n observables (the Observable<any>[]) and return an Observable<any> that emits n values
.toArray() // But I want a single emission of an any[], so I turn that n emissions to a single emission of an array
.subscribe(games => { ... }); // TA-DAAAAA!
Don't use subscribe. Use map instead.
Can't test it, but should look more like this:
this._appService
.getUserGames()
.map(games => {
this._userGames = _.map(games, game => ({ id: game.id, externalGameId: game.externalGameId, name: game.name }));
return this._userGames.map(game => { /* this should return an array of observables.. */
return this._externalService
.getExternalGameById(game.externalGameId)
.map(externalThing => {
(<any>game).thumbnail = externalThing.thumbnail;
(<any>game).name = externalThing.name;
return game;
});
});
})
.mergeAll()
.subscribe(xx => ...); // here you can subscribe..

Resources