diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index c58ca18ff..dea2c0409 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -112,6 +112,8 @@ export interface DataEditorTypesBehaviour { supportNullType?: boolean; supportJsonType?: boolean; supportObjectIdType?: boolean; + + supportFieldRemoval?: boolean; } export interface FilterBehaviourProvider { diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index d3034d9dd..a608cff9f 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -81,10 +81,21 @@ category: 'Data grid', name: 'Set NULL', keyText: 'CtrlOrCommand+0', - testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable, + testEnabled: () => + getCurrentDataGrid()?.getGrider()?.editable && !getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval, onClick: () => getCurrentDataGrid().setFixedValue(null), }); + registerCommand({ + id: 'dataGrid.removeField', + category: 'Data grid', + name: 'Remove field', + keyText: 'CtrlOrCommand+0', + testEnabled: () => + getCurrentDataGrid()?.getGrider()?.editable && getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval, + onClick: () => getCurrentDataGrid().setFixedValue(undefined), + }); + registerCommand({ id: 'dataGrid.undo', category: 'Data grid', @@ -823,6 +834,10 @@ }); } + export function getEditorTypes() { + return display?.driver?.dataEditorTypesBehaviour; + } + export function addJsonDocumentEnabled() { return grider.editable; } @@ -1703,7 +1718,8 @@ { command: 'dataGrid.deleteSelectedRows' }, { command: 'dataGrid.insertNewRow' }, { command: 'dataGrid.cloneRows' }, - { command: 'dataGrid.setNull' }, + { command: 'dataGrid.setNull', hideDisabled: true }, + { command: 'dataGrid.removeField', hideDisabled: true }, { placeTag: 'edit' }, { divider: true }, { command: 'dataGrid.findColumn' }, diff --git a/packages/web/src/formview/FormView.svelte b/packages/web/src/formview/FormView.svelte index 32b51f156..7dce34966 100644 --- a/packages/web/src/formview/FormView.svelte +++ b/packages/web/src/formview/FormView.svelte @@ -48,10 +48,19 @@ category: 'Data form', name: 'Set NULL', keyText: 'CtrlOrCommand+0', - testEnabled: () => getCurrentDataForm() != null, + testEnabled: () => getCurrentDataForm() != null && !getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval, onClick: () => getCurrentDataForm().setFixedValue(null), }); + registerCommand({ + id: 'dataForm.removeField', + category: 'Data form', + name: 'Remove field', + keyText: 'CtrlOrCommand+0', + testEnabled: () => getCurrentDataForm() != null && getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval, + onClick: () => getCurrentDataForm().setFixedValue(undefined), + }); + registerCommand({ id: 'dataForm.undo', category: 'Data form', @@ -321,6 +330,10 @@ export const activator = createActivator('FormView', false); + export function getEditorTypes() { + return display?.driver?.dataEditorTypesBehaviour; + } + const handleTableMouseDown = event => { if (event.target.closest('.buttonLike')) return; if (event.target.closest('.resizeHandleControl')) return; @@ -411,10 +424,11 @@ { divider: true }, { placeTag: 'save' }, { command: 'dataForm.revertRowChanges' }, - { command: 'dataForm.setNull' }, + { command: 'dataForm.setNull', hideDisabled: true }, + { command: 'dataForm.removeField', hideDisabled: true }, { divider: true }, - { command: 'dataForm.undo' }, - { command: 'dataForm.redo' }, + { command: 'dataForm.undo', hideDisabled: true }, + { command: 'dataForm.redo', hideDisabled: true }, { divider: true }, { command: 'dataForm.goToFirst' }, { command: 'dataForm.goToPrevious' }, diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index 2dd8fb6d6..4417742d0 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -121,7 +121,13 @@ const resp = await apiCall('database-connections/update-collection', { conid, database, - changeSet, + changeSet: { + ...changeSet, + updates: changeSet.updates.map(update => ({ + ...update, + fields: _.mapValues(update.fields, (v, k) => (v === undefined ? { $undefined: true } : v)), + })), + }, }); const { errorMessage } = resp || {}; if (errorMessage) { diff --git a/plugins/dbgate-plugin-mongo/src/backend/driver.js b/plugins/dbgate-plugin-mongo/src/backend/driver.js index 9a91dcca7..58f0a5b6d 100644 --- a/plugins/dbgate-plugin-mongo/src/backend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/backend/driver.js @@ -330,7 +330,14 @@ const driver = { } } else { const resdoc = await collection.updateOne(convertObjectId(update.condition), { - $set: convertObjectId(update.fields), + $set: convertObjectId(_.pickBy(update.fields, (v, k) => !v?.$undefined)), + $unset: _.fromPairs( + Object.keys(update.fields) + .filter((k) => update.fields[k]?.$undefined) + .map((k) => [k, '']) + ), + + // $set: convertObjectId(update.fields), }); res.updated.push(resdoc._id); } diff --git a/plugins/dbgate-plugin-mongo/src/frontend/driver.js b/plugins/dbgate-plugin-mongo/src/frontend/driver.js index 5e0fdd7cf..4f3f1bfea 100644 --- a/plugins/dbgate-plugin-mongo/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mongo/src/frontend/driver.js @@ -2,6 +2,8 @@ const { driverBase } = global.DBGATE_PACKAGES['dbgate-tools']; const { convertToMongoCondition, convertToMongoSort } = require('./convertToMongoCondition'); const Dumper = require('./Dumper'); const { mongoSplitterOptions } = require('dbgate-query-splitter/lib/options'); +const _pickBy = require('lodash/pickBy'); +const _fromPairs = require('lodash/fromPairs'); function jsonStringifyWithObjectId(obj) { return JSON.stringify(obj, undefined, 2).replace( @@ -96,7 +98,12 @@ const driver = { res += `db.${update.pureName}.updateOne(${jsonStringifyWithObjectId( update.condition )}, ${jsonStringifyWithObjectId({ - $set: update.fields, + $set: _pickBy(update.fields, (v, k) => v !== undefined), + $unset: _fromPairs( + Object.keys(update.fields) + .filter((k) => update.fields[k] === undefined) + .map((k) => [k, '']) + ), })});\n`; } } @@ -140,6 +147,8 @@ const driver = { supportJsonType: true, supportObjectIdType: true, supportNullType: true, + + supportFieldRemoval: true, }, };