fix(mongo): preserve document IDs during editing
This commit is contained in:
parent
295b67dd36
commit
d9076f4689
|
|
@ -367,12 +367,6 @@ function buildElasticsearchInsertDocument(row: MongoInputValue[], columns: strin
|
|||
return doc;
|
||||
}
|
||||
|
||||
function mongoIdPreview(val: unknown): string {
|
||||
if (val === null || val === undefined) return "null";
|
||||
if (typeof val === "string" && /^[a-fA-F0-9]{24}$/.test(val)) return `ObjectId("${val}")`;
|
||||
return formatMongoShellLiteral(val);
|
||||
}
|
||||
|
||||
function elasticsearchPathIdPreview(id: string): string {
|
||||
return encodeURIComponent(id);
|
||||
}
|
||||
|
|
@ -408,7 +402,7 @@ async function previewDocumentChanges(changes: DocumentGridChanges): Promise<str
|
|||
stmts.push(`POST /${coll}/_update/${elasticsearchPathIdPreview(String(id))}${elasticsearchRoutingPreview(routing)}\n${stringifyDocumentStoreValue({ doc: updateDoc.$set ?? updateDoc }, "elasticsearch", 2)}`);
|
||||
} else {
|
||||
const updateDoc = buildMongoUpdateDocument(dirtyCols, columns, documents.value[rowIdx]);
|
||||
stmts.push(`db.${coll}.updateOne({_id: ${mongoIdPreview(documents.value[rowIdx]?._id ?? id)}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
stmts.push(`db.${coll}.updateOne({_id: ${formatMongoShellLiteral(documents.value[rowIdx]?._id ?? id)}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +414,7 @@ async function previewDocumentChanges(changes: DocumentGridChanges): Promise<str
|
|||
const routing = documentRoutingFromGridRow(row, columns);
|
||||
stmts.push(`DELETE /${coll}/_doc/${elasticsearchPathIdPreview(String(id))}${elasticsearchRoutingPreview(routing)}`);
|
||||
} else {
|
||||
stmts.push(`db.${coll}.deleteOne({_id: ${mongoIdPreview(documents.value[rowIdx]?._id ?? id)}})`);
|
||||
stmts.push(`db.${coll}.deleteOne({_id: ${formatMongoShellLiteral(documents.value[rowIdx]?._id ?? id)}})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -382,11 +382,6 @@ type MongoQueryGridChanges = {
|
|||
columns: string[];
|
||||
rows: MongoInputValue[][];
|
||||
};
|
||||
function mongoIdPreview(val: unknown): string {
|
||||
if (val === null || val === undefined) return "null";
|
||||
if (typeof val === "string" && /^[a-fA-F0-9]{24}$/.test(val)) return `ObjectId("${val}")`;
|
||||
return formatMongoShellLiteral(val);
|
||||
}
|
||||
function mongoCollectionExpression(collection: string): string {
|
||||
return `db.getCollection(${JSON.stringify(collection)})`;
|
||||
}
|
||||
|
|
@ -427,7 +422,7 @@ const mongoQueryResultSaveHandler = computed<CustomSaveHandler | undefined>(() =
|
|||
if (id === null || id === undefined || String(id).trim() === "") continue;
|
||||
const updateDoc = buildMongoUpdateDocument(dirtyCols, changes.columns, tab.result?.mongo_documents?.[rowIdx]);
|
||||
if (Object.keys(updateDoc).length === 0) continue;
|
||||
stmts.push(`${mongoCollectionExpression(target.collection)}.updateOne({_id: ${mongoIdPreview(mongoQueryResultDocumentId(rowIdx, id))}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
stmts.push(`${mongoCollectionExpression(target.collection)}.updateOne({_id: ${formatMongoShellLiteral(mongoQueryResultDocumentId(rowIdx, id))}}, ${formatMongoShellLiteral(updateDoc)})`);
|
||||
}
|
||||
return stmts;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ export function serializeMongoDocumentId(value: unknown): string {
|
|||
}
|
||||
|
||||
export function mongoDocumentIdForGrid(value: unknown): MongoInputValue {
|
||||
if (isMongoNumberLong(value)) return value.$numberLong;
|
||||
if (isMongoExtendedJsonId(value)) return String(value.$numberLong ?? value.$oid);
|
||||
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
|
@ -185,7 +185,3 @@ function isMongoExtendedJsonId(value: unknown): value is Record<string, unknown>
|
|||
const keys = Object.keys(object);
|
||||
return keys.length === 1 && (typeof object.$numberLong === "string" || typeof object.$oid === "string");
|
||||
}
|
||||
|
||||
function isMongoNumberLong(value: unknown): value is { $numberLong: string } {
|
||||
return !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && typeof (value as Record<string, unknown>).$numberLong === "string";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1341,8 +1341,10 @@ fn bson_to_json(bson: &Bson) -> serde_json::Value {
|
|||
|
||||
fn bson_document_field_to_json(key: &str, bson: &Bson) -> serde_json::Value {
|
||||
if key == "_id" {
|
||||
if let Bson::Int64(value) = bson {
|
||||
return serde_json::json!({ "$numberLong": value.to_string() });
|
||||
match bson {
|
||||
Bson::Int64(value) => return serde_json::json!({ "$numberLong": value.to_string() }),
|
||||
Bson::ObjectId(value) => return serde_json::json!({ "$oid": value.to_hex() }),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
bson_to_json(bson)
|
||||
|
|
@ -1870,6 +1872,16 @@ mod tests {
|
|||
assert_eq!(value["snowflake"], serde_json::json!("2048938405781032962"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bson_to_json_preserves_object_id_type_for_updates() {
|
||||
let oid = ObjectId::parse_str("507f1f77bcf86cd799439011").unwrap();
|
||||
let value = bson_to_json(&Bson::Document(doc! {
|
||||
"_id": Bson::ObjectId(oid),
|
||||
}));
|
||||
|
||||
assert_eq!(value["_id"], serde_json::json!({ "$oid": "507f1f77bcf86cd799439011" }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bson_to_json_keeps_safe_int64_as_number() {
|
||||
let value = bson_to_json(&Bson::Int64(42));
|
||||
|
|
|
|||
|
|
@ -222,13 +222,18 @@ test("formats extended JSON dates as Mongo shell ISODate literals", () => {
|
|||
|
||||
test("formats extended JSON object ids as Mongo shell ObjectId literals", () => {
|
||||
assert.equal(formatMongoShellLiteral({ $oid: "6743e4bfa3f6f84bc3fff6c8" }), 'ObjectId("6743e4bfa3f6f84bc3fff6c8")');
|
||||
assert.equal(formatMongoShellLiteral("6743e4bfa3f6f84bc3fff6c8"), '"6743e4bfa3f6f84bc3fff6c8"');
|
||||
});
|
||||
|
||||
test("serializes typed Mongo document ids while keeping their grid display compact", () => {
|
||||
const id = { $numberLong: "2048938405781032962" };
|
||||
assert.equal(serializeMongoDocumentId(id), '{"$numberLong":"2048938405781032962"}');
|
||||
assert.equal(mongoDocumentIdForGrid(id), "2048938405781032962");
|
||||
assert.equal(serializeMongoDocumentId({ $oid: "6743e4bfa3f6f84bc3fff6c8" }), '{"$oid":"6743e4bfa3f6f84bc3fff6c8"}');
|
||||
const longId = { $numberLong: "2048938405781032962" };
|
||||
const objectId = { $oid: "6743e4bfa3f6f84bc3fff6c8" };
|
||||
assert.equal(serializeMongoDocumentId(longId), '{"$numberLong":"2048938405781032962"}');
|
||||
assert.equal(mongoDocumentIdForGrid(longId), "2048938405781032962");
|
||||
assert.equal(serializeMongoDocumentId(objectId), '{"$oid":"6743e4bfa3f6f84bc3fff6c8"}');
|
||||
assert.equal(mongoDocumentIdForGrid(objectId), "6743e4bfa3f6f84bc3fff6c8");
|
||||
assert.equal(serializeMongoDocumentId(42), "42");
|
||||
assert.equal(serializeMongoDocumentId(42.5), "42.5");
|
||||
assert.equal(serializeMongoDocumentId("2048938405781032962"), '__dbx_mongo_string_id__"2048938405781032962"');
|
||||
assert.equal(serializeMongoDocumentId('{"$numberLong":"2048938405781032962"}'), '__dbx_mongo_string_id__"{\\"$numberLong\\":\\"2048938405781032962\\"}"');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -626,12 +626,24 @@ test("mongoDocumentsToQueryResult turns mongo documents into grid rows", () => {
|
|||
assert.equal(result.truncated, true);
|
||||
});
|
||||
|
||||
test("mongoDocumentsToQueryResult displays typed int64 ids without losing raw type metadata", () => {
|
||||
const id = { $numberLong: "2048938405781032962" };
|
||||
const result = mongoDocumentsToQueryResult([{ _id: id, name: "snowflake" }], 1, 1);
|
||||
test("mongoDocumentsToQueryResult displays ids without losing raw type metadata", () => {
|
||||
const documents = [
|
||||
{ _id: { $oid: "6743e4bfa3f6f84bc3fff6c8" }, name: "object id" },
|
||||
{ _id: { $numberLong: "2048938405781032962" }, name: "int64" },
|
||||
{ _id: 42, name: "int" },
|
||||
{ _id: 42.5, name: "double" },
|
||||
{ _id: "customer-42", name: "string" },
|
||||
];
|
||||
const result = mongoDocumentsToQueryResult(documents, documents.length, documents.length);
|
||||
|
||||
assert.deepEqual(result.rows, [["2048938405781032962", "snowflake"]]);
|
||||
assert.deepEqual(result.mongo_documents, [{ _id: id, name: "snowflake" }]);
|
||||
assert.deepEqual(result.rows, [
|
||||
["6743e4bfa3f6f84bc3fff6c8", "object id"],
|
||||
["2048938405781032962", "int64"],
|
||||
[42, "int"],
|
||||
[42.5, "double"],
|
||||
["customer-42", "string"],
|
||||
]);
|
||||
assert.deepEqual(result.mongo_documents, documents);
|
||||
});
|
||||
|
||||
test("buildMongoUpdateDocument ignores _id and preserves typed values", () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue