mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-21 21:01:55 +08:00
- 为 MongoDB 编辑态补充字段名驱动的保守类型推断 - 统一 DataGrid 基准数据为类型化值,覆盖 JSON、行编辑和单元格编辑 - 保持 pMid 等普通字符串字段不被误判为 ObjectId - 补充 Mongo helper、DataViewer 主键定位与 DataGrid 提交回归测试
208 lines
7.8 KiB
TypeScript
208 lines
7.8 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import {
|
|
applyMongoQueryAutoLimit,
|
|
buildMongoFindCommand,
|
|
convertMongoShellToJsonCommand,
|
|
formatMongoEditableValue,
|
|
normalizeMongoDocumentForEditing,
|
|
parseMongoEditedValue,
|
|
} from './mongodb';
|
|
|
|
const parseCommand = (command: string | undefined) => JSON.parse(command || '{}');
|
|
|
|
describe('convertMongoShellToJsonCommand', () => {
|
|
it('converts show dbs shell shortcut to listDatabases command', () => {
|
|
expect(convertMongoShellToJsonCommand('show dbs;')).toEqual({
|
|
recognized: true,
|
|
command: JSON.stringify({ listDatabases: 1, nameOnly: true }),
|
|
});
|
|
});
|
|
|
|
it('converts show collections shell shortcut to listCollections command', () => {
|
|
expect(convertMongoShellToJsonCommand(' show collections ')).toEqual({
|
|
recognized: true,
|
|
command: JSON.stringify({ listCollections: 1, filter: {}, nameOnly: true }),
|
|
});
|
|
});
|
|
|
|
it('converts find shell commands without adding implicit limit', () => {
|
|
const result = convertMongoShellToJsonCommand('db.users.find({ active: true })');
|
|
|
|
expect(result.recognized).toBe(true);
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: { active: true },
|
|
});
|
|
});
|
|
|
|
it('keeps explicit find limit values from shell commands', () => {
|
|
const result = convertMongoShellToJsonCommand('db.users.find({}).limit(10)');
|
|
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: {},
|
|
limit: 10,
|
|
});
|
|
});
|
|
|
|
it('keeps explicit zero limit values from shell commands', () => {
|
|
const result = convertMongoShellToJsonCommand('db.users.find({}).limit(0)');
|
|
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: {},
|
|
limit: 0,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('applyMongoQueryAutoLimit', () => {
|
|
it('adds limit to raw Mongo find commands', () => {
|
|
const result = applyMongoQueryAutoLimit('{"find":"users","filter":{}}', 500);
|
|
|
|
expect(result.applied).toBe(true);
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: {},
|
|
limit: 500,
|
|
});
|
|
});
|
|
|
|
it('adds limit after shell find conversion', () => {
|
|
const shell = convertMongoShellToJsonCommand('db.users.find({ active: true })');
|
|
const result = applyMongoQueryAutoLimit(shell.command || '', 500);
|
|
|
|
expect(result.applied).toBe(true);
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: { active: true },
|
|
limit: 500,
|
|
});
|
|
});
|
|
|
|
it('does not replace explicit find limits', () => {
|
|
const result = applyMongoQueryAutoLimit('{"find":"users","filter":{},"limit":10}', 500);
|
|
|
|
expect(result.applied).toBe(false);
|
|
expect(parseCommand(result.command)).toEqual({
|
|
find: 'users',
|
|
filter: {},
|
|
limit: 10,
|
|
});
|
|
});
|
|
|
|
it('adds $limit to read-only aggregate pipelines', () => {
|
|
const result = applyMongoQueryAutoLimit('{"aggregate":"users","pipeline":[{"$match":{"active":true}}],"cursor":{}}', 500);
|
|
|
|
expect(result.applied).toBe(true);
|
|
expect(parseCommand(result.command)).toEqual({
|
|
aggregate: 'users',
|
|
pipeline: [
|
|
{ $match: { active: true } },
|
|
{ $limit: 500 },
|
|
],
|
|
cursor: {},
|
|
});
|
|
});
|
|
|
|
it('does not add another aggregate $limit', () => {
|
|
const command = '{"aggregate":"users","pipeline":[{"$limit":10}],"cursor":{}}';
|
|
const result = applyMongoQueryAutoLimit(command, 500);
|
|
|
|
expect(result.applied).toBe(false);
|
|
expect(result.command).toBe(command);
|
|
});
|
|
|
|
it('does not alter aggregate write pipelines', () => {
|
|
const command = '{"aggregate":"users","pipeline":[{"$match":{}},{"$out":"tmp_users"}],"cursor":{}}';
|
|
const result = applyMongoQueryAutoLimit(command, 500);
|
|
|
|
expect(result.applied).toBe(false);
|
|
expect(result.command).toBe(command);
|
|
});
|
|
|
|
it('does not limit non-read or invalid commands', () => {
|
|
expect(applyMongoQueryAutoLimit('{"count":"users","query":{}}', 500).applied).toBe(false);
|
|
expect(applyMongoQueryAutoLimit('db.users.find({})', 500).applied).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('buildMongoFindCommand', () => {
|
|
it('marks DataViewer Mongo find commands to include typed _id locator', () => {
|
|
expect(parseCommand(buildMongoFindCommand({
|
|
collection: 'users',
|
|
filter: {},
|
|
includeObjectIDLocator: true,
|
|
}))).toEqual({
|
|
find: 'users',
|
|
filter: {},
|
|
__gonaviIncludeObjectIDLocator: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Mongo edit value helpers', () => {
|
|
it('formats common extended JSON wrappers to editable literals', () => {
|
|
expect(formatMongoEditableValue({ $oid: '507f1f77bcf86cd799439011' })).toBe('ObjectId("507f1f77bcf86cd799439011")');
|
|
expect(formatMongoEditableValue({ $date: { $numberLong: '1719100800000' } })).toBe('ISODate("2024-06-23T00:00:00.000Z")');
|
|
expect(formatMongoEditableValue({ $numberInt: '7' })).toBe('NumberInt(7)');
|
|
expect(formatMongoEditableValue({ $numberLong: '8' })).toBe('NumberLong("8")');
|
|
expect(formatMongoEditableValue({ $numberDouble: '1.5' })).toBe('1.5');
|
|
expect(formatMongoEditableValue({ $numberDecimal: '9.99' })).toBe('NumberDecimal("9.99")');
|
|
expect(formatMongoEditableValue({
|
|
$binary: {
|
|
base64: 'EjRWeBI0RniSNFZ4EjRWeA==',
|
|
subType: '04',
|
|
},
|
|
})).toBe('UUID("12345678-1234-4678-9234-567812345678")');
|
|
});
|
|
|
|
it('infers editable Mongo typed literals from common string field names', () => {
|
|
expect(formatMongoEditableValue('5a7fb5b93560e06a6e1e4950', 'merchantId')).toBe('ObjectId("5a7fb5b93560e06a6e1e4950")');
|
|
expect(formatMongoEditableValue('5ba279393560e029bb0b6359', 'pMid')).toBe('5ba279393560e029bb0b6359');
|
|
expect(formatMongoEditableValue('2018-06-24 07:42:51.8', 'updateTime')).toBe('ISODate("2018-06-24T07:42:51.800Z")');
|
|
});
|
|
|
|
it('parses typed Mongo edit text back to extended JSON wrappers', () => {
|
|
expect(parseMongoEditedValue('_id', '507f1f77bcf86cd799439011')).toEqual({ $oid: '507f1f77bcf86cd799439011' });
|
|
expect(parseMongoEditedValue('createdAt', '2024-06-23T00:00:00.000Z', { $date: { $numberLong: '1719100800000' } })).toEqual({
|
|
$date: { $numberLong: '1719100800000' },
|
|
});
|
|
expect(parseMongoEditedValue('count32', '7', { $numberInt: '1' })).toEqual({ $numberInt: '7' });
|
|
expect(parseMongoEditedValue('count64', '8', { $numberLong: '1' })).toEqual({ $numberLong: '8' });
|
|
expect(parseMongoEditedValue('ratio', '1.5', { $numberDouble: '0.5' })).toEqual({ $numberDouble: '1.5' });
|
|
expect(parseMongoEditedValue('price', '9.99', { $numberDecimal: '1.23' })).toEqual({ $numberDecimal: '9.99' });
|
|
expect(parseMongoEditedValue('uid', 'UUID("12345678-1234-4678-9234-567812345678")')).toEqual({
|
|
$binary: {
|
|
base64: 'EjRWeBI0RniSNFZ4EjRWeA==',
|
|
subType: '04',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('infers typed Mongo values from string edits when the field name is sufficient', () => {
|
|
expect(parseMongoEditedValue('merchantId', '5a7fb5b93560e06a6e1e4950')).toEqual({ $oid: '5a7fb5b93560e06a6e1e4950' });
|
|
expect(parseMongoEditedValue('updateTime', '2018-06-24 07:42:51.8')).toEqual({
|
|
$date: '2018-06-24T07:42:51.800Z',
|
|
});
|
|
expect(parseMongoEditedValue('pMid', '5ba279393560e029bb0b6359')).toBe('5ba279393560e029bb0b6359');
|
|
});
|
|
|
|
it('normalizes Mongo documents for JSON editing without promoting plain string ids blindly', () => {
|
|
expect(normalizeMongoDocumentForEditing({
|
|
_id: '5a8262f93560e05dd3465288',
|
|
merchantId: '5a7fb5b93560e06a6e1e4950',
|
|
pMid: '5ba279393560e029bb0b6359',
|
|
updateTime: '2018-06-24 07:42:51.8',
|
|
userId: '5a65611fadfce63b96bb2001',
|
|
})).toEqual({
|
|
_id: { $oid: '5a8262f93560e05dd3465288' },
|
|
merchantId: { $oid: '5a7fb5b93560e06a6e1e4950' },
|
|
pMid: '5ba279393560e029bb0b6359',
|
|
updateTime: { $date: '2018-06-24T07:42:51.800Z' },
|
|
userId: { $oid: '5a65611fadfce63b96bb2001' },
|
|
});
|
|
});
|
|
});
|