Query child in Fluent+Vapor - fluent

I'm confused on how to query the children of a model object and use it immediately. My Client contains a number of Station children
final class Client: PostgreSQLModel {
var stations: Children<Client, Station> {
return children(\.clientID)
}
}
and then in my controller I have a list of clients that I want to look at and grab their stations.
func clientIndexHandler(_ req: Request) throws -> Future<View> {
return Client.query(on: req).all().flatMap(to: View.self) { clients in
let sorted = clients.sorted { ... }
let content = try sorted.map { client in
let stations = try client.stations
.query(on: req)
.all()
.map(to: [String].self) { stations in
return stations.map { $0.name }
}
// Now I want to use the stations for other stuff.
return ClientIndexContent(client: client, stations: stations, ....)
}
let context = ClientIndexContext(clients: content)
return try req.make(LeafRenderer.self).render("clients/index", context)
}
}
My problem is that stations is an EventLoopFuture<[String]> instead of a [String]. Since I'm using Leaf here I need the actual values from the clients and stations so that I can populate the content to pass into the leaf renderer.

So you have a number of ways of doing it, but basically you need to rethink how you do things in an async world. However, Vapor does provide some nice things to help this. To start with, Leaf can actually handle futures, so if you set your ClientIndexContext to have a property of let stations: Future<[String]>, then you can just access that inside Leaf as normal.
The other option you can do is to call map(to: [String].self) on stations which will get all of the futures for you.

Related

How can I use the JSON value obtained from a function in a different function? (Might be clearer with explanation below)

