Skip to content

Commit be352d9

Browse files
committed
add support for nested object within query validator
1 parent 92e419c commit be352d9

File tree

3 files changed

+302
-276
lines changed

3 files changed

+302
-276
lines changed

core/src/test/scala/app/softnetwork/elastic/client/ElasticConversionSpec.scala

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package app.softnetwork.elastic.client
22

3-
import app.softnetwork.elastic.sql.Identifier
4-
import app.softnetwork.elastic.sql.function.aggregate.ArrayAgg
5-
import app.softnetwork.elastic.sql.query.{OrderBy, SQLAggregation}
63
import org.json4s.ext.{JavaTimeSerializers, JavaTypesSerializers, JodaTimeSerializers}
74
import org.json4s.jackson.Serialization
85
import org.json4s.{Formats, NoTypeHints}
@@ -63,6 +60,50 @@ class ElasticConversionSpec extends AnyFlatSpec with Matchers with ElasticConver
6360
throw error
6461
}
6562
}
63+
it should "parse hits with field object" in {
64+
val results =
65+
"""{
66+
| "took": 8,
67+
| "hits": {
68+
| "total": { "value": 1, "relation": "eq" },
69+
| "max_score": 1.0,
70+
| "hits": [
71+
| {
72+
| "_index": "users",
73+
| "_id": "u1",
74+
| "_score": 1.0,
75+
| "_source": {
76+
| "id": "u1",
77+
| "name": "Alice",
78+
| "address": {
79+
| "street": "123 Main St",
80+
| "city": "Wonderland",
81+
| "country": "Fictionland"
82+
| }
83+
| }
84+
| }
85+
| ]
86+
| }
87+
|}""".stripMargin
88+
parseResponse(
89+
ElasticResponse("", results, Map.empty, Map.empty)
90+
) match {
91+
case Success(rows) =>
92+
rows.foreach(println)
93+
// Map(name -> Alice, address -> Map(street -> 123 Main St, city -> Wonderland, country -> Fictionland), _id -> u1, _index -> users, _score -> 1.0)
94+
val users = rows.map(row => convertTo[User](row))
95+
users.foreach(println)
96+
// User(u1,Alice,Address(123 Main St,Wonderland,Fictionland))
97+
users.size shouldBe 1
98+
users.head.id shouldBe "u1"
99+
users.head.name shouldBe "Alice"
100+
users.head.address.street shouldBe "123 Main St"
101+
users.head.address.city shouldBe "Wonderland"
102+
users.head.address.country shouldBe "Fictionland"
103+
case Failure(error) =>
104+
throw error
105+
}
106+
}
66107
it should "parse aggregations with top hits" in {
67108
val results = """{
68109
| "took": 10,
@@ -638,3 +679,15 @@ case class SalesHistory(
638679
sales_over_time: ZonedDateTime,
639680
total_revenue: Double
640681
)
682+
683+
case class Address(
684+
street: String,
685+
city: String,
686+
country: String
687+
)
688+
689+
case class User(
690+
id: String,
691+
name: String,
692+
address: Address
693+
)

macros-tests/src/test/scala/app/softnetwork/elastic/sql/macros/SQLQueryValidatorSpec.scala

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
99
// Positive Tests (Should Compile)
1010
// ============================================================
1111

12-
"SQLQueryValidator" should "validate all numeric types" in {
12+
"SQLQueryValidator" should "VALIDATE all numeric types" in {
1313
assertCompiles("""
1414
import app.softnetwork.elastic.client.macros.TestElasticClientApi
1515
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -21,7 +21,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
2121
)""")
2222
}
2323

24-
it should "validate string types" in {
24+
it should "VALIDATE string types" in {
2525
assertCompiles("""
2626
import app.softnetwork.elastic.client.macros.TestElasticClientApi
2727
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -33,7 +33,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
3333
)""")
3434
}
3535

36-
it should "validate temporal types" in {
36+
it should "VALIDATE temporal types" in {
3737
assertCompiles("""
3838
import app.softnetwork.elastic.client.macros.TestElasticClientApi
3939
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -45,7 +45,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
4545
)""")
4646
}
4747

48-
it should "validate Product with all fields" in {
48+
it should "VALIDATE with all fields" in {
4949
assertCompiles("""
5050
import app.softnetwork.elastic.client.macros.TestElasticClientApi
5151
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -57,7 +57,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
5757
)""")
5858
}
5959

60-
it should "validate with aliases" in {
60+
it should "VALIDATE with aliases" in {
6161
assertCompiles("""
6262
import app.softnetwork.elastic.client.macros.TestElasticClientApi
6363
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -69,7 +69,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
6969
)""")
7070
}
7171

72-
it should "accept query with missing Option fields" in {
72+
it should "ACCEPT query with missing Option fields" in {
7373
assertCompiles("""
7474
import app.softnetwork.elastic.client.macros.TestElasticClientApi
7575
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -82,7 +82,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
8282
""")
8383
}
8484

85-
it should "accept query with missing fields that have defaults" in {
85+
it should "ACCEPT query with missing fields that have defaults" in {
8686
assertCompiles("""
8787
import app.softnetwork.elastic.client.macros.TestElasticClientApi
8888
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -95,7 +95,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
9595
""")
9696
}
9797

98-
it should "accept SELECT * with Unchecked variant" in {
98+
it should "ACCEPT SELECT * with Unchecked variant" in {
9999
assertCompiles("""
100100
import app.softnetwork.elastic.client.macros.TestElasticClientApi
101101
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -108,6 +108,28 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
108108
""")
109109
}
110110

111+
it should "ACCEPT nested object with complete selection" in {
112+
assertCompiles("""
113+
import app.softnetwork.elastic.client.macros.TestElasticClientApi
114+
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
115+
import app.softnetwork.elastic.sql.macros.SQLQueryValidatorSpec.{User, Address}
116+
117+
TestElasticClientApi.searchAs[User](
118+
"SELECT id, name, address FROM users"
119+
)""")
120+
}
121+
122+
it should "ACCEPT nested object with UNNEST" in {
123+
assertCompiles("""
124+
import app.softnetwork.elastic.client.macros.TestElasticClientApi
125+
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
126+
import app.softnetwork.elastic.sql.macros.SQLQueryValidatorSpec.{User, Address}
127+
128+
TestElasticClientApi.searchAs[User](
129+
"SELECT id, name, address.street, address.city, address.country FROM users JOIN UNNEST(users.address) AS address"
130+
)""")
131+
}
132+
111133
// ============================================================
112134
// Negative Tests (Should NOT Compile)
113135
// ============================================================
@@ -149,7 +171,7 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
149171
)""")
150172
}
151173

