fix(mongodb): decode extended JSON document ids
This commit is contained in:
parent
6b98c7ebf1
commit
5a47084c7b
|
|
@ -641,12 +641,9 @@ public final class MongoAgent {
|
|||
return stringId;
|
||||
}
|
||||
String trimmed = id.trim();
|
||||
if (isNumberLongIdWrapper(trimmed)) {
|
||||
try {
|
||||
return Document.parse("{\"_id\":" + trimmed + "}").get("_id");
|
||||
} catch (Exception e) {
|
||||
// Fall through to the legacy ObjectId/string handling below.
|
||||
}
|
||||
Object extendedJsonId = parseExtendedJsonId(trimmed);
|
||||
if (extendedJsonId != null) {
|
||||
return extendedJsonId;
|
||||
}
|
||||
try {
|
||||
return new ObjectId(id);
|
||||
|
|
@ -668,20 +665,21 @@ public final class MongoAgent {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isNumberLongIdWrapper(String value) {
|
||||
private static Object parseExtendedJsonId(String value) {
|
||||
try {
|
||||
JsonElement parsed = JsonParser.parseString(value);
|
||||
if (!parsed.isJsonObject()) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
JsonObject wrapper = parsed.getAsJsonObject();
|
||||
JsonElement numberLong = wrapper.get("$numberLong");
|
||||
return wrapper.size() == 1
|
||||
&& numberLong != null
|
||||
&& numberLong.isJsonPrimitive()
|
||||
&& numberLong.getAsJsonPrimitive().isString();
|
||||
if (wrapper.size() != 1 || (!wrapper.has("$oid") && !wrapper.has("$numberLong"))) {
|
||||
return null;
|
||||
}
|
||||
// The document browser preserves BSON _id types as Extended JSON;
|
||||
// decode only known wrappers so JSON-looking string IDs stay strings.
|
||||
return Document.parse("{\"_id\":" + value + "}").get("_id");
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -698,9 +696,22 @@ public final class MongoAgent {
|
|||
var result = isUpdateOperatorDocument(newDoc)
|
||||
? col.updateOne(filter, newDoc)
|
||||
: col.replaceOne(filter, replacementDocument(newDoc));
|
||||
requireMatchedDocument(id, result);
|
||||
return Collections.singletonMap("modified_count", result.getModifiedCount());
|
||||
}
|
||||
|
||||
static void requireMatchedDocument(String id, UpdateResult result) {
|
||||
if (result.getMatchedCount() == 0) {
|
||||
throw new IllegalStateException(noMatchingDocumentError(id));
|
||||
}
|
||||
}
|
||||
|
||||
private static String noMatchingDocumentError(String id) {
|
||||
String display = decodeStringDocumentId(id);
|
||||
return "No document matched _id " + (display == null ? id : display)
|
||||
+ ". It may have been deleted or its _id changed since the query ran.";
|
||||
}
|
||||
|
||||
private static Object updateDocuments(JsonObject params) {
|
||||
MongoClient c = requireClient();
|
||||
String database = params.get("database").getAsString();
|
||||
|
|
|
|||
|
|
@ -179,10 +179,12 @@ class MongoAgentTest {
|
|||
void preservesLongDocumentIdTypeForGridUpdates() {
|
||||
Object id = MongoAgent.convertDocumentFieldValue("_id", 2_048_938_405_781_032_962L);
|
||||
Object value = MongoAgent.convertDocumentFieldValue("snowflake", 2_048_938_405_781_032_962L);
|
||||
ObjectId objectId = new ObjectId("507f1f77bcf86cd799439011");
|
||||
|
||||
assertEquals(Collections.singletonMap("$numberLong", "2048938405781032962"), id);
|
||||
assertEquals("2048938405781032962", value);
|
||||
assertEquals(2_048_938_405_781_032_962L, MongoAgent.parseId("{\"$numberLong\":\"2048938405781032962\"}"));
|
||||
assertEquals(objectId, MongoAgent.parseId("{\"$oid\":\"507f1f77bcf86cd799439011\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -196,6 +198,23 @@ class MongoAgentTest {
|
|||
assertEquals("{\"$numberLong\":\"invalid\"}", MongoAgent.parseId("{\"$numberLong\":\"invalid\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void documentUpdateDistinguishesNoMatchFromUnchangedValue() {
|
||||
MongoAgent.requireMatchedDocument(
|
||||
"{\"$oid\":\"507f1f77bcf86cd799439011\"}",
|
||||
UpdateResult.acknowledged(1, 0L, null)
|
||||
);
|
||||
|
||||
IllegalStateException error = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> MongoAgent.requireMatchedDocument(
|
||||
"{\"$oid\":\"507f1f77bcf86cd799439012\"}",
|
||||
UpdateResult.acknowledged(0, 0L, null)
|
||||
)
|
||||
);
|
||||
assertTrue(error.getMessage().startsWith("No document matched _id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void serverVersionMethodIsRecognizedOverJsonRpc() {
|
||||
String response = MongoAgent.handleRequest(
|
||||
|
|
|
|||
Loading…
Reference in New Issue