mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 10:16:00 +00:00
193 lines
5.8 KiB
JavaScript
193 lines
5.8 KiB
JavaScript
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 mongoReplacer(key, value) {
|
|
if (typeof value === 'bigint') {
|
|
return { $bigint: value.toString() };
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function jsonStringifyWithObjectId(obj) {
|
|
return JSON.stringify(obj, mongoReplacer, 2)
|
|
.replace(/\{\s*\"\$oid\"\s*\:\s*\"([0-9a-f]+)\"\s*\}/g, (m, id) => `ObjectId("${id}")`)
|
|
.replace(/\{\s*\"\$bigint\"\s*\:\s*\"([0-9]+)\"\s*\}/g, (m, num) => `${num}n`);
|
|
}
|
|
|
|
/** @type {import('dbgate-types').SqlDialect} */
|
|
const dialect = {
|
|
limitSelect: true,
|
|
rangeSelect: true,
|
|
offsetFetchRangeSyntax: true,
|
|
stringEscapeChar: "'",
|
|
fallbackDataType: 'nvarchar(max)',
|
|
quoteIdentifier(s) {
|
|
return `[${s}]`;
|
|
},
|
|
};
|
|
|
|
/** @type {import('dbgate-types').EngineDriver} */
|
|
const driver = {
|
|
...driverBase,
|
|
dumperClass: Dumper,
|
|
databaseEngineTypes: ['document'],
|
|
dialect,
|
|
engine: 'mongo@dbgate-plugin-mongo',
|
|
title: 'MongoDB',
|
|
editorMode: 'javascript',
|
|
defaultPort: 27017,
|
|
supportsDatabaseUrl: true,
|
|
supportsServerSummary: true,
|
|
// temporatily disable MongoDB profiler support
|
|
supportsDatabaseProfiler: false,
|
|
profilerFormatterFunction: 'formatProfilerEntry@dbgate-plugin-mongo',
|
|
profilerTimestampFunction: 'extractProfileTimestamp@dbgate-plugin-mongo',
|
|
profilerChartAggregateFunction: 'aggregateProfileChartEntry@dbgate-plugin-mongo',
|
|
profilerChartMeasures: [
|
|
{ label: 'Req count/s', field: 'countPerSec' },
|
|
{ label: 'Avg duration', field: 'avgDuration' },
|
|
{ label: 'Max duration', field: 'maxDuration' },
|
|
],
|
|
databaseUrlPlaceholder: 'e.g. mongodb://username:password@mongodb.mydomain.net/dbname',
|
|
collectionSingularLabel: 'collection',
|
|
collectionPluralLabel: 'collections',
|
|
|
|
getQuerySplitterOptions: () => mongoSplitterOptions,
|
|
|
|
showConnectionField: (field, values) => {
|
|
if (field == 'useDatabaseUrl') return true;
|
|
if (values.useDatabaseUrl) {
|
|
return ['databaseUrl', 'defaultDatabase', 'singleDatabase', 'isReadOnly'].includes(field);
|
|
}
|
|
return ['server', 'port', 'user', 'password', 'defaultDatabase', 'singleDatabase', 'isReadOnly'].includes(field);
|
|
},
|
|
|
|
importExportArgs: [
|
|
{
|
|
type: 'checkbox',
|
|
name: 'createStringId',
|
|
label: 'Create string _id attribute',
|
|
apiName: 'createStringId',
|
|
direction: 'target',
|
|
},
|
|
],
|
|
|
|
newCollectionFormParams: [
|
|
{
|
|
type: 'text',
|
|
label: 'Collection name',
|
|
name: 'name',
|
|
focused: true,
|
|
},
|
|
],
|
|
|
|
getCollectionUpdateScript(changeSet, collectionInfo) {
|
|
let res = '';
|
|
for (const insert of changeSet.inserts) {
|
|
res += `db.getCollection('${insert.pureName}').insertOne(${jsonStringifyWithObjectId({
|
|
...insert.document,
|
|
...insert.fields,
|
|
})});\n`;
|
|
}
|
|
for (const update of changeSet.updates) {
|
|
if (update.document) {
|
|
res += `db.getCollection('${update.pureName}').replaceOne(${jsonStringifyWithObjectId(
|
|
update.condition
|
|
)}, ${jsonStringifyWithObjectId({
|
|
...update.document,
|
|
...update.fields,
|
|
})});\n`;
|
|
} else {
|
|
const set = _pickBy(update.fields, (v, k) => v !== undefined);
|
|
const unset = _fromPairs(
|
|
Object.keys(update.fields)
|
|
.filter((k) => update.fields[k] === undefined)
|
|
.map((k) => [k, ''])
|
|
);
|
|
const updates = {};
|
|
if (!_.isEmpty(set)) updates.$set = set;
|
|
if (!_.isEmpty(unset)) updates.$unset = unset;
|
|
|
|
res += `db.getCollection('${update.pureName}').updateOne(${jsonStringifyWithObjectId(
|
|
update.condition
|
|
)}, ${jsonStringifyWithObjectId(updates)});\n`;
|
|
}
|
|
}
|
|
for (const del of changeSet.deletes) {
|
|
res += `db.getCollection('${del.pureName}').deleteOne(${jsonStringifyWithObjectId(del.condition)});\n`;
|
|
}
|
|
return res;
|
|
},
|
|
|
|
getFilterBehaviour(dataType, standardFilterBehaviours) {
|
|
return standardFilterBehaviours.mongoFilterBehaviour;
|
|
},
|
|
|
|
getCollectionExportQueryScript(collection, condition, sort) {
|
|
return `db.getCollection('${collection}')
|
|
.find(${JSON.stringify(convertToMongoCondition(condition) || {})})
|
|
.sort(${JSON.stringify(convertToMongoSort(sort) || {})})`;
|
|
},
|
|
getCollectionExportQueryJson(collection, condition, sort) {
|
|
return {
|
|
collection,
|
|
condition: convertToMongoCondition(condition) || {},
|
|
sort: convertToMongoSort(sort) || {},
|
|
};
|
|
},
|
|
|
|
dataEditorTypesBehaviour: {
|
|
parseJsonNull: true,
|
|
parseJsonBoolean: true,
|
|
parseNumber: true,
|
|
parseJsonArray: true,
|
|
parseJsonObject: true,
|
|
parseObjectIdAsDollar: true,
|
|
parseDateAsDollar: true,
|
|
|
|
explicitDataType: true,
|
|
supportNumberType: true,
|
|
supportStringType: true,
|
|
supportBooleanType: true,
|
|
supportDateType: true,
|
|
supportJsonType: true,
|
|
supportObjectIdType: true,
|
|
supportNullType: true,
|
|
|
|
supportFieldRemoval: true,
|
|
},
|
|
|
|
getScriptTemplates(objectTypeField) {
|
|
switch (objectTypeField) {
|
|
case 'collections':
|
|
return [
|
|
{
|
|
label: 'JS: dropCollection()',
|
|
scriptTemplate: 'dropCollection',
|
|
},
|
|
{
|
|
label: 'JS: find()',
|
|
scriptTemplate: 'findCollection',
|
|
},
|
|
];
|
|
}
|
|
|
|
return [];
|
|
},
|
|
|
|
async getScriptTemplateContent(scriptTemplate, props) {
|
|
switch (scriptTemplate) {
|
|
case 'dropCollection':
|
|
return `db.getCollection('${props.pureName}').drop();`;
|
|
case 'findCollection':
|
|
return `db.getCollection('${props.pureName}').find();`;
|
|
}
|
|
},
|
|
};
|
|
|
|
module.exports = driver;
|