So I have a pretty normal eventListener that listens to the incoming events.
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
It goes to the handleRequest, which does certain different tasks depending on the request.url.
async function handleRequest (request) {
var url = new URL(request.url);
if (url.pathname === '[some-domain-name]/[some-link]') {
var jsonResult = handleJSON();
return jsonResult;
} else {
return handleHTML();
}
The handleJSON() and the handleHTML() are two additional functions that I have set up. What I essentially want to do is add one more if condition that has the criteria based on the response from handleJSON(), i.e., if jsonResult = [somevalidvalue] run handleHMTL() else respond with "You haven't accessed /[some-link] yet.
So to summarize, if we go to [some-domain-name] it should respond with the sentence. Then once we access /[some-link] we get some kind of value in jsonResult AFTER WHICH if we go back to [some-domain-name] it should hit with the response from handleHTML(). Also if possible, I'd like to know how can I pass the value from jsonResult in to our handleHTML() function. This is the result in the jsonResult.
const body = JSON.stringify(links, null, 2)
return new Response(body, init)
I'm sorry if the information sounds too long and stretched out. I haven't used Cloudflare's worker before and I've been trying to figure out the little stuff of what goes where and what I can and can't do with it. Thank You!
Your code implies that handleJSON() returns a Response object, since you then return it as the response to the original request. Your question is a little unclear, but it sounds like you are saying that this response contains a JSON body, and you want to inspect that body in your code. So you could do something like:
let jsonResponse = handleJSON();
if (jsonResponse.ok) { // check status code is 200
let jsonValue = await jsonRespnose.json();
if (jsonValue.someFlag) {
return handleHTML();
}
}
Note that calling jsonResponse.json() consumes the response body. Therefore, you can no longer return the response after this point. If you decide you want to return the JSON response to the client after all, you'll need to reconstruct it, like:
jsonResponse = new Respnose(JSON.stringify(jsonValue), jsonResponse);
This recreates the response body, while copying over the status and headers from the original response.

Swift Vapor3 Raw SQL query with new connection

I'm attempting to use Vapor3 to perform raw SQL queries. The supplied documentation for this kind of thing is pretty vague on the website unfortunately.
Essentially I want to do something like:
router.get("example") { req -> Future<View> in
let leaf = try request.make(LeafRenderer.self)
// I can't get this next bit to work. Does anyone have any ideas how to do this? I seem to get all sorts of Xcode errors with .mysql, closures etc.
let users = try request.withNewConnection(to: .mysql) { connection -> EventLoopFuture<[User]>
return try connection.raw("select * from users").all(decoding: User.self)
}
var context = [String: String]()
context["user"] = users
return leaf.render("example", context)
}
Any help on want I'm doing wrong here would be greatly appreciated.
Thanks in advance,
Matt
You code was failing because you aren't implementing the closure properly. Your route returns in the let users... closure so the second return is never reached.
This works:
router.get("example")
{
insecure.get("example") {
request -> Future<View> in
return request.withNewConnection(to: .mysql) {
connection in
return connection.raw("select * from User").all(decoding: User.self).flatMap(to:View.self) {
users in
return try request.make(LeafRenderer.self).render("example",["users":users])
}
}
}
}
The changes are:
There's no need to define leaf until you need it.
The definition of users is now inside the closure.

how to fetch data from two different api simulations? swift

I would like to know, according to a job interview that I have been, how to fetch 2 differents API call - let say movie name and international language support API
how to download 2 of them together to into one table view?
thank you in advance it will help me a lot
It is Simple You have to create request chain and after getting both result reload the tableview
you have create array of dictionary from both service resposnse
For example say first will return just arrayForMovieName:["a","b","c"]
and Second will return just arrayForLanguage:["Hindi","English","etc"]
now merge this two array into your created third array of dictionary like
arrForMovieWithLanguage = [[movie:"a","language":["Hindi","English"]],[movie:"b","language":["English"]]]
Solution :1 Take boolean for both service like
var isLanguageGet:Bool = false
var isMovieGet:Bool = false
wsGetMovie()
{
isMovieGet = true
if isLanguageGet
{ self.tableView.reloadData()
}
}
wsGetLanguage()
{
isLanguageGet = true
if isMovieGet
{ self.tableView.reloadData()
}
}
Solution :2 Make webservice call sync
wsGetMovie()
{
wsGetLanguage()
}
wsGetLanguage()
{
self.tableView.reloadData()
}
You can use closure to wait asynchronously for another API response. i 'm just give you a idea of implementation. after that you can implement as per your requirement.
In my requirement it needs Euro price from first service. and after that another API need that euro price and will return Payment data. So, I achieve this scenario like below.
func getPaymentDetail(euroPrice: Double, completion: #escaping (Result<JSON>) -> Void) {
// Call second API and return result in completion closure.
if response.result.isSuccess {
completion(response.result)
}
// For failure handle here.
}
func getPriceOfEuro(rate: #escaping (Double) -> Void) {
// Here I get Euro price.
}
Then bind them in sequence like below.
getPriceOfEuro(rate: { (price) in
self.getPaymentDetail(euroPrice: price, completion: { (result) in
// Take data from result and reload Table.
})
})

integrate UISearchController with Async result update in swift

I want to implement UISearchContoller that search from webservice JSON with swifty json, exactly like apple's appStore when you search for an app, it loads without load them into tableView
here is what I have done in updateSearchResultsForSearchController method:
func updateSearchResultsForSearchController(searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
func filterContentForSearchText(searchText: String) {
filteredContents = myStruct.filter{$0.name.rangeOfString(searchText) != nil
}
Posting more of your code would be nice, like what you are using to get the results from the web service, However, I will try to step you through it anyway.
I have done with before just using a UISearchBar and it's delegate method, one the user pressed the search button or enter, I would use NSURLSession to pass the user's search terms to the API, and parsed the response.
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let searchText : String = searchBar.text
webService.getRecipe(ingredient: searchText, completionHandler: { (recipeArray) in
self.highProteinArray = recipeArray
dispatch_async(dispatch_get_main_queue(), {
self.collectionView.reloadData()
})
})
}
As you can see I used a callback to handle setting the newly parsed data to a variable for later use, and then reloaded the collectionView. This way your tableView/collectionView will load and set itself up while you are waiting for the response from the web service and then parsing it, once that is complete you just reload to show the new data.
To add a little extra you could even add a fading in animation in your cellForItemAtIndexPath or cellForRowAtIndexPath, whichever you are using.

Returning a reference does not live long enough

I've just started learning Rust, and have come from a mainly JavaScript background so I'm a bit stumped when it comes to the whole borrowing system and memory management.
I have the following code:
fn load(db: &MyPool, id: i32) -> &Account{
let accounts: Vec<Account> = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
.and_then(|mut stmt| {
stmt.execute(&[&id]).map(|result| {
result.map(|x| x.unwrap()).map(|row| {
Account{
id: from_value(&row[0]),
balance: from_value(&row[1]),
name: from_value(&row[2])
}
}).collect()
})
}).unwrap();
&accounts[0]
}
And I've managed to fix all the errors the compiler throws out apart from
/main.rs:42:4: 42:12 error: 'accounts' does not live long enough
Is this the best way to get one result from the MySQL query, or have I been going at it completely wrong?
You don't want to return a reference to an account, but you want to pass ownership to the caller after retrieving from the db.
Thus, change the signature to:
fn load(db: &MyPool, id: i32) -> Account
Now the idea would be to return the object by value, not by reference:
accounts[0]
However doing so will fail with an error: cannot move out of indexed content. A better approach would be to avoid collecting in a vector altogether, and use Iterator::next(&self) to take the first element. This would look like:
fn load(db: &MyPool, id: i32) -> Account{
let account: Account = db.prepare("SELECT id, balance, name FROM `accounts` WHERE `id`=?")
.and_then(|mut stmt| {
stmt.execute(&[&id]).map(|result| {
result.map(|x| x.unwrap()).map(|row| {
Account{
id: from_value(&row[0]),
balance: from_value(&row[1]),
name: from_value(&row[2])
}
}).next().unwrap() // <- next() takes the first elt of the iterator
})
}).unwrap();
account // <- return by value, pass ownership to caller
}
(Untested as I couldn't reproduce your dev environment.)
Kind of unrelated, but it is worth noting that those multiple unwrap() calls render your function extremely brittle as any failure will crash your whole program with a panic. Fortunately the answer to this bad smell is easy: you want to return Option<Account> rather than Account. Then remove all calls to unwrap() and let the Option<Account> propagate throughout calls (your use of map() is good because it says "return None if you find None and return Some(f(a)) if you find Some(a)".)