Skip to content

Commit 0a3805e

Browse files
engalarclaude
andcommitted
perf(show modules): eliminate BSON decode for type-based counting
show modules was decoding ALL page, microflow, nanoflow, snippet, enumeration, constant and Java action documents (via listPagesWithContainerGen, listMicroflowsWithContainerGen, etc.) just to produce count columns. The unitCache already carries type strings from the BSON $Type field — no document decoding is needed for counting. Replace the multi-function approach with a single pass over ListUnits() using a switch on types.UnitTypeXxx constants. Entity counts still require domain-model decoding (entities are sub-objects, not standalone units). Also add mdl/types/unit_types.go with exported BSON type name constants (types.UnitTypePage, types.UnitTypeMicroflow, etc.) shared across executor and backend layers, replacing scattered hard-coded string literals. Expected speedup: eliminates ~9 domain-model decodes + all page/microflow/ snippet/nanoflow/enumeration/constant decodes per show modules invocation. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 5985101 commit 0a3805e

2 files changed

Lines changed: 78 additions & 66 deletions

File tree

mdl/executor/cmd_modules.go

Lines changed: 29 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -446,26 +446,45 @@ func listModules(ctx *ExecContext) error {
446446
bizEventCounts := make(map[model.ID]int)
447447
extDbCounts := make(map[model.ID]int)
448448

449-
// Count from units by type prefix (efficient single pass)
449+
// Single-pass over unit metadata using mdl/types constants: all
450+
// type-based counts are derived from the unitCache type strings —
451+
// no BSON decoding required. This is the dominant performance path.
450452
for _, u := range units {
451453
modID := h.FindModuleID(u.ContainerID)
452-
switch {
453-
case strings.HasPrefix(u.Type, "Rest$PublishedRestService"):
454+
switch u.Type {
455+
case types.UnitTypePage:
456+
pageCounts[modID]++
457+
case types.UnitTypeSnippet:
458+
snippetCounts[modID]++
459+
case types.UnitTypeMicroflow:
460+
microflowCounts[modID]++
461+
case types.UnitTypeNanoflow:
462+
nanoflowCounts[modID]++
463+
case types.UnitTypeEnumeration:
464+
enumCounts[modID]++
465+
case types.UnitTypeConstant:
466+
constantCounts[modID]++
467+
case types.UnitTypeJavaAction:
468+
javaActionCounts[modID]++
469+
case types.UnitTypePublishedRestService:
454470
pubRestCounts[modID]++
455-
case strings.HasPrefix(u.Type, "ODataPublish$PublishedODataService"):
471+
case types.UnitTypePublishedODataService:
456472
pubODataCounts[modID]++
457-
case strings.HasPrefix(u.Type, "Rest$ConsumedODataService"):
473+
case types.UnitTypeConsumedODataService:
458474
conODataCounts[modID]++
459-
case strings.HasPrefix(u.Type, "BusinessEvents$"):
460-
bizEventCounts[modID]++
461-
case strings.HasPrefix(u.Type, "Workflows$Workflow"):
475+
case types.UnitTypeWorkflow:
462476
workflowCounts[modID]++
463-
case strings.HasPrefix(u.Type, "DatabaseConnector$DatabaseConnection"):
477+
case types.UnitTypeDatabaseConnection:
464478
extDbCounts[modID]++
479+
default:
480+
if strings.HasPrefix(u.Type, types.UnitTypeBusinessEvent) {
481+
bizEventCounts[modID]++
482+
}
465483
}
466484
}
467485

468-
// Count entities from domain models (Stage 3.3.4 C2.c — gen path).
486+
// Entity counts still require domain-model decoding: entities are sub-objects
487+
// of domain model units, not standalone units with their own unitCache entries.
469488
if pairs, err := listDomainModelsWithContainerGen(ctx); err == nil {
470489
for _, p := range pairs {
471490
if p.DM == nil {
@@ -476,62 +495,6 @@ func listModules(ctx *ExecContext) error {
476495
}
477496
}
478497

479-
// Count enumerations
480-
if enums, err := ctx.Backend.ListEnumerations(); err == nil {
481-
for _, enum := range enums {
482-
modID := h.FindModuleID(enum.ContainerID)
483-
enumCounts[modID]++
484-
}
485-
}
486-
487-
// Count pages
488-
if pagePairs, err := listPagesWithContainerGen(ctx); err == nil {
489-
for _, pair := range pagePairs {
490-
modID := h.FindModuleID(model.ID(pair.ContainerID))
491-
pageCounts[modID]++
492-
}
493-
}
494-
495-
// Count snippets
496-
if snippetPairs, err := listSnippetsWithContainerGen(ctx); err == nil {
497-
for _, pair := range snippetPairs {
498-
modID := h.FindModuleID(model.ID(pair.ContainerID))
499-
snippetCounts[modID]++
500-
}
501-
}
502-
503-
// Count microflows
504-
if mfs, err := listMicroflowsWithContainerGen(ctx); err == nil {
505-
for _, item := range mfs {
506-
modID := h.FindModuleID(item.ContainerUUID)
507-
microflowCounts[modID]++
508-
}
509-
}
510-
511-
// Count nanoflows
512-
if nfs, err := listNanoflowsWithContainerGen(ctx); err == nil {
513-
for _, item := range nfs {
514-
modID := h.FindModuleID(item.ContainerUUID)
515-
nanoflowCounts[modID]++
516-
}
517-
}
518-
519-
// Count constants
520-
if constants, err := ctx.Backend.ListConstants(); err == nil {
521-
for _, c := range constants {
522-
modID := h.FindModuleID(c.ContainerID)
523-
constantCounts[modID]++
524-
}
525-
}
526-
527-
// Count Java actions (gen-typed)
528-
if pairs, err := listJavaActionsWithContainerGen(ctx); err == nil {
529-
for _, p := range pairs {
530-
modID := h.FindModuleID(model.ID(p.ContainerID))
531-
javaActionCounts[modID]++
532-
}
533-
}
534-
535498
// Sort modules alphabetically by name
536499
sort.Slice(modules, func(i, j int) bool {
537500
return strings.ToLower(modules[i].Name) < strings.ToLower(modules[j].Name)

mdl/types/unit_types.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package types
4+
5+
// Unit type name constants for MPR BSON $Type fields.
6+
// These are the storage names used by Mendix Studio Pro — not the SDK
7+
// qualified names. Use these constants instead of raw string literals
8+
// when switching on UnitInfo.Type or unitCache entries.
9+
const (
10+
// Core project structure
11+
UnitTypeModule = "Projects$ModuleImpl"
12+
UnitTypeModuleSettings = "Projects$ModuleSettings"
13+
UnitTypeFolder = "Projects$Folder"
14+
UnitTypeProjectSettings = "Settings$ProjectSettings"
15+
16+
// Domain model
17+
UnitTypeDomainModel = "DomainModels$DomainModel"
18+
UnitTypeEnumeration = "Enumerations$Enumeration"
19+
UnitTypeConstant = "Constants$Constant"
20+
21+
// Flows
22+
UnitTypeMicroflow = "Microflows$Microflow"
23+
UnitTypeNanoflow = "Microflows$Nanoflow"
24+
UnitTypeRule = "Microflows$Rule"
25+
26+
// Pages / UI
27+
UnitTypePage = "Forms$Page"
28+
UnitTypeLayout = "Forms$Layout"
29+
UnitTypeSnippet = "Forms$Snippet"
30+
31+
// Java / JavaScript actions
32+
UnitTypeJavaAction = "JavaActions$JavaAction"
33+
UnitTypeJavaScriptAction = "JavaActions$JavaScriptAction"
34+
35+
// Workflows
36+
UnitTypeWorkflow = "Workflows$Workflow"
37+
38+
// REST / OData / Business events
39+
UnitTypePublishedRestService = "Rest$PublishedRestService"
40+
UnitTypePublishedODataService = "ODataPublish$PublishedODataService"
41+
UnitTypeConsumedODataService = "Rest$ConsumedODataService"
42+
UnitTypeBusinessEvent = "BusinessEvents$" // prefix — multiple sub-types
43+
44+
// Database connector
45+
UnitTypeDatabaseConnection = "DatabaseConnector$DatabaseConnection"
46+
47+
// Images
48+
UnitTypeImageCollection = "Images$ImageCollection"
49+
)

0 commit comments

Comments
 (0)