152-
it should "suggest closest field names" in {
174+
it should "SUGGEST closest field names" in {
153175
assertDoesNotCompile("""
154176
import app.softnetwork.elastic.client.macros.TestElasticClientApi
155177
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
@@ -200,6 +222,17 @@ class SQLQueryValidatorSpec extends AnyFlatSpec with Matchers {
200222
""")
201223
}
202224

225+
it should "REJECT nested object with individual field selection without UNNEST" in {
226+
assertDoesNotCompile("""
227+
import app.softnetwork.elastic.client.macros.TestElasticClientApi
228+
import app.softnetwork.elastic.client.macros.TestElasticClientApi.defaultFormats
229+
import app.softnetwork.elastic.sql.macros.SQLQueryValidatorSpec.{User, Address}
230+
231+
TestElasticClientApi.searchAs[User](
232+
"SELECT id, name, address.street, address.city, address.country FROM users"
233+
)""")
234+
}
235+
203236
}
204237

205238
object SQLQueryValidatorSpec {
@@ -249,4 +282,16 @@ object SQLQueryValidatorSpec {
249282
dt: java.time.LocalDateTime,
250283
ts: java.time.Instant
251284
)
285+
286+
case class Address(
287+
street: String,
288+
city: String,
289+
country: String
290+
)
291+
292+
case class User(
293+
id: String,
294+
name: String,
295+
address: Address
296+
)
252297
}

0 commit comments

Comments
 (0)