///|
/// Only the resolvers are written by hand: leaving one out is a compile warning that names it.
let authors : Array[Author] = [
{ id: "a1", name: "Ursula", },
{ id: "a2", name: "Stanislaw", },
]
///|
let books : Array[Book] = [
{ id: "b1", title: "The Dispossessed", status: PUBLISHED, author_id: "a1", },
{ id: "b2", title: "Solaris", status: PUBLISHED, author_id: "a2", },
{ id: "b3", title: "Notes", status: DRAFT, author_id: "a2", },
]
///|
fn Query::book(id : String) -> Book? raise {
books.iter().find_first(b => b.id == id)
}
///|
fn Query::search(text : String) -> Array[Hit] raise {
let hits : Array[Hit] = []
for a in authors {
if a.name.contains(text) {
hits.push(Author(a))
}
}
for b in books {
if b.title.contains(text) {
hits.push(Book(b))
}
}
hits
}
///|
fn Mutation::add_book(input : NewBook) -> Book raise {
guard authors.iter().any(a => a.id == input.author_id) else {
raise @exec.ResolverError("no author \{input.author_id}")
}
let book = {
id: "b\{books.length() + 1}",
title: input.title,
status: DRAFT,
author_id: input.author_id,
}
books.push(book)
book
}
///|
fn Author::books(self : Author, first? : Int32) -> Array[Book] raise {
let own = books.filter(b => b.author_id == self.id)
match first {
Some(n) if n < own.length() => own[:n].to_owned()
_ => own
}
}
///|
fn Book::author(self : Book) -> Author raise {
guard authors.iter().find_first(a => a.id == self.author_id) is Some(a) else {
raise @exec.ResolverError("no author \{self.author_id}")
}
a
}
///|
/// A subscription is a function whose array is the stream of events, so `bookAdded` delivers the
/// books it finds — one event each — and the executor maps every event to a response.
fn Subscription::book_added(author_id? : String) -> Array[Book] raise {
match author_id {
Some(id) => books.filter(b => b.author_id == id)
None => books.copy()
}
}