Http rxjs - Passing Subscribe result to another function - http

Please would you kindly guide me in the right direction?
I am trying to pull records from an old Http REST service, restructure the data, then post it to firebase.
I'm not sure if this is the completely wrong approach or I misunderstand observable's completely. Your guidance will be most appreciated. How to send this new listing to another DataService function: exportToFirebase(new_listing) ?
onServiceCall() {
this.httpDataService.getData().subscribe((itemData) => {
this.itemDataJSON = itemData;
if (this.itemDataJSON) {
this.itemDataJSON.forEach(function(value) {
let new_listing = new Listing(value.id, value.name, value.category);
//console.log(new_listing);
//How to send this new listing to another firebaseDataService function exportToFirebase(new_listing);
});
}
});
}

This demo does what you want, using mocked http & firebase services.
// --- make http call
httpCall.pipe(
// --- construct an array of "new_listing" (of just one, up to u) and pass along the observable chain
concatMap(httpNumbers => of(...httpNumbers)),
// --- make the firebase call
concatMap(number => firebaseCall(number))
).subscribe(val => console.log(val))
Hope this helps. If this does not make sense, then you need to read up on RxJS.

Related

How to make Next-Auth-session-token-dependent server queries with React Query in Next JS?

I am trying to make an API GET request, using React Query's useInfiniteQuery hook, that uses data from a Next Auth session token in the query string.
I have a callback in /api/auth/[...nextauth.ts] to send extra userData to my session token.
There are two relevant pages on the client side. Let's call them /pages/index.tsx and /hooks/useApiData.ts. This is what they look like, for all intents and purposes:
// pages/index.tsx
export default function Page() {
const {data, fetchNextPage, isLoading, isError} = useCourseData()
if (isLoading) return <main />
return <main>
<InfiniteScroller fetchMore={fetchNextPage}>
{data?.pages?.map(page => page?.results?.map(item: string => item))}
</InfiniteScroller>
</main>
}
// hooks/useApiData.ts
async function fetchPage(pageParam: string) {
const response = await fetch(pageParam)
return await response.json()
}
export default function useApiData() {
const {data: session} = useSession()
const init = `/api?userData=${session?.user?.userData}`
return useInfiniteQuery('query',
({pageParam = init}) => fetchPage(pageParam),
{getNextPageParam: prevPage => prevPage.next ?? undefined}
)
}
My initial request gets sent to the API as /api?userData=undefined. The extra data is definitely making its way into the token.
I can place the data from my session in the DOM via the render function of /pages/index.tsx, so I figure the problem is something to do with custom hooks running before the session context is ready, or something like that... I don't understand the mechanics of hooks well enough to figure that out.
I've been looking for answers for a long time, and I'm surprised not to have found a single person with the same issue. These are not unpopular packages and I guess a lot of people are using them in conjunction to achieve what I'm attempting here, so I figure I must be doing something especially dumb. But what?!
How can I get the data from my Next Auth session into my React Query request? And for bonus points, why is the session data not available when the request is sent in my custom hook?

Can I make connections NonNullable in GraphQL .NET?

I'm working on a project, where we need to make non optional connections, and I can't really find anything on the subject.
I made the fields work with the NonNullableGraphType as shown beneath, but I have no luck getting the connections to be non nullable.
I've searched far and wide, and can't find anything about the issue, so I hope someone can help me here, as I'm completely lost.
The fields that are non nullable are written as such:
Field<NonNullGraphType<OrderPresetGraphType>>(
"preset",
resolve: context => {
var loader = dataLoader.Context.GetOrAddBatchLoader<int, Base.Entities.Orders.OrderPreset>(
"OrderPresetById", orderPresetController.GetOrderPresetsByIdAsync
);
return loader.LoadAsync(context.Source.PresetId);
}
);
Sadly, the same method doesn't work with lists.
Any help is much appreciated!
Edit
My current attempt at solving this, looks like this:
Connection<NonNullGraphType<AssetFilterPresetFieldGraphType>>()
.Name("fields")
.Unidirectional()
.Description("Returns a list of AssetFilterPresetFieldGraphType connected to this AsetFilterPresetGraphType")
.ResolveAsync(async context =>
{
var result = await assetFilterPresetController.GetFilterPresetFieldsByIdAsync(context.Source.Id)
.ConfigureAwait(false);
return ConnectionResolver.ToConnection(result.Data, context);
});
I stumbled into this problem as well. I solved by wrapping the current type with NonNullableGraphType using an extension method.
public static ConnectionBuilder<TSource> NonNullable<TSource>(
this ConnectionBuilder<TSource> builder
)
{
builder.FieldType.Type = typeof(NonNullGraphType<>).MakeGenericType(builder.FieldType.Type);
return builder;
}
Use it like this:
Connection<UserGraphType>()
.Name("users")
.NonNullable()
.Resolve(ctx => /*...*/);

How to handle multiple action types in one epic? Any cons of doing the same?

