mongosh support only for premium

This commit is contained in:
SPRINX0\prochazka
2025-07-30 10:19:57 +02:00
parent 6e8cdc24a3
commit e856d8fddf
4 changed files with 172 additions and 60 deletions

View File

@@ -43,6 +43,8 @@ function adjustFile(file, isApp = false) {
if (process.argv.includes('--community')) { if (process.argv.includes('--community')) {
delete json.optionalDependencies['mongodb-client-encryption']; delete json.optionalDependencies['mongodb-client-encryption'];
delete json.dependencies['@mongosh/service-provider-node-driver'];
delete json.dependencies['@mongosh/browser-runtime-electron'];
} }
if (isApp && process.argv.includes('--premium')) { if (isApp && process.argv.includes('--premium')) {

View File

@@ -3,6 +3,7 @@ const os = require('os');
const path = require('path'); const path = require('path');
const processArgs = require('./processArgs'); const processArgs = require('./processArgs');
const isElectron = require('is-electron'); const isElectron = require('is-electron');
const { isProApp } = require('./checkLicense');
const platform = process.env.OS_OVERRIDE ? process.env.OS_OVERRIDE : process.platform; const platform = process.env.OS_OVERRIDE ? process.env.OS_OVERRIDE : process.platform;
const isWindows = platform === 'win32'; const isWindows = platform === 'win32';
@@ -59,6 +60,7 @@ const platformInfo = {
defaultKeyfile: path.join(os.homedir(), '.ssh/id_rsa'), defaultKeyfile: path.join(os.homedir(), '.ssh/id_rsa'),
isAwsUbuntuLayout, isAwsUbuntuLayout,
isAzureUbuntuLayout, isAzureUbuntuLayout,
isProApp: isProApp()
}; };
module.exports = platformInfo; module.exports = platformInfo;

View File

@@ -2,10 +2,9 @@ const _ = require('lodash');
const stream = require('stream'); const stream = require('stream');
const driverBase = require('../frontend/driver'); const driverBase = require('../frontend/driver');
const Analyser = require('./Analyser'); const Analyser = require('./Analyser');
const { MongoClient, ObjectId, Long } = require('mongodb'); const isPromise = require('is-promise');
const { MongoClient, ObjectId, AbstractCursor, Long } = require('mongodb');
const { EJSON } = require('bson'); const { EJSON } = require('bson');
const { NodeDriverServiceProvider } = require('@mongosh/service-provider-node-driver');
const { ElectronRuntime } = require('@mongosh/browser-runtime-electron');
const { serializeJsTypesForJsonStringify, deserializeJsTypesFromJsonParse } = require('dbgate-tools'); const { serializeJsTypesForJsonStringify, deserializeJsTypesFromJsonParse } = require('dbgate-tools');
const createBulkInsertStream = require('./createBulkInsertStream'); const createBulkInsertStream = require('./createBulkInsertStream');
const { const {
@@ -14,6 +13,8 @@ const {
convertToMongoSort, convertToMongoSort,
} = require('../frontend/convertToMongoCondition'); } = require('../frontend/convertToMongoCondition');
let platformInfo;
function serializeMongoData(row) { function serializeMongoData(row) {
return EJSON.serialize( return EJSON.serialize(
serializeJsTypesForJsonStringify(row, (value) => { serializeJsTypesForJsonStringify(row, (value) => {
@@ -29,12 +30,27 @@ function serializeMongoData(row) {
); );
} }
async function readCursor(cursor, options) {
options.recordset({ __isDynamicStructure: true });
await cursor.forEach((row) => {
options.row(serializeMongoData(row));
});
}
function deserializeMongoData(value) { function deserializeMongoData(value) {
return deserializeJsTypesFromJsonParse(EJSON.deserialize(value)); return deserializeJsTypesFromJsonParse(EJSON.deserialize(value));
} }
function findArrayResult(resValue) {
if (!_.isPlainObject(resValue)) return null;
const arrays = _.values(resValue).filter((x) => _.isArray(x));
if (arrays.length == 1) return arrays[0];
return null;
}
async function getScriptableDb(dbhan) { async function getScriptableDb(dbhan) {
const db = dbhan.getDatabase(); const db = dbhan.getDatabase();
db.getCollection = (name) => db.collection(name);
const collections = await db.listCollections().toArray(); const collections = await db.listCollections().toArray();
for (const collection of collections) { for (const collection of collections) {
_.set(db, collection.name, db.collection(collection.name)); _.set(db, collection.name, db.collection(collection.name));
@@ -114,22 +130,33 @@ const driver = {
}; };
}, },
async script(dbhan, sql) { async script(dbhan, sql) {
const connectionString = ensureDatabaseInMongoURI(dbhan.client.s.url, dbhan.database); if (platformInfo.isProApp) {
const serviceProvider = await NodeDriverServiceProvider.connect(connectionString); const { NodeDriverServiceProvider } = require('@mongosh/service-provider-node-driver');
const runtime = new ElectronRuntime(serviceProvider); const { ElectronRuntime } = require('@mongosh/browser-runtime-electron');
const exprValue = await runtime.evaluate(sql);
const { printable } = exprValue; const connectionString = ensureDatabaseInMongoURI(dbhan.client.s.url, dbhan.database);
const serviceProvider = await NodeDriverServiceProvider.connect(connectionString);
const runtime = new ElectronRuntime(serviceProvider);
const exprValue = await runtime.evaluate(sql);
const { printable } = exprValue;
if (Array.isArray(printable)) {
return printable;
} else if ('documents' in printable) {
return printable.documents;
} else if ('cursor' in printable && 'firstBatch' in printable.cursor) {
return printable.cursor.firstBatch;
}
if (Array.isArray(printable)) {
return printable; return printable;
} else if ('documents' in printable) { } else {
return printable.documents; let func;
} else if ('cursor' in printable && 'firstBatch' in printable.cursor) { func = eval(`(db,ObjectId) => ${sql}`);
return printable.cursor.firstBatch; const db = await getScriptableDb(dbhan);
const res = func(db, ObjectId.createFromHexString);
if (isPromise(res)) await res;
} }
return printable;
}, },
async operation(dbhan, operation, options) { async operation(dbhan, operation, options) {
const { type } = operation; const { type } = operation;
@@ -158,60 +185,134 @@ const driver = {
// saveScriptToDatabase({ conid: connection._id, database: name }, `db.createCollection('${newCollection}')`); // saveScriptToDatabase({ conid: connection._id, database: name }, `db.createCollection('${newCollection}')`);
}, },
async stream(dbhan, sql, options) { async stream(dbhan, sql, options) {
let exprValue; if (platformInfo.isProApp) {
const { NodeDriverServiceProvider } = require('@mongosh/service-provider-node-driver');
const { ElectronRuntime } = require('@mongosh/browser-runtime-electron');
try { let exprValue;
const connectionString = ensureDatabaseInMongoURI(dbhan.client.s.url, dbhan.database);
const serviceProvider = await NodeDriverServiceProvider.connect(connectionString);
const runtime = new ElectronRuntime(serviceProvider);
exprValue = await runtime.evaluate(sql);
} catch (err) {
options.info({
message: 'Error evaluating expression: ' + err.message,
time: new Date(),
severity: 'error',
});
options.done();
return;
}
const { printable, type } = exprValue; try {
const connectionString = ensureDatabaseInMongoURI(dbhan.client.s.url, dbhan.database);
if (type === 'Document') { const serviceProvider = await NodeDriverServiceProvider.connect(connectionString);
options.recordset({ __isDynamicStructure: true }); const runtime = new ElectronRuntime(serviceProvider);
options.row(printable); exprValue = await runtime.evaluate(sql);
} else if (type === 'Cursor' || exprValue.type === 'AggregationCursor') { } catch (err) {
options.recordset({ __isDynamicStructure: true }); options.info({
for (const doc of printable.documents) { message: 'Error evaluating expression: ' + err.message,
options.row(doc); time: new Date(),
severity: 'error',
});
options.done();
return;
} }
} else {
if (Array.isArray(printable)) { const { printable, type } = exprValue;
if (type === 'Document') {
options.recordset({ __isDynamicStructure: true }); options.recordset({ __isDynamicStructure: true });
for (const row of printable) { options.row(printable);
options.row(row); } else if (type === 'Cursor' || exprValue.type === 'AggregationCursor') {
}
} else if ('documents' in printable) {
options.recordset({ __isDynamicStructure: true }); options.recordset({ __isDynamicStructure: true });
for (const row of printable.documents) { for (const doc of printable.documents) {
options.row(row); options.row(doc);
}
} else if ('cursor' in printable && 'firstBatch' in printable.cursor) {
options.recordset({ __isDynamicStructure: true });
for (const row of printable.cursor.firstBatch) {
options.row(row);
} }
} else { } else {
options.info({ if (Array.isArray(printable)) {
printable: printable, options.recordset({ __isDynamicStructure: true });
time: new Date(), for (const row of printable) {
severity: 'info', options.row(row);
message: 'Query returned not supported value.', }
}); } else if ('documents' in printable) {
options.recordset({ __isDynamicStructure: true });
for (const row of printable.documents) {
options.row(row);
}
} else if ('cursor' in printable && 'firstBatch' in printable.cursor) {
options.recordset({ __isDynamicStructure: true });
for (const row of printable.cursor.firstBatch) {
options.row(row);
}
} else {
options.info({
printable: printable,
time: new Date(),
severity: 'info',
message: 'Query returned not supported value.',
});
}
} }
}
options.done(); options.done();
} else {
let func;
try {
func = eval(`(db,ObjectId) => ${sql}`);
} catch (err) {
options.info({
message: 'Error compiling expression: ' + err.message,
time: new Date(),
severity: 'error',
});
options.done();
return;
}
const db = await getScriptableDb(dbhan);
let exprValue;
try {
exprValue = func(db, ObjectId.createFromHexString);
} catch (err) {
options.info({
message: 'Error evaluating expression: ' + err.message,
time: new Date(),
severity: 'error',
});
options.done();
return;
}
if (exprValue instanceof AbstractCursor) {
await readCursor(exprValue, options);
} else if (isPromise(exprValue)) {
try {
const resValue = await exprValue;
options.info({
message: 'Command succesfully executed',
time: new Date(),
severity: 'info',
});
try {
options.info({
message: `Result: ${JSON.stringify(resValue)}`,
time: new Date(),
severity: 'info',
});
} catch (err) {
options.info({
message: `Result: ${resValue}`,
time: new Date(),
severity: 'info',
});
}
const arrayRes = findArrayResult(resValue);
if (arrayRes) {
options.recordset({ __isDynamicStructure: true });
for (const row of arrayRes) {
options.row(row);
}
}
} catch (err) {
options.info({
message: 'Error when running command: ' + err.message,
time: new Date(),
severity: 'error',
});
}
}
options.done();
}
}, },
async startProfiler(dbhan, options) { async startProfiler(dbhan, options) {
const db = await getScriptableDb(dbhan); const db = await getScriptableDb(dbhan);
@@ -590,4 +691,8 @@ const driver = {
}, },
}; };
driver.initialize = (dbgateEnv) => {
platformInfo = dbgateEnv.platformInfo;
};
module.exports = driver; module.exports = driver;

View File

@@ -13,4 +13,7 @@ module.exports = {
extractProfileTimestamp, extractProfileTimestamp,
aggregateProfileChartEntry, aggregateProfileChartEntry,
}, },
initialize(dbgateEnv) {
driver.initialize(dbgateEnv);
},
}; };