Repository navigation
Expand file tree
/
Copy pathMessagesQuery.java
More file actions
160 lines (139 loc) · 5.49 KB
/
Copy pathMessagesQuery.java
File metadata and controls
160 lines (139 loc) · 5.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package dev.getchat.sdk;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
/**
* Typed filters and pagination for {@link GetChatClient#listMessages(String, MessagesQuery)}.
*
* <p>The typed input to {@code listMessages}: {@link #asMap()} produces exactly
* the keys the endpoint reads ({@code extra}, {@code isDeleted}, {@code isEdited},
* {@code with_users}) plus {@code page} and {@code limit}. Only the fields you set
* appear — an unset boolean is left off entirely, which the backend reads as
* "don't filter on this", and an unset {@code page}/{@code limit} falls back to
* the method default (page 1, 50 per page).
*
* <p>The typed form removes two footguns: the camelCase/underscore confusion
* between {@code with_users} and {@code withUsers}, and untyped flag values. For
* a key without a typed setter, use {@link Builder#set(String, Object)}.
*/
public final class MessagesQuery {
private final Map<String, Object> data;
private MessagesQuery(Map<String, Object> data) {
this.data = data;
}
public static Builder builder() {
return new Builder();
}
/**
* The filters as the {@code Map} {@code listMessages} consumes. Keys present
* only for fields that were set; unset booleans and unset {@code page}/{@code
* limit} are omitted.
*/
public Map<String, Object> asMap() {
return Collections.unmodifiableMap(data);
}
/** Equal to another {@code MessagesQuery} producing the same map. */
@Override
public boolean equals(@Nullable Object o) {
return this == o || (o instanceof MessagesQuery q && data.equals(q.data));
}
@Override
public int hashCode() {
return data.hashCode();
}
/** Compact dump for logs, e.g. {@code MessagesQuery{isDeleted=false}}. */
@Override
public String toString() {
return "MessagesQuery" + data;
}
/** Builder for {@link MessagesQuery}. */
public static final class Builder {
private final Map<String, Object> extra = new LinkedHashMap<>();
private final Map<String, Object> raw = new LinkedHashMap<>();
private @Nullable Integer page;
private @Nullable Integer limit;
private @Nullable Boolean deleted;
private @Nullable Boolean edited;
private @Nullable Boolean withUsers;
private Builder() {}
/** Page number; must be at least 1, checked at {@link #build()}. Unset defaults to 1. */
public Builder page(int page) {
this.page = page;
return this;
}
/** Items per page; must be in {@code 1..1000}, checked at {@link #build()}. Unset defaults to 50. */
public Builder limit(int limit) {
this.limit = limit;
return this;
}
/**
* Filter by {@code extra} fields (scalar values). Replaces any extra
* entries accumulated so far; non-scalar values are dropped downstream.
*/
public Builder extra(@Nullable Map<String, Object> extra) {
this.extra.clear();
if (extra != null) {
this.extra.putAll(extra);
}
return this;
}
/** Add a single {@code extra} filter entry. */
public Builder extra(String key, @Nullable Object value) {
this.extra.put(key, value);
return this;
}
/** {@code true} — only deleted messages; {@code false} — only live ones. */
public Builder deleted(boolean deleted) {
this.deleted = deleted;
return this;
}
/** {@code true} — only edited messages; {@code false} — only never-edited ones. */
public Builder edited(boolean edited) {
this.edited = edited;
return this;
}
/** Include the {@code users} map alongside the messages. */
public Builder withUsers(boolean withUsers) {
this.withUsers = withUsers;
return this;
}
/** Escape hatch for a query key with no typed setter. */
public Builder set(String key, @Nullable Object value) {
this.raw.put(key, value);
return this;
}
public MessagesQuery build() {
// Validate the typed page/limit; the raw set() channel stays unchecked
// (the escape hatch), and GetChatClient clamps as a second defence.
if (page != null && page < 1) {
throw new GetChatException("page must be at least 1");
}
if (limit != null && (limit < 1 || limit > 1000)) {
throw new GetChatException("limit must be between 1 and 1000");
}
Map<String, Object> data = new LinkedHashMap<>();
if (page != null) {
data.put("page", page);
}
if (limit != null) {
data.put("limit", limit);
}
if (!extra.isEmpty()) {
data.put("extra", new LinkedHashMap<>(extra));
}
if (deleted != null) {
data.put("isDeleted", deleted);
}
if (edited != null) {
data.put("isEdited", edited);
}
if (withUsers != null) {
data.put("with_users", withUsers);
}
// The escape hatch is applied last so it can override a typed field.
data.putAll(raw);
return new MessagesQuery(data);
}
}
}