Skip to content

Commit

Permalink
Merge pull request #71 from algolia/feat/multiple_get
Browse files Browse the repository at this point in the history
Multiple get objets
  • Loading branch information
ElPicador committed Jan 26, 2016
2 parents d22a592 + 1853d50 commit c73f90f
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 21 deletions.
44 changes: 32 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Table of Contents

1. [Setup](#setup)
1. [Quick Start](#quick-start)
1. [Philosophy of the scala client](#philosophy)
1. [Philosophy of the scala client](#philosophy)
1. [Online documentation](#documentation)
1. [Tutorials](#tutorials)

Expand Down Expand Up @@ -219,10 +219,10 @@ client.execute { get / "index" / "myId" }
Future
------

The `execute` method always return a [`scala.concurrent.Future`](http://www.scala-lang.org/api/2.11.7/#scala.concurrent.Future).
The `execute` method always return a [`scala.concurrent.Future`](http://www.scala-lang.org/api/2.11.7/#scala.concurrent.Future).
Depending of the operation it will be parametrized by a `case class`. For example:
```scala
var future: Future[Search] =
var future: Future[Search] =
client.execute {
search into "index" query "a"
}
Expand All @@ -239,7 +239,7 @@ case class Contact(firstname: String,
followers: Int,
compagny: String)

var future: Future[Seq[Contact]] =
var future: Future[Seq[Contact]] =
client
.execute {
search into "index" query "a"
Expand All @@ -260,7 +260,7 @@ case class EnhanceContact(firstname: String,
_snippetResult: Option[Map[String, SnippetResult]],
_rankingInfo: Option[RankingInfo]) extends Hit

var future: Future[Seq[EnhanceContact]] =
var future: Future[Seq[EnhanceContact]] =
client
.execute {
search into "index" query "a"
Expand Down Expand Up @@ -606,22 +606,40 @@ You can easily retrieve an object using its `objectID` and optionally specify a

```scala
// Retrieves all attributes
get objectId "myId" from "index"
client.execute {
get objectId "myId" from "index"
}

//or

get from "index" objectId "myId"
client.execute {
get from "index" objectId "myId"
}
```

You can get a case object by:
```scala
(get / "index" / "myId").map(_.as[Contact])
val result = client.execute {
get / "index" / "myId"
}

result.map(_.as[Contact])
```

You can also retrieve a set of objects:

```scala
//Not yet implemented
client.execute {
get from "index" objectIds Seq("myId", "myOtherId")
}
```

You can get a case object by:
```scala
val result = client.execute {
get from "index" objectIds Seq("myId", "myOtherId")
}

result.map(_.as[Contact])
```

Delete an object
Expand Down Expand Up @@ -709,7 +727,7 @@ You can decide to have the same priority for two attributes by passing them in t
* **advancedSyntax**: Enable the advanced query syntax. Defaults to 0 (false).

* **Phrase query:** a phrase query defines a particular sequence of terms. A phrase query is build by Algolia's query parser for words surrounded by `"`. For example, `"search engine"` will retrieve records having `search` next to `engine` only. Typo-tolerance is disabled on phrase queries.

* **Prohibit operator:** The prohibit operator excludes records that contain the term after the `-` symbol. For example `search -engine` will retrieve records containing `search` but not `engine`.
* **replaceSynonymsInHighlight**: (boolean) If set to false, words matched via synonyms expansion will not be replaced by the matched synonym in the highlighted result. Default to true.
* **maxValuesPerFacet**: (integer) Limit the number of facet values returned for each facet. For example: `maxValuesPerFacet=10` will retrieve max 10 values per facet.
Expand Down Expand Up @@ -1010,7 +1028,7 @@ are still returned ranked by attributes and custom ranking.


It will return a `cursor` alongside your data, that you can then use to retrieve
the next chunk of your records.
the next chunk of your records.

You can specify custom parameters (like `page` or `hitsPerPage`) on your first
`browse` call, and these parameters will then be included in the `cursor`. Note
Expand Down Expand Up @@ -1055,3 +1073,5 @@ You can retrieve the logs of your last 1,000 API calls and browse them using the





34 changes: 32 additions & 2 deletions src/main/scala/algolia/definitions/GetObjectDefinition.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@
package algolia.definitions

import algolia.http.HttpPayload
import algolia.responses.Get
import algolia.inputs.{Request, Requests}
import algolia.responses.{Get, Results}
import algolia.{AlgoliaClient, Executable, _}
import org.json4s.Formats
import org.json4s.JsonAST.JObject
import org.json4s.native.Serialization._

import scala.concurrent.{ExecutionContext, Future}

case class GetObjectDefinition(index: Option[String] = None, oid: Option[String] = None) extends Definition {
case class GetObjectDefinition(index: Option[String] = None, oid: Option[String] = None)(implicit val formats: Formats) extends Definition {

def objectIds(oids: Seq[String]): GetObjectsDefinition = GetObjectsDefinition(index, oids)

def from(ind: String): GetObjectDefinition = copy(index = Some(ind))

Expand All @@ -40,8 +45,26 @@ case class GetObjectDefinition(index: Option[String] = None, oid: Option[String]
HttpPayload(http.GET, Seq("1", "indexes") ++ index ++ oid)
}

case class GetObjectsDefinition(index: Option[String], oids: Seq[String] = Seq())(implicit val formats: Formats) extends Definition {

override private[algolia] def build(): HttpPayload = {
val requests = oids.map { oid =>
Request(index, oid)
}

HttpPayload(
http.POST,
Seq("1", "indexes", "*", "objects"),
body = Some(write(Requests(requests)))
)
}

}

trait GetObjectDsl {

implicit val formats: Formats

case object get {

def objectId(objectId: String) = GetObjectDefinition(oid = Some(objectId))
Expand All @@ -57,4 +80,11 @@ trait GetObjectDsl {
}
}

implicit object GetObjectsDefinitionExecutable extends Executable[GetObjectsDefinition, Results] {

override def apply(client: AlgoliaClient, query: GetObjectsDefinition)(implicit executor: ExecutionContext): Future[Results] = {
client request[Results] query.build()
}
}

}
28 changes: 28 additions & 0 deletions src/main/scala/algolia/inputs/Requests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2016 Algolia
* http://www.algolia.com/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package algolia.inputs

case class Requests(requests: Seq[Request])

case class Request(indexName: Option[String], objectID: String)
34 changes: 34 additions & 0 deletions src/main/scala/algolia/responses/Results.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2016 Algolia
* http://www.algolia.com/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package algolia.responses

import org.json4s._

case class Results(results: Seq[JObject]) {

implicit val formats = org.json4s.DefaultFormats

def as[T: Manifest]: Seq[T] = results.map(_.extract[T])

}
10 changes: 5 additions & 5 deletions src/test/scala/algolia/AlgoliaTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ import scala.concurrent.{ExecutionContext, Future}

class AlgoliaTest
extends FunSpec
with Matchers
with BeforeAndAfter
with ScalaFutures
with MockFactory {
with Matchers
with BeforeAndAfter
with ScalaFutures
with MockFactory {

val applicationId = System.getenv("APPLICATION_ID")
val apiKey = System.getenv("API_KEY")
Expand All @@ -51,7 +51,7 @@ class AlgoliaTest
}

val waiting = client.execute {
waitFor task t from index
waitFor task t from index maxDelay (60 * 1000) //60 seconds
}

whenReady(waiting) { result =>
Expand Down
34 changes: 32 additions & 2 deletions src/test/scala/algolia/dsl/GetObjectTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ package algolia.dsl

import algolia.AlgoliaDsl._
import algolia.AlgoliaTest
import algolia.http.{GET, HttpPayload}
import algolia.http.{GET, HttpPayload, POST}

class GetObjectTest extends AlgoliaTest {

Expand All @@ -40,9 +40,39 @@ class GetObjectTest extends AlgoliaTest {
}

it("should call API") {
(get objectId "myId" from "test").build() eq HttpPayload(GET, Seq("1", "indexes", "test", "myId"))
val payload = HttpPayload(GET, Seq("1", "indexes", "test", "myId"))
(get objectId "myId" from "test").build() should be(payload)
}

}

describe("get multiple objects") {

it("should get objects by ids") {
get from "test" objectIds Seq("myId1", "myId2")
}

it("should call API") {
val body =
"""
|{
| "requests":[
| {
| "indexName":"test",
| "objectID":"myId1"
| },{
| "indexName":"test",
| "objectID":"myId2"
| }
| ]
|}
""".stripMargin.split("\n").map(_.trim).mkString

val payload = HttpPayload(POST, Seq("1", "indexes", "*", "objects"), body = Some(body))
(get from "test" objectIds Seq("myId1", "myId2")).build() should be(payload)
}


}

}
90 changes: 90 additions & 0 deletions src/test/scala/algolia/integration/GetObjectIntegrationTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2016 Algolia
* http://www.algolia.com/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package algolia.integration

import algolia.AlgoliaDsl._
import algolia.responses.{Get, Results, TasksMultipleIndex}
import algolia.{AlgoliaClient, AlgoliaTest}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class GetObjectIntegrationTest extends AlgoliaTest {

val client = new AlgoliaClient(applicationId, apiKey)

after {
val indices = Seq(
"indexToGet"
)

val del = client.execute {
batch(indices.map { i => delete index i })
}

whenReady(del) { res => res }
}

it("should get object") {
val create: Future[TasksMultipleIndex] = client.execute {
batch(
index into "indexToGet" `object` ObjectToGet("1", "toto")
)
}

taskShouldBeCreatedAndWaitForIt(client, create, "indexToGet")

val request: Future[Get] = client.execute {
get from "indexToGet" objectId "1"
}

whenReady(request) { result =>
result.as[ObjectToGet] should be(ObjectToGet("1", "toto"))
}
}

it("should get multiple objects") {
val create: Future[TasksMultipleIndex] = client.execute {
batch(
index into "indexToGet" `object` ObjectToGet("1", "toto"),
index into "indexToGet" `object` ObjectToGet("2", "tata")
)
}

taskShouldBeCreatedAndWaitForIt(client, create, "indexToGet")

val request: Future[Results] = client.execute {
get from "indexToGet" objectIds Seq("1", "2")
}

whenReady(request) { results =>
results.as[ObjectToGet] should be(Seq(ObjectToGet("1", "toto"), ObjectToGet("2", "tata")))
}
}


}


case class ObjectToGet(objectID: String, name: String)

0 comments on commit c73f90f

Please sign in to comment.