|
1 | 1 | package com.example.query; |
2 | 2 |
|
| 3 | +import io.questdb.client.Query; |
| 4 | +import io.questdb.client.QueryException; |
| 5 | +import io.questdb.client.QuestDB; |
3 | 6 | import io.questdb.client.cutlass.qwp.client.QwpColumnBatch; |
4 | 7 | import io.questdb.client.cutlass.qwp.client.QwpColumnBatchHandler; |
5 | | -import io.questdb.client.cutlass.qwp.client.QwpQueryClient; |
6 | 8 |
|
7 | 9 | /** |
8 | 10 | * Minimal QWP egress query example. |
9 | 11 | * <p> |
10 | | - * Connects to a QuestDB server over the /read/v1 WebSocket endpoint, |
11 | | - * runs a SELECT query, and prints each row as the batches arrive. |
| 12 | + * Opens a pooled {@link QuestDB} handle over QWP (WebSocket), borrows a |
| 13 | + * {@link Query} to run a SELECT, and prints each row as the batches |
| 14 | + * arrive. {@code Completion.await()} blocks until the query finishes and |
| 15 | + * rethrows any server error as a {@link QueryException}. |
12 | 16 | * <p> |
13 | 17 | * Iterates rows via {@link QwpColumnBatch#forEachRow}, which hands a reusable |
14 | 18 | * row-pinned view to the lambda. Single-arg accessors keep the read path |
15 | 19 | * compact; the underlying batch is still column-major and the {@code (col, row)} |
16 | 20 | * primitives remain available on {@code batch} for callers that prefer them. |
17 | 21 | * <p> |
18 | | - * Assumes a table exists: |
| 22 | + * Queries the {@code trades} table the ingest examples |
| 23 | + * ({@code com.example.sender.WsExample}, {@code com.example.QuestDBExample}) |
| 24 | + * write -- auto-created on first ingest as: |
19 | 25 | * <pre> |
20 | | - * CREATE TABLE trades (ts TIMESTAMP, sym SYMBOL, price DOUBLE, qty LONG) |
21 | | - * TIMESTAMP(ts) PARTITION BY DAY WAL; |
| 26 | + * CREATE TABLE trades ( |
| 27 | + * symbol SYMBOL, side SYMBOL, price DOUBLE, amount DOUBLE, timestamp TIMESTAMP |
| 28 | + * ) TIMESTAMP(timestamp) PARTITION BY DAY WAL; |
22 | 29 | * </pre> |
23 | 30 | */ |
24 | 31 | public class BasicQueryExample { |
25 | 32 |
|
26 | | - public static void main(String[] args) { |
27 | | - try (QwpQueryClient client = QwpQueryClient.newPlainText("localhost", 9000)) { |
28 | | - client.connect(); |
| 33 | + public static void main(String[] args) throws InterruptedException { |
| 34 | + try (QuestDB db = QuestDB.connect("ws::addr=localhost:9000;")) { |
| 35 | + try (Query q = db.borrowQuery()) { |
| 36 | + q.sql( |
| 37 | + "SELECT timestamp, symbol, side, price, amount FROM trades WHERE symbol = 'ETH-USD' LIMIT 1000") |
| 38 | + .handler(new QwpColumnBatchHandler() { |
| 39 | + @Override |
| 40 | + public void onBatch(QwpColumnBatch batch) { |
| 41 | + // The RowView handed to the lambda is reusable and pinned to the |
| 42 | + // current row; copy values out before the callback returns if you |
| 43 | + // need to retain them past the surrounding onBatch call. |
| 44 | + batch.forEachRow(row -> { |
| 45 | + long timestamp = row.getLongValue(0); // TIMESTAMP -> microseconds since epoch |
| 46 | + String symbol = row.getSymbol(1); // SYMBOL -> String |
| 47 | + String side = row.getSymbol(2); // SYMBOL -> String |
| 48 | + double price = row.getDoubleValue(3); // DOUBLE |
| 49 | + double amount = row.getDoubleValue(4); // DOUBLE |
29 | 50 |
|
30 | | - client.execute( |
31 | | - "SELECT ts, sym, price, qty FROM trades WHERE sym = 'AAPL' LIMIT 1000", |
32 | | - new QwpColumnBatchHandler() { |
33 | | - @Override |
34 | | - public void onBatch(QwpColumnBatch batch) { |
35 | | - // The RowView handed to the lambda is reusable and pinned to the |
36 | | - // current row; copy values out before the callback returns if you |
37 | | - // need to retain them past the surrounding onBatch call. |
38 | | - batch.forEachRow(row -> { |
39 | | - long timestamp = row.getLongValue(0); // TIMESTAMP -> microseconds since epoch |
40 | | - String symbol = row.getSymbol(1); // SYMBOL -> String |
41 | | - double price = row.getDoubleValue(2); // DOUBLE |
42 | | - long qty = row.getLongValue(3); // LONG |
| 51 | + System.out.printf( |
| 52 | + "timestamp=%d symbol=%s side=%s price=%.4f amount=%.5f%n", |
| 53 | + timestamp, symbol, side, price, amount |
| 54 | + ); |
| 55 | + }); |
| 56 | + } |
43 | 57 |
|
44 | | - System.out.printf( |
45 | | - "ts=%d sym=%s price=%.4f qty=%d%n", |
46 | | - timestamp, symbol, price, qty |
47 | | - ); |
48 | | - }); |
49 | | - } |
50 | | - |
51 | | - @Override |
52 | | - public void onEnd(long totalRows) { |
53 | | - System.out.println("query finished"); |
54 | | - } |
| 58 | + @Override |
| 59 | + public void onEnd(long totalRows) { |
| 60 | + System.out.println("query finished"); |
| 61 | + } |
55 | 62 |
|
56 | | - @Override |
57 | | - public void onError(byte status, String message) { |
58 | | - System.err.println("query failed: status=" + status + " msg=" + message); |
| 63 | + @Override |
| 64 | + public void onError(byte status, String message) { |
| 65 | + } |
59 | 66 | } |
60 | | - } |
61 | | - ); |
| 67 | + ).submit().await(); |
| 68 | + } catch (QueryException e) { |
| 69 | + System.err.printf("query failed: status=0x%02X %s%n", e.getStatus() & 0xFF, e.getMessage()); |
| 70 | + } |
62 | 71 | } |
63 | 72 | } |
64 | 73 | } |
0 commit comments