|
45 | 45 | import org.testng.annotations.Factory; |
46 | 46 | import org.testng.annotations.Test; |
47 | 47 |
|
| 48 | +import java.time.Instant; |
48 | 49 | import java.util.ArrayList; |
49 | 50 | import java.util.Arrays; |
50 | 51 | import java.util.HashMap; |
@@ -923,6 +924,62 @@ public void queryWithSqlParameterAndCustomSerializer() { |
923 | 924 | } |
924 | 925 | } |
925 | 926 |
|
| 927 | + @Test(groups = { "fast", "emulator" }, timeOut = TIMEOUT * 1000000) |
| 928 | + public void queryWithSqlParameterDateTimeAndCustomSerializer() { |
| 929 | + CosmosItemSerializer clientSerializer = this.getClientBuilder().getCustomItemSerializer(); |
| 930 | + if (clientSerializer == null || clientSerializer == CosmosItemSerializer.DEFAULT_SERIALIZER) { |
| 931 | + return; |
| 932 | + } |
| 933 | + |
| 934 | + boolean isEnvelopeWrapper = clientSerializer instanceof EnvelopWrappingItemSerializer; |
| 935 | + if (isEnvelopeWrapper) { |
| 936 | + return; |
| 937 | + } |
| 938 | + |
| 939 | + // This test validates that when a custom serializer changes how values are |
| 940 | + // stored (e.g. Instant as ISO-8601 string instead of a timestamp number), |
| 941 | + // SqlParameter correctly applies the same serializer so that query filters |
| 942 | + // match the stored representation. |
| 943 | + String id = UUID.randomUUID().toString(); |
| 944 | + String pkValue = id; |
| 945 | + Instant createdAt = Instant.parse("2026-03-15T10:30:00Z"); |
| 946 | + TestDocumentWithTimestamp doc = new TestDocumentWithTimestamp(); |
| 947 | + doc.id = id; |
| 948 | + doc.mypk = pkValue; |
| 949 | + doc.createdAt = createdAt; |
| 950 | + doc.description = "test-datetime-serialization"; |
| 951 | + |
| 952 | + try { |
| 953 | + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions() |
| 954 | + .setCustomItemSerializer(clientSerializer); |
| 955 | + container.createItem(doc, new PartitionKey(pkValue), requestOptions); |
| 956 | + |
| 957 | + CosmosQueryRequestOptions queryRequestOptions = new CosmosQueryRequestOptions() |
| 958 | + .setCustomItemSerializer(clientSerializer); |
| 959 | + |
| 960 | + // Query using SqlParameter with the same Instant value — the custom serializer |
| 961 | + // must serialize the parameter the same way as the document field. |
| 962 | + SqlQuerySpec querySpec = new SqlQuerySpec( |
| 963 | + "SELECT * FROM c WHERE c.createdAt = @createdAt AND c.id = @id", |
| 964 | + new SqlParameter("@createdAt", createdAt), |
| 965 | + new SqlParameter("@id", id)); |
| 966 | + |
| 967 | + List<TestDocumentWithTimestamp> results = container |
| 968 | + .queryItems(querySpec, queryRequestOptions, TestDocumentWithTimestamp.class) |
| 969 | + .stream().collect(Collectors.toList()); |
| 970 | + |
| 971 | + assertThat(results).isNotNull(); |
| 972 | + assertThat(results).hasSize(1); |
| 973 | + assertThat(results.get(0).id).isEqualTo(id); |
| 974 | + assertThat(results.get(0).createdAt).isEqualTo(createdAt); |
| 975 | + assertThat(results.get(0).description).isEqualTo("test-datetime-serialization"); |
| 976 | + } finally { |
| 977 | + try { |
| 978 | + container.deleteItem(id, new PartitionKey(pkValue), new CosmosItemRequestOptions()); |
| 979 | + } catch (Exception ignored) { } |
| 980 | + } |
| 981 | + } |
| 982 | + |
926 | 983 | private <T> void runBatchAndChangeFeedTestCase( |
927 | 984 | Function<String, T> docGenerator, |
928 | 985 | CosmosItemSerializer requestLevelSerializer, |
@@ -1153,6 +1210,13 @@ private static class TestDocumentWithNullableField { |
1153 | 1210 | public String nullableField; |
1154 | 1211 | } |
1155 | 1212 |
|
| 1213 | + private static class TestDocumentWithTimestamp { |
| 1214 | + public String id; |
| 1215 | + public String mypk; |
| 1216 | + public Instant createdAt; |
| 1217 | + public String description; |
| 1218 | + } |
| 1219 | + |
1156 | 1220 | private static class TestDocumentWrappedInEnvelope { |
1157 | 1221 | public String id; |
1158 | 1222 |
|
|
0 commit comments