different directory access in firebase realtime database for dialogflow fulfillment - firebase-realtime-database

I'm a newbie in node.js(firebase functions) and Dialogflow fulfillment, I want to retrieve data in a different directory. first is to check the nearest store, and then check the inventory of the store in a different directory, but I have a problem with return. so how I can fix it?
app.intent('location_checking - yes',(conv)=> {
var store= database.ref('store');
var inventory = database.ref('inventory);
var keystore=[];
return store.orderByKey().on("child_added", function(snapshot){
keystore.push(snapshot.key)
})
return inventory.child(keystore).on("value", function(snapshot){
var tomato =snapshot.val().tomato;
//and then check the nearest store with available stock
})
})

You have a few issues, some of them conceptual.
The first is that you're using on() and the "child_added" event. But since this is happening inside an Intent Handler, which only gets triggered when the user has done something, you can't also listen to conventional events and react to them. Instead, you should probably use once() with a "value" event - so you query for the values you want and work with them.
Second is that the Intent Handler expects you to return a Promise if you are doing any asynchronous operations - anything that would require a callback handler, for example. This would require some restructuring in how you make the calls to once(), so they return a Promise, and you take action in a .then() block. Since you can chain Promises together using .then(), you can make multiple calls this way.
I'm not sure that ordering by key will get you the "closest" store, but I'll ignore that for the moment to illustrate the rest of the code.
So that part of your code might look something like
return store.orderByKey().once("value")
.then( snapshot => {
// Handle the results
// ...
// Make the next query
return inventory.child( childKey ).once("value");
})
.then( snapshot => {
// Handle the inventory results
});
You can also do this with async/await by making your Intent Handler an async function and then calling await on the database calls. Possibly something like.
app.intent('location_checking - yes', async (conv) => {
const store= database.ref('store');
const inventory = database.ref('inventory);
//...
const storeSnapshot = await store.orderByKey().once("value");
// Do something with the store snapshot
const inventorySnapshot = await inventory.child( childKey ).once("value");
// Do stuff with the inventory snapshot
})

Related

Confusion in Dart's async await

I have a confusion in understanding Dart's async/await functionality. Most tutorials use the following example:
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
Future<void> main() async {
print('Fetching user order...');
print(await createOrderMessage());
}
I understand that the fetchUserOrder function returns a Future. Anyone who calls this function will immediately get a Future object as a result but this Future object may not have the real result value at that time. It will be filled up in "future".
Now, the createOrderMessage function calls: await fetchUserOrder(); This means, the control will wait till fetchUserOrder() returns a completed/non-empty Future. Am I right here? Is this what await does?
If that is correct, it means, the createOrderMessage function is essentially synchronous now because it won't return until the Future returned by fetchUserOrder is filled. Thus, the order variable in this function is initialized with a completed Future. Then why does this function need the "async" keyword in its function declaration? What does it signify?
Second confusion is if Dart is single threaded, when and how exactly is an async function executed? If I invoke multiple method calls that return Futures like this without await:
...
Future<A> fa = getA();
Future<B> fb = getB();
Future<C> fa = getC();
...
Will the functions getA, getB, and getC be executed sequentially in the background or they will be executed "in parallel" somehow?
Now, the createOrderMessage function calls: await fetchUserOrder(); This means, the control will wait till fetchUserOrder() returns a completed/non-empty Future. Am I right here? Is this what await does?
Yes. the await keyword means you get the completed T instead of Future<T> in return. So:
var a = fetchUserOrder(); // Type of a: Future<String>
var b = await fetchUserOrder(); // Type of b: String
When you use await, you tell the code to await the completion of the process and get the actual result. But without await, the stream is in the future and is in process until you await it somewhere else.
why does this function need the "async" keyword in its function declaration?
It's a rule to specify long-running functions. So when a function awaits for a long running process to complete, the function itself is also a long-running process. Why? Because it's waiting for another one to complete.
Therefore, you need to specify async for that as well. When another function is calling this one, it also knows this one might be long-running.
In short, every awaitable function needs to be in an async function.
Second confusion is if Dart is single threaded, when and how exactly is an async function executed?
You're mixing the concept of parallelism with asynchronous. An async process does not have to be done in multi thread.
Async processes can be one one at time, but in a different order in compare to synchronous code.
Take a look at this article which explains asynchronous in a single thread.
Now, the createOrderMessage function calls: await fetchUserOrder(); This means, the control will wait till fetchUserOrder() returns a completed/non-empty Future. Am I right here? Is this what await does?
If that is correct, it means, the createOrderMessage function is essentially synchronous now because it won't return until the Future returned by fetchUserOrder is filled. Thus, the order variable in this function is initialized with a completed Future.
await allows asynchronous functions to have the appearance of synchronous functions by allowing asynchronous code to be structured very similarly to synchronous code. In your example, it's syntactic sugar for registering a Future.then() callback and immediately returning:
Future<String> createOrderMessage() {
var future = fetchUserOrder().then((order) {
return 'Your order is: $order';
});
return future;
}
await defers execution of the rest of that function; it does not wait and block execution of your entire thread. Your program will continue running its event loop, possibly allowing other asynchronous operations to make progress.
Will the functions getA, getB, and getC be executed sequentially in the background or they will be executed "in parallel" somehow?
As I mentioned in comments, it depends on how getA, getB, and getC are implemented. They could run in parallel, such as if they run in separate Dart isolates or in separate threads in the Dart VM/runtime.

Pausing a stream in dart null safety

I'm converting dart code to nnbd.
I have the following code.
var subscription = response.listen(
(newBytes) async {
/// if we don't pause we get overlapping calls from listen
/// which causes the [writeFrom] to fail as you can't
/// do overlapping io.
subscription.pause();
/// we have new data to save.
await raf.writeFrom(newBytes);
subscription.resume();
});
The problem is I get the following error:
The non-nullable local variable 'subscription' must be assigned before it can be used.
Try giving it an initializer expression, or ensure that it's assigned on every execution path.
I've had a similar problem solved here:
dart - correct coding pattern for subscription when using null saftey?
which was answered by #lrn
However the pattern solution pattern doesn't seem to work in this case.
raf.writeFrom is an async operation so I must use an 'async' method which means I can't use the 'forEach' solution as again I don't have access to the subscription object.
If you really want to use listen, I'd do it as:
var subscription = response.listen(null);
subscription.onData((newBytes) async {
subscription.pause();
await raf.writeFrom(newBytes);
subscription.resume();
});
or, without the async:
var subscription = response.listen(null);
subscription.onData((newBytes) {
subscription.pause(raf.writeFrom(newBytes));
});
which will pause the subscription until the future returned by raf.writeFrom completes (it shouldn't complete with an error, though).
If using listen is not a priority, I'd prefer to use an asynchronous for-in like:
await for (var newBytes in subscription) {
await raf.writeFrom(newBytes);
}
which automatically pauses the implicit subscription at the await and resumes it when you get back to the loop.
Both with stream.listen and the StreamController constructor, null safety has made it nicer to create them first without callbacks, and then add the callbacks later, if the callback needs to refer to the subscription/controller.
(That's basically the same nswer as in the linked question, only applied to onData instead of onDone. You have to pass a default onData argument to listen, but it can be null precisely to support this approach.)
I don't think your code, as written, was legal before null-safety either; you can't reference a variable (subscription) before it's declared, and the declaration isn't complete until after the expression you initialize it with (response.listen(...)) is evaluated. You will need to separate the declaration from the initialization to break the circular dependency:
StreamSubscription<List<int>> subscription;
subscription = response.listen(...);

Trigger a StreamController at ngOnInit()

Taking this example from the doc:
Stream<List<Hero>> heroes;
// ยทยทยท
void ngOnInit() async {
heroes = _searchTerms.stream
.transform(debounce(Duration(milliseconds: 300)))
.distinct()
.transform(switchMap((term) => term.isEmpty
? Stream<List<Hero>>.fromIterable([<Hero>[]])
: _heroSearchService.search(term).asStream()))
.handleError((e) {
print(e); // for demo purposes only
});
}
Say I want to "trigger" the stream at ngOnInit().
After some tests, I find this can be done by calling void search(String term) => _searchTerms.add(term); just after this:
await Future.delayed(Duration(milliseconds: 1));
Seems that the _searchTerms call inside ngOnInit() is not await.
Could anyone explain why this works that way, or what I am doing wrong?
It isn't exactly clear what you are trying to do here, but some background that might help.
Angular lifecycle methods can't be interrupted. They also will not wait for async actions. They are simply callbacks that will be called at the point of the angular lifecycle. Asking angular to wait for you to do work at some unknown point to it is not possible. What if the action never completed? What happens to the rest of the subtree? You would be in some weird state that would invalidate much of the logic and the app.
Instead we use change detection/variables to change the state of the component to handle these async actions. So you could show a progress indicator using a boolean variable until the rpc comes back and then show the results by flipping the variable.

Is there a way to get the Future from setMethodCallHandler?

I have a setMethodCallHandler which runs a callback from my Java code, and I want it to set a Future containing the result. Something like
Future<String> fun() async {
return setMethodCallHandler((MethodCall call) {
return () async {return call.arguments["arg"];}();
});
}
What I want to be able to do is if call.argument will return "abc",
var a = await fun();
a will be equal to "abc"
The only information I found was the documentation on setMethodCallHandler:
If the future returned by the handler completes with a result, that value is sent back to the platform plugin caller wrapped in a success envelope as defined by the codec of this channel. If the future completes with a PlatformException, the fields of that exception will be used to populate an error envelope which is sent back instead.
But I don't understand how can I get the "platform plugin caller wrapped in a success envelope as defined by the codec of this channel"?
I'm guessing, but correct me if I'm wrong, that setMethodCallHandler does not return a value, it only sets up a function to be called later.
So, you can't use the return value of the setMethodCallHandler for anything.
That effectively means that you have an "event" of a kind, one that you want to "convert" into a future completion. To do that, you use a Completer to create and later complete a Future.
Future<String> fun() {
var completer = new Completer<String>();
setMethodCallHandler((MethodCall call) {
completer.complete(call.arguments["arg"]);
}
return completer.future;
}
Using async functions works when your events all come from futures or streams, but when you get other kinds of events (like port events, I/O callbacks or timers) and you want to map that back to future/stream events, you use either a Completer to complete a future or a StreamController to add events to a stream.

Is there a more elegant way to handle HttpRequest body content in Dart?

With the release of the new dart:io libraries, in order to read the data from an HttpRequest we now need to:
Listen to the body to handle data and notified of it's completion.
In order to accomplish this, I've been using something similar to the following to get all of the data from the request (taken from the dart:io tests):
List<int> body = new List<int>();
request.listen(body.addAll, onDone: () {
var str = new String.fromCharCodes(body);
// Now do something with the string of data
});
Is there some way of using transform and/or StringDecoders to already provide a constructed result. The only way I can think of, I would still need to create a StringBuffer and use writeAll to ensure all data is passed in the event it doesn't all arrive at once, and still call the onDone before using the string in the buffer.
So I guess ultimately the question is: is there some way I can use a HttpRequest (or in all actuality any Stream) without needing to buffer/build the results and can just pass a callback or handler which receives the entire contents?
I haven't tried this, but I think you should be able to use StringDecoder, toList() and join() to get the whole body:
request.transform(new StringDecoder()).toList().then((data) {
var body = data.join('');
print(body);
}

Resources