21
21
import java .util .Arrays ;
22
22
import java .util .Optional ;
23
23
24
+ import org .bson .BsonTimestamp ;
24
25
import org .bson .BsonValue ;
25
26
import org .bson .Document ;
26
27
import org .springframework .data .mongodb .core .aggregation .Aggregation ;
27
28
import org .springframework .data .mongodb .core .query .Collation ;
28
29
import org .springframework .lang .Nullable ;
29
30
import org .springframework .util .Assert ;
31
+ import org .springframework .util .ClassUtils ;
32
+ import org .springframework .util .ObjectUtils ;
30
33
31
34
import com .mongodb .client .model .changestream .ChangeStreamDocument ;
32
35
import com .mongodb .client .model .changestream .FullDocument ;
@@ -47,7 +50,7 @@ public class ChangeStreamOptions {
47
50
private @ Nullable BsonValue resumeToken ;
48
51
private @ Nullable FullDocument fullDocumentLookup ;
49
52
private @ Nullable Collation collation ;
50
- private @ Nullable Instant resumeTimestamp ;
53
+ private @ Nullable Object resumeTimestamp ;
51
54
52
55
protected ChangeStreamOptions () {}
53
56
@@ -83,7 +86,15 @@ public Optional<Collation> getCollation() {
83
86
* @return {@link Optional#empty()} if not set.
84
87
*/
85
88
public Optional <Instant > getResumeTimestamp () {
86
- return Optional .ofNullable (resumeTimestamp );
89
+ return Optional .ofNullable (resumeTimestamp ).map (this ::asInstant );
90
+ }
91
+
92
+ /**
93
+ * @return {@link Optional#empty()} if not set.
94
+ * @since 2.2
95
+ */
96
+ public Optional <BsonTimestamp > getResumeBsonTimestamp () {
97
+ return Optional .ofNullable (resumeTimestamp ).map (this ::asBsonTimestamp );
87
98
}
88
99
89
100
/**
@@ -103,6 +114,33 @@ public static ChangeStreamOptionsBuilder builder() {
103
114
return new ChangeStreamOptionsBuilder ();
104
115
}
105
116
117
+ private Instant asInstant (Object timestamp ) {
118
+ return asTimestampOfType (timestamp , Instant .class );
119
+ }
120
+
121
+ private BsonTimestamp asBsonTimestamp (Object timestamp ) {
122
+ return asTimestampOfType (timestamp , BsonTimestamp .class );
123
+ }
124
+
125
+ private <T > T asTimestampOfType (Object timestamp , Class <T > targetType ) {
126
+
127
+ if (ClassUtils .isAssignableValue (targetType , timestamp )) {
128
+ return (T ) timestamp ;
129
+ }
130
+
131
+ if (timestamp instanceof Instant ) {
132
+ return (T ) new BsonTimestamp ((int ) ((Instant ) timestamp ).getEpochSecond (), 0 );
133
+ }
134
+
135
+ if (timestamp instanceof BsonTimestamp ) {
136
+ return (T ) Instant .ofEpochSecond (((BsonTimestamp ) timestamp ).getTime ());
137
+ }
138
+
139
+ throw new IllegalArgumentException (
140
+ "o_O that should actually not happen. The timestampt should be an Instant or a BsonTimestamp but was "
141
+ + ObjectUtils .nullSafeClassName (timestamp ));
142
+ }
143
+
106
144
/**
107
145
* Builder for creating {@link ChangeStreamOptions}.
108
146
*
@@ -115,7 +153,7 @@ public static class ChangeStreamOptionsBuilder {
115
153
private @ Nullable BsonValue resumeToken ;
116
154
private @ Nullable FullDocument fullDocumentLookup ;
117
155
private @ Nullable Collation collation ;
118
- private @ Nullable Instant resumeTimestamp ;
156
+ private @ Nullable Object resumeTimestamp ;
119
157
120
158
private ChangeStreamOptionsBuilder () {}
121
159
@@ -224,6 +262,21 @@ public ChangeStreamOptionsBuilder resumeAt(Instant resumeTimestamp) {
224
262
return this ;
225
263
}
226
264
265
+ /**
266
+ * Set the cluster time to resume from.
267
+ *
268
+ * @param resumeTimestamp must not be {@literal null}.
269
+ * @return this.
270
+ * @since 2.2
271
+ */
272
+ public ChangeStreamOptionsBuilder resumeAt (BsonTimestamp resumeTimestamp ) {
273
+
274
+ Assert .notNull (resumeTimestamp , "ResumeTimestamp must not be null!" );
275
+
276
+ this .resumeTimestamp = resumeTimestamp ;
277
+ return this ;
278
+ }
279
+
227
280
/**
228
281
* @return the built {@link ChangeStreamOptions}
229
282
*/
0 commit comments