Pretty new to redux-observables, rxjs and observables. Wanted to know how can I handle another action, say 'ActionTwo' in the same epic
const Epic1 = (action$,store) => {
return action$.ofType('ActionOne')
.mergeMap((action) => {
return ajax({'method': 'GET', 'url': 'someUrl')
.map(response => resultActoin(action.userId, response.response));
}
);
}
Something like
const Epic1 = (action$){
if('ActionOne') make a API call.
if('ActionTwo') make some other API call.
else do nothing.
}
Is it the same API call? If so, ofType() accepts more than one type. You can just do action$.ofType('ActionOne', 'ActionTwo').
If you want to make a request to another API/URL, I would recommend to make another epic. You can "merge" all you epics with combineEpics see: https://redux-observable.js.org/docs/basics/SettingUpTheMiddleware.html

Best practice for meteor dynamic subscription

Is it possible to do something like "filtered subscription" in Meteor: for example if you have a filter on month june and switching to july fetches the new data and subscribes to it?
i tried something like:
Meteor.publish("report", function (query, opt) {
return Report.find({ 'timestamp' : { $gte : query.from, $lt: query.to }}, options);
}
on client with iron router:
HomeController=RouteController.extend({
template:"home",
waitOn:function(){
var dates = getDates();
return Meteor.subscribe("report", dates);
},
fastRender: true
});
but it does not work.
Is there a better method to dynamically subscribe? Or does it just help to navigate with url pattern?
thanks
Is there a better method to dynamically subscribe?
There is an alternative method using template subscriptions, example below. I don't think it's better, just different.
Or does it just help to navigate with url pattern?
If you want to handle the subscriptions in the Router, then storing the subscription query params in the URL does help and has some added benefits in my opinion. But it depends on your desired app behavior.
Using Template Subscriptions approach :
This Meteor Pad example will subscribe to a range of data based on a select :
http://meteorpad.com/pad/26dd8YQevBbA5uNGA/Dynamic%20Subscription
Using Iron Router approach :
This route example will subscribe based on the URL . "items/0/10" will subscribe to the itemData with a range of zero to 10.
Router.route('Items', {
name:'Items',
path:'items/:low/:high',
subscriptions : function(){
var low = parseInt(this.params.low);
var high = parseInt(this.params.high);
return [
Meteor.subscribe("itemData",low,high),
];
},
action: function () {
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
}
});
I think either approach is fine and depends on your interface. Using the URL is nice because you can provide links directly to the range of data, use forward and back buttons in browser, good for paging lists of data.
The template subscriptions approach might be appropriate to change the data on a graph.
The specific issue you are having might be due to the fact that your getDates() is not reactive, so the subscription is only run once when the route waitOn is first run.

How to 'transform' data returned via a Meteor.publish?

Meteor Collections have a transform ability that allows behavior to be attached to the objects returned from mongo.
We want to have autopublish turned off so the client does not have access to the database collections, but we still want the transform functionality.
We are sending data to the client with a more explicit Meteor.publish/Meteor.subscribe or the RPC mechanism ( Meteor.call()/Meteor.methods() )
How can we have the Meteor client automatically apply a transform like it will when retrieving data directly with the Meteor.Collection methods?
While you can't directly use transforms, there is a way to transform the result of a database query before publishing it. This is what the "publish the current size of a collection" example describes here.
It took me a while to figure out a really simple application of that, so maybe my code will help you, too:
Meteor.publish("publicationsWithHTML", function (data) {
var self = this;
Publications
.find()
.forEach(function(entry) {
addSomeHTML(entry); // this function changes the content of entry
self.added("publications", entry._id, entry);
});
self.ready();
});
On the client you subscribe to this:
Meteor.subscribe("publicationsWithHTML");
But your model still need to create a collection (on both sides) that is called 'publications':
Publications = new Meteor.Collection('publications');
Mind you, this is not a very good example, as it doesn't maintain the reactivity. But I found the count example a bit confusing at first, so maybe you'll find it helpful.
(Meteor 0.7.0.1) - meteor does allow behavior to be attached to the objects returned via the pub/sub.
This is from a pull request I submitted to the meteor project.
Todos = new Meteor.Collection('todos', {
// transform allows behavior to be attached to the objects returned via the pub/sub communication.
transform : function(todo) {
todo.update = function(change) {
Meteor.call('Todos_update', this._id, change);
},
todo.remove = function() {
Meteor.call('Todos_remove', this._id);
}
return todo;
}
});
todosHandle = Meteor.subscribe('todos');
Any objects returned via the 'todos' topic will have the update() and the remove() function - which is exactly what I want: I now attach behavior to the returned data.
Try:
let transformTodo = (fields) => {
fields._pubType = 'todos';
return fields;
};
Meteor.publish('todos', function() {
let subHandle = Todos
.find()
.observeChanges({
added: (id, fields) => {
fields = transformTodo(fields);
this.added('todos', id, fields);
},
changed: (id, fields) => {
fields = transformTodo(fields);
this.changed('todos', id, fields);
},
removed: (id) => {
this.removed('todos', id);
}
});
this.ready();
this.onStop(() => {
subHandle.stop();
});
});
Currently, you can't apply transforms on the server to published collections. See this question for more details. That leaves you with either transforming the data on the client, or using a meteor method. In a method, you can have the server do whatever you want to the data.
In one of my projects, we perform our most expensive query (it joins several collections, denormalizes the documents, and trims unnecessary fields) via a method call. It isn't reactive, but it greatly simplifies our code because all of the transformation happens on the server.
To extend #Christian Fritz answer, with Reactive Solution using peerlibrary:reactive-publish
Meteor.publish("todos", function() {
const self = this;
return this.autorun(function(computation) {
// Loop over each document in collection
todo.find().forEach(function(entry) {
// Add function to transform / modify each document here
self.added("todos", entry._id, entry);
});
});
});

Resources