From 6bd48ca29fd4e9487c0ebc66ed771303f107cfa2 Mon Sep 17 00:00:00 2001 From: Jan Prochazka Date: Tue, 7 Dec 2021 21:29:31 +0100 Subject: [PATCH] precise work with mongoid --- packages/filterparser/src/filterTool.ts | 1 + packages/filterparser/src/mongoParser.ts | 12 +++---- packages/web/src/datagrid/DataGridCell.svelte | 2 ++ packages/web/src/datagrid/gridutil.ts | 1 + .../web/src/jsonview/CollectionJsonRow.svelte | 2 +- packages/web/src/utility/clipboard.ts | 1 + .../dbgate-plugin-mongo/src/backend/driver.js | 34 +++++++------------ .../src/frontend/driver.js | 6 ++-- 8 files changed, 25 insertions(+), 34 deletions(-) diff --git a/packages/filterparser/src/filterTool.ts b/packages/filterparser/src/filterTool.ts index 416850641..af50bf38b 100644 --- a/packages/filterparser/src/filterTool.ts +++ b/packages/filterparser/src/filterTool.ts @@ -8,6 +8,7 @@ export function getFilterValueExpression(value, dataType) { if (isTypeDateTime(dataType)) return moment(value).format('YYYY-MM-DD HH:mm:ss'); if (value === true) return 'TRUE'; if (value === false) return 'FALSE'; + if (value.$oid) return `ObjectId("${value.$oid}")`; return `="${value}"`; } diff --git a/packages/filterparser/src/mongoParser.ts b/packages/filterparser/src/mongoParser.ts index f40f907d2..b5dd3335c 100644 --- a/packages/filterparser/src/mongoParser.ts +++ b/packages/filterparser/src/mongoParser.ts @@ -28,16 +28,12 @@ const numberTestCondition = () => value => ({ ], }); +const idRegex = /[('"]([0-9a-f]{24})['")]/; + const objectIdTestCondition = () => value => ({ $or: [ { - __placeholder__: { - $regex: `.*${value}.*`, - $options: 'i', - }, - }, - { - __placeholder__: { $oid: value }, + __placeholder__: { $oid: value.match(idRegex)[1] }, }, ], }); @@ -78,7 +74,7 @@ const createParser = () => { .map(Number) .desc('number'), - objectid: () => token(P.regexp(/[0-9a-f]{24}/)).desc('ObjectId'), + objectid: () => token(P.regexp(/ObjectId\(['"]?[0-9a-f]{24}['"]?\)/)).desc('ObjectId'), noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'), diff --git a/packages/web/src/datagrid/DataGridCell.svelte b/packages/web/src/datagrid/DataGridCell.svelte index 9a49ca254..7ebd565fd 100644 --- a/packages/web/src/datagrid/DataGridCell.svelte +++ b/packages/web/src/datagrid/DataGridCell.svelte @@ -124,6 +124,8 @@ {:else} ({value.data.length} bytes) {/if} + {:else if value.$oid} + ObjectId("{value.$oid}") {:else if _.isPlainObject(value)} (JSON) {:else if _.isArray(value)} diff --git a/packages/web/src/datagrid/gridutil.ts b/packages/web/src/datagrid/gridutil.ts index d5f91ea5f..9bffcfc5b 100644 --- a/packages/web/src/datagrid/gridutil.ts +++ b/packages/web/src/datagrid/gridutil.ts @@ -67,6 +67,7 @@ export function countColumnSizes(grider: Grider, columns, containerWidth, displa const value = row[uqName]; let text = value; if (_.isArray(value)) text = `[${value.length} items]`; + else if (value?.$oid) text = `ObjectId("${value.$oid}")`; const width = context.measureText(text).width + 8; // console.log('colName', colName, text, width); columnSizes.putSizeOverride(colIndex, width); diff --git a/packages/web/src/jsonview/CollectionJsonRow.svelte b/packages/web/src/jsonview/CollectionJsonRow.svelte index 93307f1ed..c0daca2d8 100644 --- a/packages/web/src/jsonview/CollectionJsonRow.svelte +++ b/packages/web/src/jsonview/CollectionJsonRow.svelte @@ -4,7 +4,7 @@ showModal(EditJsonModal, { json: rowData, onSave: value => { - if (value._id != rowData._id) { + if (rowData._id && value._id != rowData._id) { showModal(ErrorMessageModal, { message: '_id attribute cannot be changed' }); return false; } diff --git a/packages/web/src/utility/clipboard.ts b/packages/web/src/utility/clipboard.ts index 6d82b50a3..2ed5bc560 100644 --- a/packages/web/src/utility/clipboard.ts +++ b/packages/web/src/utility/clipboard.ts @@ -71,6 +71,7 @@ export function extractRowCopiedValue(row, col) { if (value === undefined) value = _.get(row, col); if (value === null) return '(NULL)'; if (value === undefined) return '(NoField)'; + if (value && value.$oid) return `ObjectId("${value.$oid}")`; if (value && value.type == 'Buffer' && _.isArray(value.data)) return arrayToHexString(value.data); if (_.isPlainObject(value) || _.isArray(value)) return JSON.stringify(value); return value; diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 25fa56eb9..99a6160b4 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -8,28 +8,20 @@ const ObjectId = require('mongodb').ObjectId; const Cursor = require('mongodb').Cursor; const createBulkInsertStream = require('./createBulkInsertStream'); +function transformMongoData(row) { + return _.mapValues(row, (v) => (v && v.constructor && v.constructor.name == 'ObjectID' ? { $oid: v.toString() } : v)); +} + function readCursor(cursor, options) { return new Promise((resolve) => { options.recordset({ __isDynamicStructure: true }); - cursor.on('data', (data) => options.row(data)); + cursor.on('data', (data) => options.row(transformMongoData(data))); cursor.on('end', () => resolve()); }); } -const mongoIdRegex = /^[0-9a-f]{24}$/; -function convertConditionInternal(condition) { - if (condition && _.isString(condition._id) && condition._id.match(mongoIdRegex)) { - return { - _id: { - $in: [condition._id, ObjectId(condition._id)], - }, - }; - } - return condition; -} - -function convertConditionUser(condition) { +function convertCondition(condition) { return _.cloneDeepWith(condition, (x) => { if (x && x.$oid) return ObjectId(x.$oid); }); @@ -213,16 +205,16 @@ const driver = { try { const collection = pool.__getDatabase().collection(options.pureName); if (options.countDocuments) { - const count = await collection.countDocuments(convertConditionUser(options.condition) || {}); + const count = await collection.countDocuments(convertCondition(options.condition) || {}); return { count }; } else { // console.log('options.condition', JSON.stringify(options.condition, undefined, 2)); - let cursor = await collection.find(convertConditionUser(options.condition) || {}); + let cursor = await collection.find(convertCondition(options.condition) || {}); if (options.sort) cursor = cursor.sort(options.sort); if (options.skip) cursor = cursor.skip(options.skip); if (options.limit) cursor = cursor.limit(options.limit); const rows = await cursor.toArray(); - return { rows }; + return { rows: rows.map(transformMongoData) }; } } catch (err) { return { errorMessage: err.message }; @@ -253,16 +245,16 @@ const driver = { ...update.document, ...update.fields, }; - const doc = await collection.findOne(convertConditionInternal(update.condition)); + const doc = await collection.findOne(convertCondition(update.condition)); if (doc) { - const resdoc = await collection.replaceOne(convertConditionInternal(update.condition), { + const resdoc = await collection.replaceOne(convertCondition(update.condition), { ...document, _id: doc._id, }); res.replaced.push(resdoc._id); } } else { - const resdoc = await collection.updateOne(convertConditionInternal(update.condition), { + const resdoc = await collection.updateOne(convertCondition(update.condition), { $set: update.fields, }); res.updated.push(resdoc._id); @@ -270,7 +262,7 @@ const driver = { } for (const del of changeSet.deletes) { const collection = db.collection(del.pureName); - const resdoc = await collection.deleteOne(convertConditionInternal(del.condition)); + const resdoc = await collection.deleteOne(convertCondition(del.condition)); res.deleted.push(resdoc._id); } return res; diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index edf10f2a2..1ccf067f2 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -3,11 +3,9 @@ const { driverBase } = global.DBGATE_TOOLS; const Dumper = require('./Dumper'); const { mongoSplitterOptions } = require('dbgate-query-splitter/lib/options'); -const mongoIdRegex = /^[0-9a-f]{24}$/; - function getConditionPreview(condition) { - if (condition && _isString(condition._id) && condition._id.match(mongoIdRegex)) { - return `{ _id: { $in: ['${condition._id}', ObjectId('${condition._id}')] } }`; + if (condition && condition._id && condition._id.$oid) { + return `{ _id: ObjectId('${condition._id.$oid}') }`; } return JSON.stringify(condition); }