-
Notifications
You must be signed in to change notification settings - Fork 715
refactor: optimize value mapping with caching for improved performance #8828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
PR Reviewer Guide 🔍(Review updated until commit 468f653)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 468f653
Previous suggestionsSuggestions up to commit f4eaf91
|
|
| Status | Total | Passed | Failed | Skipped | Flaky | Pass Rate | Duration |
|---|---|---|---|---|---|---|---|
| All tests passed | 364 | 342 | 0 | 19 | 3 | 94% | 7m 6s |
f4eaf91 to
468f653
Compare
|
Persistent review updated to latest commit 468f653 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Overview
Summary
Optimized table data conversion by caching value mappings, unit/color configs, and timezone lookups. Removed deep cloning to work with original data directly.
Critical Issues Found:
- Missing regex mapping support: Cache only handles
valueandrangetypes, omittingregexpattern matching entirely (lines 28-49, 64-89) - Incorrect lowercase transformation:
aliasLower = aliasshould bealias.toLowerCase()for proper case-insensitive lookup (line 135) - Data mutation risk: Shallow copy instead of deep clone means mutations to
tableRowsaffect originalsearchQueryData[0](line 117)
Performance Improvements:
- Pre-built value mapping cache reduces O(n×m) to O(1) or O(log n) lookups
- Config maps avoid repeated override config traversals
- Cached timezone/decimals eliminate repeated store/config reads
- Field name cache speeds up case-insensitive field resolution
Confidence Score: 2/5
- Not safe to merge - contains critical bugs that break existing functionality
- Three critical bugs found: (1) regex mapping support completely removed causing feature regression, (2) incorrect variable assignment breaks case-insensitive lookups, (3) shallow copy introduces potential data mutation. These will cause runtime failures for dashboards using regex mappings and case-sensitive field mismatches.
- web/src/utils/dashboard/convertTableData.ts requires immediate attention to fix regex mapping support, lowercase transformation, and shallow copy issues
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| web/src/utils/dashboard/convertTableData.ts | 2/5 | Performance optimizations introduced three critical bugs: missing regex mapping support, incorrect lowercase transformation, and potential data mutation from shallow copy |
Sequence Diagram
sequenceDiagram
participant Caller
participant convertTableData
participant buildCache as buildValueMappingCache
participant lookup as lookupValueMapping
participant formatter as Column Formatters
Caller->>convertTableData: panelSchema, searchQueryData
Note over convertTableData: Shallow copy (no deep clone)
convertTableData->>convertTableData: tableRows = searchQueryData[0]
convertTableData->>buildCache: panelSchema.config.mappings
Note over buildCache: Build once for all cells
buildCache->>buildCache: Create Map cache for value/range
Note right of buildCache: ❌ Missing regex mappings
buildCache-->>convertTableData: valueMappingCache
Note over convertTableData: Build config maps once
convertTableData->>convertTableData: Build colorConfigMap
convertTableData->>convertTableData: Build unitConfigMap
Note right of convertTableData: ❌ aliasLower = alias (not lowercased)
convertTableData->>convertTableData: Build fieldNameCache
loop For each column
convertTableData->>formatter: Create format function
Note over formatter: Closure captures:<br/>- valueMappingCache<br/>- unitConfigMap<br/>- timezone (cached)<br/>- decimals (cached)
formatter->>lookup: value, valueMappingCache
lookup->>lookup: Check direct value in Map
lookup->>lookup: Check range mappings
Note right of lookup: ❌ No regex check
lookup-->>formatter: mapped value or null
end
convertTableData-->>Caller: {rows, columns}
1 file reviewed, 4 comments
| const buildValueMappingCache = (mappings: any) => { | ||
| if (!mappings || !Array.isArray(mappings)) { | ||
| return null; | ||
| } | ||
|
|
||
| const cache = new Map<any, string>(); | ||
|
|
||
| mappings.forEach((mapping: any) => { | ||
| if (mapping && mapping.text) { | ||
| // Handle range mappings | ||
| if (mapping.from !== undefined && mapping.to !== undefined) { | ||
| // Store range info for later lookup | ||
| cache.set(`__range_${mapping.from}_${mapping.to}`, mapping.text); | ||
| } else if (mapping.value !== undefined && mapping.value !== null) { | ||
| // Direct value mapping | ||
| cache.set(mapping.value, mapping.text); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| return cache.size > 0 ? cache : null; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Cache doesn't handle all mapping types - regex type mappings are missing
The original findFirstValidMappedValue function supports three mapping types: value, range, and regex. The new cache only handles direct value and range mappings, but completely omits regex pattern matching.
| const buildValueMappingCache = (mappings: any) => { | |
| if (!mappings || !Array.isArray(mappings)) { | |
| return null; | |
| } | |
| const cache = new Map<any, string>(); | |
| mappings.forEach((mapping: any) => { | |
| if (mapping && mapping.text) { | |
| // Handle range mappings | |
| if (mapping.from !== undefined && mapping.to !== undefined) { | |
| // Store range info for later lookup | |
| cache.set(`__range_${mapping.from}_${mapping.to}`, mapping.text); | |
| } else if (mapping.value !== undefined && mapping.value !== null) { | |
| // Direct value mapping | |
| cache.set(mapping.value, mapping.text); | |
| } | |
| } | |
| }); | |
| return cache.size > 0 ? cache : null; | |
| }; | |
| const buildValueMappingCache = (mappings: any) => { | |
| if (!mappings || !Array.isArray(mappings)) { | |
| return null; | |
| } | |
| const cache = new Map<any, string>(); | |
| const regexMappings: Array<{pattern: RegExp, text: string}> = []; | |
| mappings.forEach((mapping: any) => { | |
| if (mapping && mapping.text) { | |
| // Handle regex mappings separately | |
| if (mapping.type === "regex" && mapping.pattern) { | |
| regexMappings.push({ pattern: new RegExp(mapping.pattern), text: mapping.text }); | |
| } | |
| // Handle range mappings | |
| else if ((mapping.type === "range" || mapping.from !== undefined) && mapping.to !== undefined) { | |
| // Store range info for later lookup | |
| cache.set(`__range_${mapping.from}_${mapping.to}`, mapping.text); | |
| } else if ((mapping.type === "value" || mapping.value !== undefined) && mapping.value !== null) { | |
| // Direct value mapping | |
| cache.set(mapping.value, mapping.text); | |
| } | |
| } | |
| }); | |
| if (cache.size === 0 && regexMappings.length === 0) return null; | |
| return { cache, regexMappings }; | |
| }; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/utils/dashboard/convertTableData.ts
Line: 28:49
Comment:
**logic:** Cache doesn't handle all mapping types - `regex` type mappings are missing
The original `findFirstValidMappedValue` function supports three mapping types: `value`, `range`, and `regex`. The new cache only handles direct value and range mappings, but completely omits regex pattern matching.
```suggestion
const buildValueMappingCache = (mappings: any) => {
if (!mappings || !Array.isArray(mappings)) {
return null;
}
const cache = new Map<any, string>();
const regexMappings: Array<{pattern: RegExp, text: string}> = [];
mappings.forEach((mapping: any) => {
if (mapping && mapping.text) {
// Handle regex mappings separately
if (mapping.type === "regex" && mapping.pattern) {
regexMappings.push({ pattern: new RegExp(mapping.pattern), text: mapping.text });
}
// Handle range mappings
else if ((mapping.type === "range" || mapping.from !== undefined) && mapping.to !== undefined) {
// Store range info for later lookup
cache.set(`__range_${mapping.from}_${mapping.to}`, mapping.text);
} else if ((mapping.type === "value" || mapping.value !== undefined) && mapping.value !== null) {
// Direct value mapping
cache.set(mapping.value, mapping.text);
}
}
});
if (cache.size === 0 && regexMappings.length === 0) return null;
return { cache, regexMappings };
};
```
How can I resolve this? If you propose a fix, please make it concise.| const lookupValueMapping = (value: any, cache: Map<any, string> | null) => { | ||
| if (!cache) return null; | ||
|
|
||
| // Direct lookup first | ||
| if (cache.has(value)) { | ||
| return cache.get(value); | ||
| } | ||
|
|
||
| // Check range mappings | ||
| if (typeof value === 'number') { | ||
| const entries = Array.from(cache.entries()); | ||
| for (let i = 0; i < entries.length; i++) { | ||
| const [key, text] = entries[i]; | ||
| if (typeof key === 'string' && key.startsWith('__range_')) { | ||
| const parts = key.split('_'); | ||
| const from = parseFloat(parts[2]); | ||
| const to = parseFloat(parts[3]); | ||
| if (!isNaN(from) && !isNaN(to) && value >= from && value <= to) { | ||
| return text; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return null; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Lookup function needs to support regex mappings and check explicit types
Update to handle regex mappings and properly check type field:
| const lookupValueMapping = (value: any, cache: Map<any, string> | null) => { | |
| if (!cache) return null; | |
| // Direct lookup first | |
| if (cache.has(value)) { | |
| return cache.get(value); | |
| } | |
| // Check range mappings | |
| if (typeof value === 'number') { | |
| const entries = Array.from(cache.entries()); | |
| for (let i = 0; i < entries.length; i++) { | |
| const [key, text] = entries[i]; | |
| if (typeof key === 'string' && key.startsWith('__range_')) { | |
| const parts = key.split('_'); | |
| const from = parseFloat(parts[2]); | |
| const to = parseFloat(parts[3]); | |
| if (!isNaN(from) && !isNaN(to) && value >= from && value <= to) { | |
| return text; | |
| } | |
| } | |
| } | |
| } | |
| return null; | |
| }; | |
| const lookupValueMapping = (value: any, cacheObj: {cache: Map<any, string>, regexMappings: Array<{pattern: RegExp, text: string}>} | null) => { | |
| if (!cacheObj) return null; | |
| const { cache, regexMappings } = cacheObj; | |
| // Direct lookup first | |
| if (cache.has(value)) { | |
| return cache.get(value); | |
| } | |
| // Check range mappings | |
| if (typeof value === 'number') { | |
| const entries = Array.from(cache.entries()); | |
| for (let i = 0; i < entries.length; i++) { | |
| const [key, text] = entries[i]; | |
| if (typeof key === 'string' && key.startsWith('__range_')) { | |
| const parts = key.split('_'); | |
| const from = parseFloat(parts[2]); | |
| const to = parseFloat(parts[3]); | |
| if (!isNaN(from) && !isNaN(to) && value >= from && value <= to) { | |
| return text; | |
| } | |
| } | |
| } | |
| } | |
| // Check regex mappings | |
| for (const {pattern, text} of regexMappings) { | |
| if (pattern.test(value)) { | |
| return text; | |
| } | |
| } | |
| return null; | |
| }; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/utils/dashboard/convertTableData.ts
Line: 64:89
Comment:
**logic:** Lookup function needs to support regex mappings and check explicit types
Update to handle regex mappings and properly check `type` field:
```suggestion
const lookupValueMapping = (value: any, cacheObj: {cache: Map<any, string>, regexMappings: Array<{pattern: RegExp, text: string}>} | null) => {
if (!cacheObj) return null;
const { cache, regexMappings } = cacheObj;
// Direct lookup first
if (cache.has(value)) {
return cache.get(value);
}
// Check range mappings
if (typeof value === 'number') {
const entries = Array.from(cache.entries());
for (let i = 0; i < entries.length; i++) {
const [key, text] = entries[i];
if (typeof key === 'string' && key.startsWith('__range_')) {
const parts = key.split('_');
const from = parseFloat(parts[2]);
const to = parseFloat(parts[3]);
if (!isNaN(from) && !isNaN(to) && value >= from && value <= to) {
return text;
}
}
}
}
// Check regex mappings
for (const {pattern, text} of regexMappings) {
if (pattern.test(value)) {
return text;
}
}
return null;
};
```
How can I resolve this? If you propose a fix, please make it concise.| const config = o?.config?.[0]; | ||
|
|
||
| if (alias && config) { | ||
| const aliasLower = alias; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Variable assigned but never transformed - should be alias.toLowerCase()
| const aliasLower = alias; | |
| const aliasLower = alias.toLowerCase(); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/utils/dashboard/convertTableData.ts
Line: 135:135
Comment:
**logic:** Variable assigned but never transformed - should be `alias.toLowerCase()`
```suggestion
const aliasLower = alias.toLowerCase();
```
How can I resolve this? If you propose a fix, please make it concise.| let columnData = [...x, ...y]; | ||
| let tableRows = JSON.parse(JSON.stringify(searchQueryData[0])); | ||
| // Avoid deep cloning - use shallow copy and work with original data | ||
| let tableRows = searchQueryData[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Shallow copy breaks mutability assumptions - can cause unintended side effects
Removing the deep clone means the original searchQueryData[0] is now directly referenced and could be mutated by downstream code. If any code modifies tableRows, it will affect the original data structure.
Prompt To Fix With AI
This is a comment left during a code review.
Path: web/src/utils/dashboard/convertTableData.ts
Line: 117:117
Comment:
**logic:** Shallow copy breaks mutability assumptions - can cause unintended side effects
Removing the deep clone means the original `searchQueryData[0]` is now directly referenced and could be mutated by downstream code. If any code modifies `tableRows`, it will affect the original data structure.
How can I resolve this? If you propose a fix, please make it concise.
|
| Status | Total | Passed | Failed | Skipped | Flaky | Pass Rate | Duration |
|---|---|---|---|---|---|---|---|
| All tests passed | 364 | 342 | 0 | 19 | 3 | 94% | 7m 7s |
468f653 to
18a4a09
Compare
|
| Status | Total | Passed | Failed | Skipped | Flaky | Pass Rate | Duration |
|---|---|---|---|---|---|---|---|
| All tests passed | 364 | 342 | 0 | 19 | 3 | 94% | 4m 39s |
464f610 to
2c9931a
Compare
2c9931a to
ace4d9f
Compare
PR Type
Enhancement
Description
Add value mapping cache for fast lookups
Avoid deep clone; use original data
Precompute config and timezone for formatters
Case-insensitive field lookup caching
Diagram Walkthrough
File Walkthrough
convertTableData.ts
Performance-focused refactor of table conversion logicweb/src/utils/dashboard/convertTableData.ts