-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
STAC Client pagination support #327
STAC Client pagination support #327
Conversation
1cabc1c
to
23a050e
Compare
30716e3
to
7c238b1
Compare
c4d8a6e
to
ccbd9ed
Compare
fbab985
to
fe67718
Compare
type SttpStacClient[F[_]] = SttpStacClientF[F, SearchFilters] | ||
type StacClient[F[_]] = StacClientF[F, SearchFilters] | ||
type StreamingClient[F[_]] = StreamingStacClientF[F, fs2.Stream[F, *], SearchFilters] | ||
type StreamingStacClient[F[_], G[_]] = StreamingStacClientF[F, G, SearchFilters] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still should be type aliases, traits would not work since they add children into the traits hierarchy.
def item(collectionId: NonEmptyString, itemId: NonEmptyString): F[StacItem] | ||
def itemCreate(collectionId: NonEmptyString, item: StacItem): F[StacItem] | ||
def collectionCreate(collection: StacCollection): F[StacCollection] | ||
} | ||
|
||
trait StreamingStacClientF[F[_], G[_], S] extends StacClientF[F, S] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
G
here is a separate parameter to make it independent from F
.
/** [[Sync]] instance defined for Either[Throwable, *]. | ||
* It is required (sadly) to derive [[fs2.Stream.Compiler]] which is necessary for the [[fs2.Stream.compile]] function. | ||
*/ | ||
implicit val eitherSync: Sync[Either[Throwable, *]] = new Sync[Either[Throwable, *]] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use the default synchronous Either backend to use the same tests set for the Scala JS backend. (c)
9a1f157
to
e85ee2f
Compare
val items = body.flatMap(_.hcursor.downField("features").as[List[StacItem]]).liftTo[F] | ||
val next = getNextLink(body).map(_.map(_ -> noPaginationBody)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this can be better handled via #199 eventually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mostly looks good -- can you let me know some testing instructions so I can try it out?
// the same filter would be used as a body for all pagination requests | ||
val noPaginationBody = filter.map(paginationTokenLens.set(None)(_).asJson).getOrElse(emptyJson) | ||
Stream | ||
.unfoldLoopEval((baseUri.withPath("search"), initialBody)) { case (link, request) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha nice first search result
@jisantuc you mean testing insturctions that are different from tests? There is also its usage example in GT Server. Sure: // to run it you'd need the following dep
// "com.softwaremill.sttp.client3" %% "async-http-client-backend-cats-ce2" % "3.3.4"
import com.azavea.stac4s.api.client.SttpStacClient
import cats.effect.IO
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend
import sttp.client3.UriContext
import scala.concurrent.ExecutionContext
object Test {
implicit val executionContext = ExecutionContext.global
implicit val contextShift = IO.contextShift(executionContext)
implicit val timer = IO.timer(executionContext)
def main(args: Array[String]): Unit = {
AsyncHttpClientCatsBackend
.resource[IO]()
.use { backend =>
val client = SttpStacClient(backend, uri"https://franklin.nasa-hsi.azavea.com/")
// any number here, or don't use take at all
// try to pass params, fetch collections, items, etc
client.search.take(95).compile.toList
}
.map(list => println(s"items count: ${list.map(_.id).distinct.length}"))
.unsafeRunSync()
}
} |
Yeah pretty much exactly that -- it's helpful to me to have a sense of the real use that the test is a tiny version of. Maybe that's not a great attitude about tests. Anyway I threw your example into this ammonite script and it worked great:
|
Overview
This PR refactors StacClient. All methods that returned Lists return fs2.Streams now. These changes allowed SttpStacClient to support pagination 🎉 🎉 🎉
All changes are done to keep the interface as simple as it is possible, see how it can be combined via
Apply2K
hereChecklist
chan
)Other info
or a more traditional
attach
semantics:Closes #198
Closes #324
Closes #326
Closes #316
Closes #314