Skip to content

Commit a7d437e

Browse files
committed
feat(response): add typed getFetched() for related entities
- getFetched(Class) returns List<T> of fetched related entities - getFetchedByKey(Class, key) returns single entity by key - Type-safe access to fetchedResults using @SbxModel annotation
1 parent 03a939b commit a7d437e

3 files changed

Lines changed: 85 additions & 4 deletions

File tree

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Java 21+ client for SBX Cloud APIs. Spring Boot 3.x compatible.
1717
<dependency>
1818
<groupId>com.github.socobox</groupId>
1919
<artifactId>sbxcloud-lib-java</artifactId>
20-
<version>v0.0.14</version>
20+
<version>v0.0.15</version>
2121
</dependency>
2222
```
2323

@@ -29,7 +29,7 @@ repositories {
2929
}
3030
3131
dependencies {
32-
implementation 'com.github.socobox:sbxcloud-lib-java:v0.0.14'
32+
implementation 'com.github.socobox:sbxcloud-lib-java:v0.0.15'
3333
}
3434
```
3535

@@ -146,6 +146,13 @@ repo.query().where(...).count() // long
146146
repo.query().where(...).exists() // boolean
147147
repo.query().where(...).execute() // SBXFindResponse<T>
148148

149+
// Fetching related entities (type-safe!)
150+
var response = repo.query()
151+
.fetch("account", "department")
152+
.execute();
153+
List<Account> accounts = response.getFetched(Account.class);
154+
Account acc = response.getFetchedByKey(Account.class, contact.account());
155+
149156
// Shortcuts
150157
repo.findWhere(q -> q.andWhereIsEqualTo("status", "ACTIVE"))
151158
repo.query().whereEquals("status", "ACTIVE").first()

src/main/java/com/sbxcloud/sbx/model/SBXFindResponse.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.sbxcloud.sbx.annotation.SbxModels;
6+
import com.sbxcloud.sbx.util.Sbx;
57

8+
import java.util.ArrayList;
69
import java.util.List;
710
import java.util.Map;
811

@@ -49,4 +52,74 @@ public String getErrorMessage() {
4952
public boolean hasMorePages(int currentPage) {
5053
return totalPages != null && currentPage < totalPages;
5154
}
55+
56+
/**
57+
* Gets fetched related entities as a typed list.
58+
* <p>
59+
* When using fetchModels() in your query, related entities are returned
60+
* in fetchedResults. This method converts them to typed objects.
61+
*
62+
* <pre>{@code
63+
* var query = FindQuery.from(CartBox.class)
64+
* .fetchModels("purchase")
65+
* .andWhereIsNotNull("purchase");
66+
*
67+
* var response = sbx.find(query);
68+
* List<CartBox> boxes = response.results();
69+
* List<Purchase> purchases = response.getFetched(Purchase.class);
70+
* }</pre>
71+
*
72+
* @param type class annotated with @SbxModel
73+
* @return list of typed entities, or empty list if none found
74+
*/
75+
public <F> List<F> getFetched(Class<F> type) {
76+
if (fetchedResults == null) {
77+
return List.of();
78+
}
79+
80+
String modelName = SbxModels.getModelName(type);
81+
Map<String, Object> modelData = fetchedResults.get(modelName);
82+
83+
if (modelData == null || modelData.isEmpty()) {
84+
return List.of();
85+
}
86+
87+
List<F> result = new ArrayList<>();
88+
for (Object value : modelData.values()) {
89+
result.add(Sbx.mapper().convertValue(value, type));
90+
}
91+
return result;
92+
}
93+
94+
/**
95+
* Gets a single fetched entity by its key.
96+
*
97+
* <pre>{@code
98+
* var box = response.results().get(0);
99+
* Purchase purchase = response.getFetchedByKey(Purchase.class, box.purchase());
100+
* }</pre>
101+
*
102+
* @param type class annotated with @SbxModel
103+
* @param key the entity key
104+
* @return the typed entity, or null if not found
105+
*/
106+
public <F> F getFetchedByKey(Class<F> type, String key) {
107+
if (fetchedResults == null || key == null) {
108+
return null;
109+
}
110+
111+
String modelName = SbxModels.getModelName(type);
112+
Map<String, Object> modelData = fetchedResults.get(modelName);
113+
114+
if (modelData == null) {
115+
return null;
116+
}
117+
118+
Object value = modelData.get(key);
119+
if (value == null) {
120+
return null;
121+
}
122+
123+
return Sbx.mapper().convertValue(value, type);
124+
}
52125
}

src/test/java/com/sbxcloud/sbx/SBXIntegrationTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,14 @@ void testFindAll() {
188188
@Order(10)
189189
void testFindWithAnnotatedClass() {
190190
// Uses @SbxModel annotation to infer model name
191+
// Type is inferred - no need to pass class twice!
191192
var query = FindQuery.from(InventoryHistory.class)
192193
.setPageSize(5);
193194

194-
var response = sbx.find(query, InventoryHistory.class);
195+
var response = sbx.find(query); // Type inferred from query
195196

196197
assertTrue(response.success(), "Find with annotated class should succeed: " + response.error());
197-
System.out.println("Found " + (response.results() != null ? response.results().size() : 0) + " records using @SbxModel");
198+
System.out.println("Found " + (response.results() != null ? response.results().size() : 0) + " records using typed FindQuery");
198199
}
199200

200201
@Test

0 commit comments

Comments
 (0)