TeaQL Quick Guide(Query)
This guide introduces the TeaQL generated query library, focusing on the two core expression families: Q and E.
1. Overview
After TeaQL generates the client library, developers can use:
- Q: Query expressions for data access
- E: NULL-safe chained expressions for safe navigation and evaluation
These APIs are designed to be:
- Strongly typed
- Fluent and readable
- Safe for complex domain models
2. Q Expressions (Query API)
2.1 Basic Query Structure
Q.<pluralObjectName>
.<select | filter | aggregate | order | pagination>
.comment("What this query loads")
.purpose("Why this data is needed")
.executeForList(userContext)
Return a single object:
Q.<pluralObjectName>
.<select | filter | aggregate | order | pagination>
.comment("What this query loads")
.purpose("Why this data is needed")
.executeForOne(userContext)
executeForList(...)→ returns multiple resultsexecuteForOne(...)→ returns a single resultexecuteForStream(...)→ returns a stream for large result sets
purpose(...) is the terminal builder method. Put all select, filter,
aggregation, ordering, and pagination calls before .comment(...).purpose(...).
3. Selection (Select)
3.1 Default Selection
Q.users()
.comment("Query users")
.purpose("Load data")
.executeForList(userContext);
- Selects all fields by default
3.2 Minimal Fields
Q.usersWithMinimalFields()
.comment("Query users")
.purpose("Load user ids and versions")
.executeForList(userContext);
- Selects only
idandversion
3.3 Select Variants
| Method | Description |
|---|---|
selectSelf() | Select only the object itself, no expanded references |
selectAll() | Select all scalar fields (no lists) |
selectAny() | Select all fields including lists |
select<Field>() | Select a single field |
select<List>() | Select a list field |
Examples
Q.users()
.selectName()
.comment("Query users")
.purpose("Load display names")
.executeForList(userContext);
Select a related object with custom fields:
Q.orders().selectUser(
Q.usersWithIdField().selectName()
)
.comment("Query orders")
.purpose("Load orders with user names")
.executeForList(userContext);
Filter list fields during selection:
Q.users()
.selectOrderList(Q.orders().withAmountGreaterThan(100))
.comment("Query users")
.purpose("Load users with high-value orders")
.executeForList(userContext);
3.4 Unselect (Exclude Fields)
Exclude specific fields from the selection:
Q.articles()
.unselectContent()
.comment("Query articles")
.purpose("List articles without loading large content")
.executeForList(userContext);
Useful for excluding large text or blob fields.
4. Filtering
4.1 Exact Filtering (filterBy)
Q.users()
.filterByStatus("ACTIVE")
.comment("Query users")
.purpose("Load active users")
.executeForList(userContext);
Filter by object reference:
Q.orders()
.filterByUser(Q.users().withUserGenderIsFemale())
.comment("Query orders")
.purpose("Load orders for female users")
.executeForList(userContext);
4.2 Conditional Filtering (which)
Generated based on field type:
Q.users()
.withNameIsNull()
.comment("Query users")
.purpose("Find users missing names")
.executeForList(userContext);
Q.users()
.withAgeGreaterThan(18)
.comment("Query users")
.purpose("Find adult users")
.executeForList(userContext);
Generic operator form:
Q.users()
.withName(Operator.contains, "admin")
.comment("Query users")
.purpose("Find admin-like users")
.executeForList(userContext);
4.3 List Existence (has<List>)
Q.users()
.hasOrders()
.comment("Query users")
.purpose("Find users with orders")
.executeForList(userContext);
Find users who have at least one order.
5. Aggregation & Statistics
5.1 Count
Q.orders()
.count()
.comment("Query orders")
.purpose("Count orders")
.aggregation(userContext);
Conditional count with alias:
Q.orders().count(
"shippedCount",
Q.orders().withStatusAreShipped()
)
.comment("Query orders")
.purpose("Count shipped orders")
.aggregation(userContext);
5.2 Other Aggregates
Supported functions:
summaxminavg
Example:
Q.orders()
.sumTotalAmount()
.comment("Query orders")
.purpose("Calculate total order amount")
.aggregation(userContext);
5.3 Group By
Q.orders()
.count()
.groupByOrderStatus()
.comment("Query orders")
.purpose("Count orders by status")
.aggregation(userContext);
6. Sorting
Sorting methods are generated per field.
Q.orders()
.orderByCreateTimeAscending()
.comment("Query orders")
.purpose("Load orders by creation time")
.executeForList(userContext);
Locale-aware sorting:
Q.users()
.orderByNameAscendingUsingGBK()
.comment("Query users")
.purpose("Load users ordered by localized name")
.executeForList(userContext);
7. Pagination
7.1 Top N
Q.orders()
.top(10)
.comment("Query orders")
.purpose("Load latest orders")
.executeForList(userContext);
7.2 Offset
Q.orders()
.offset(20, 10)
.comment("Query orders")
.purpose("Load a result window")
.executeForList(userContext);
- Start from index 20
- Fetch 10 records
- Index starts from 0
7.3 Page
Q.orders()
.page(2, 20)
.comment("Query orders")
.purpose("Load page two of orders")
.executeForList(userContext);
- Page number starts from 1
- 20 records per page
8. E Expressions (NULL-Safe Chain API)
E provides safe navigation for deep object graphs without explicit null checks.
8.1 Safe Null Checking
CustomOrderItem item = null;
if (
E.customerOrderItem(item)
.getCustomOrder()
.getCustomer()
.getContactName()
.isNull()
) {
// your logic
}
8.2 Safe Value Evaluation
String name =
E.customerOrderItem(item)
.getCustomOrder()
.getCustomer()
.getContactName()
.eval();
- Returns
nullsafely if any link in the chain is null
8.3 Safe Lambda Execution
Execute logic only when value is empty:
E.customOrderItem(item)
.getCustomOrder()
.getCustomer()
.getContactName()
.whenIsEmpty(() -> {
// do something
});
Enum-specific helpers:
E.user(user)
.getGender()
.whenUserGenderIsFemale(() -> {
// do something
});
9. Summary
- Q: expressive, composable, type-safe query DSL
- E: NULL-safe navigation and conditional execution
- Designed to work seamlessly with KSML domain models
- Ideal for complex enterprise systems with deep object graphs