Skip to content

Commit 2be3bab

Browse files
committed
WIP
1 parent b56210e commit 2be3bab

File tree

3 files changed

+62
-10
lines changed

3 files changed

+62
-10
lines changed

document-store/src/integrationTest/java/org/hypertrace/core/documentstore/MongoPostgresWriteConsistencyTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,52 @@ void testSetNestedJsonbArray(String storeName) throws Exception {
533533
// Other sales fields preserved
534534
assertEquals(200, resultJson.get("sales").get("total").asInt());
535535
}
536+
537+
@ParameterizedTest(name = "{0}: SET entire JSONB column")
538+
@ArgumentsSource(AllStoresProvider.class)
539+
void testSetEntireJsonbColumn(String storeName) throws Exception {
540+
String docId = generateDocId("set-jsonb-column");
541+
insertTestDocument(docId);
542+
543+
Collection collection = getCollection(storeName);
544+
Query query = buildQueryById(docId);
545+
546+
// Create a completely new object to replace the entire JSONB column
547+
ObjectNode newProps = OBJECT_MAPPER.createObjectNode();
548+
newProps.put("manufacturer", "NewManufacturer");
549+
newProps.put("model", "Model-X");
550+
newProps.put("year", 2024);
551+
newProps.putArray("features").add("feature1").add("feature2");
552+
553+
List<SubDocumentUpdate> updates =
554+
List.of(
555+
SubDocumentUpdate.of("props", SubDocumentValue.of(new JSONDocument(newProps))));
556+
557+
UpdateOptions options =
558+
UpdateOptions.builder().returnDocumentType(ReturnDocumentType.AFTER_UPDATE).build();
559+
560+
Optional<Document> result = collection.update(query, updates, options);
561+
562+
assertTrue(result.isPresent());
563+
JsonNode resultJson = OBJECT_MAPPER.readTree(result.get().toJson());
564+
JsonNode propsNode = resultJson.get("props");
565+
assertNotNull(propsNode);
566+
567+
// Verify new fields are present
568+
assertEquals("NewManufacturer", propsNode.get("manufacturer").asText());
569+
assertEquals("Model-X", propsNode.get("model").asText());
570+
assertEquals(2024, propsNode.get("year").asInt());
571+
assertTrue(propsNode.get("features").isArray());
572+
assertEquals(2, propsNode.get("features").size());
573+
assertEquals("feature1", propsNode.get("features").get(0).asText());
574+
assertEquals("feature2", propsNode.get("features").get(1).asText());
575+
576+
// Verify old fields are NOT present (entire column replaced)
577+
assertFalse(propsNode.has("brand"));
578+
assertFalse(propsNode.has("size"));
579+
assertFalse(propsNode.has("count"));
580+
assertFalse(propsNode.has("colors"));
581+
}
536582
}
537583

538584
@Nested

document-store/src/main/java/org/hypertrace/core/documentstore/postgres/PostgresCollection.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,10 +1466,8 @@ private void addColumnToJsonNode(
14661466
if (jsonString != null) {
14671467
try {
14681468
JsonNode jsonValue = MAPPER.readTree(jsonString);
1469-
// For FLAT documents, column names with dots are actual column names, not encoded
1470-
// nested paths. Only apply nesting logic for non-FLAT document types.
1471-
if (documentType != DocumentType.FLAT
1472-
&& PostgresUtils.isEncodedNestedField(columnName)) {
1469+
// Handle like MetaData iterator - check for encoded nested fields
1470+
if (PostgresUtils.isEncodedNestedField(columnName)) {
14731471
handleNestedField(
14741472
PostgresUtils.decodeAliasForNestedField(columnName), jsonNode, jsonValue);
14751473
} else {

document-store/src/main/java/org/hypertrace/core/documentstore/postgres/update/parser/PostgresSetValueParser.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.hypertrace.core.documentstore.model.subdoc.SubDocumentUpdate;
99
import org.hypertrace.core.documentstore.postgres.Params;
1010
import org.hypertrace.core.documentstore.postgres.Params.Builder;
11+
import org.hypertrace.core.documentstore.postgres.query.v1.parser.filter.nonjson.field.PostgresDataType;
1112
import org.hypertrace.core.documentstore.postgres.subdoc.PostgresSubDocumentArrayGetter;
1213
import org.hypertrace.core.documentstore.postgres.subdoc.PostgresSubDocumentValueParser;
1314

@@ -33,14 +34,21 @@ public String parseNonJsonbField(final UpdateParserInput input) {
3334
.accept(new PostgresSubDocumentArrayGetter())
3435
.values();
3536
input.getParamsBuilder().addObjectParam(values);
37+
return String.format("\"%s\" = ?", input.getBaseField());
3638
} else {
37-
// For scalar columns, use standard value parser (ignore returned JSONB expression)
38-
input
39-
.getUpdate()
40-
.getSubDocumentValue()
41-
.accept(new PostgresSubDocumentValueParser(input.getParamsBuilder()));
39+
// For scalar columns, use value parser which returns proper expression with type cast
40+
String valueExpr =
41+
input
42+
.getUpdate()
43+
.getSubDocumentValue()
44+
.accept(new PostgresSubDocumentValueParser(input.getParamsBuilder()));
45+
// For JSONB columns, use the returned expression (e.g., "?::jsonb" for nested documents)
46+
// For other columns, use plain "?"
47+
if (input.getColumnType() == PostgresDataType.JSONB) {
48+
return String.format("\"%s\" = %s", input.getBaseField(), valueExpr);
49+
}
50+
return String.format("\"%s\" = ?", input.getBaseField());
4251
}
43-
return String.format("\"%s\" = ?", input.getBaseField());
4452
}
4553

4654
@Override

0 commit comments

Comments
 (0)