Error when mapping an EventLoopFuture<Type> to an expected Type

1.6k views Asked by At

I've tried mapping, flat mapping, creating an EventLoopFuture of Post, etc... I'm trying to return two db.queries that create separate arrays of content to be rendered on the req.view.render, which returns an EventLoopFuture<View>.

My error is: Cannot convert value of type 'EventLoopFuture<[Posts]>' to expected argument type '[Posts]'.

Here is my code that gets called by the router:

func blogView(req: Request) throws -> EventLoopFuture<View> {
    struct PageContext: Encodable {
        var posts: [Posts]
        var categories: [Categories]
        var title: String
    }
    struct Posts: Encodable {
        var posts: BlogPostModel.ViewContext
        var category: BlogCategoryModel.ViewContext
    }
    struct Categories: Encodable {
        var categoryList: BlogCategoryModel.ViewContext
    }

    let posts = BlogPostModel.query(on: req.db)
        .sort(\.$date, .descending)
        .with(\.$category)
        .all()
        .mapEach {Posts(posts: $0.viewContext, category: $0.category.viewContext)}
    let categories = BlogCategoryModel.query(on: req.db)
        .sort(\.$title)
        .all()
        .mapEach {Categories(categoryList: $0.viewContext)}
    let returnContext = PageContext(posts: posts,categories: categories, title: categories)
    return req.view.render("Blog/Frontend/Blog", returnContext)
}

EDIT: re my comment below. This snippet returns the Posts (and associated Categories). Trying to add a second db.query to the return.

func blogView(req: Request) throws -> EventLoopFuture<View> {
    struct Context: Encodable {
        struct PostWithCategory: Encodable {
            var category: BlogCategoryModel.ViewContext
            var post: BlogPostModel.ViewContext }
        let title: String
        let items: [PostWithCategory]
    }

    return BlogPostModel.query(on: req.db)
        .sort(\.$date, .descending)
        .with(\.$category)
        .all()
        .mapEach {
            Context.PostWithCategory(category: $0.category.viewContext, post: $0.viewContext) 
        }
        .flatMap {
            let context = Context(title: "Blog Posts", items: $0)
            return req.view.render("Blog/Frontend/Blog", context)
        }
}
1

There are 1 answers

1
Caleb Kleveter On BEST ANSWER

Your issue is that your PageContext type has properties of types [Post] and [Categories], but you are trying to initialize a PageContext using EventLoopFuture<[Post]> and EventLoopFuture<[Categories]>. What you can do is use NIO's .and method to combine 2 EventLoopFuture objects into 1:

posts.and(categories) // EventLoopFuture<([Post], [Categories])>

You can then map on this new EventLoopFuture to get the tuple and create your PageContext instance:

return posts.and(categories).flatMap { posts, categories in
    let returnContext = PageContext(posts: posts, categories: categories, title: "Blog Posts")
    return req.view.render("Blog/Frontend/Blog", context)
}