• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vocdoni / saas-backend / 16290308099

15 Jul 2025 10:03AM UTC coverage: 55.959% (+0.02%) from 55.936%
16290308099

Pull #188

github

altergui
db: refactor redundant code

* SetProcessBundle
* SetBulkOrgMembers
Pull Request #188: db: remove redundant code in SetProcessBundle

7 of 8 new or added lines in 2 files covered. (87.5%)

1 existing line in 1 file now uncovered.

4902 of 8760 relevant lines covered (55.96%)

24.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.06
/db/process_bundles.go
1
package db
2

3
import (
4
        "bytes"
5
        "context"
6
        "fmt"
7

8
        "github.com/vocdoni/saas-backend/internal"
9
        "go.mongodb.org/mongo-driver/bson"
10
        "go.mongodb.org/mongo-driver/bson/primitive"
11
        "go.mongodb.org/mongo-driver/mongo/options"
12
)
13

14
// SetProcessBundle creates a new process bundle or updates an existing one.
15
// It validates that the organization and census exist before creating or updating the bundle.
16
// Returns the bundle ID as a hex string on success.
17
func (ms *MongoStorage) SetProcessBundle(bundle *ProcessesBundle) (internal.HexBytes, error) {
11✔
18
        if bundle.ID.IsZero() {
20✔
19
                bundle.ID = primitive.NewObjectID()
9✔
20
        }
9✔
21

22
        // Check that the org exists
23
        if _, err := ms.Organization(bundle.OrgAddress); err != nil {
12✔
24
                return nil, fmt.Errorf("failed to get organization: %w", err)
1✔
25
        }
1✔
26

27
        // check that the census exists
28
        _, err := ms.Census(bundle.Census.ID.Hex())
10✔
29
        if err != nil {
10✔
30
                return nil, fmt.Errorf("failed to get census: %w", err)
×
31
        }
×
32

33
        ms.keysLock.Lock()
10✔
34
        defer ms.keysLock.Unlock()
10✔
35
        // Create a context with a timeout
10✔
36
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
10✔
37
        defer cancel()
10✔
38

10✔
39
        // If the bundle has an ID, update it, otherwise create a new one
10✔
40
        filter := bson.M{"_id": bundle.ID}
10✔
41
        update := bson.M{"$set": bundle}
10✔
42
        opts := &options.UpdateOptions{}
10✔
43
        opts.SetUpsert(true)
10✔
44

10✔
45
        if _, err := ms.processBundles.UpdateOne(ctx, filter, update, opts); err != nil {
10✔
NEW
46
                return nil, fmt.Errorf("failed to update process bundle: %w", err)
×
UNCOV
47
        }
×
48

49
        return *new(internal.HexBytes).SetString(bundle.ID.Hex()), nil
10✔
50
}
51

52
// DelProcessBundle removes a process bundle by ID.
53
// Returns ErrInvalidData if the bundleID is zero, or ErrNotFound if no bundle with the given ID exists.
54
func (ms *MongoStorage) DelProcessBundle(hbBundleID internal.HexBytes) error {
3✔
55
        bundleID, err := primitive.ObjectIDFromHex(hbBundleID.String())
3✔
56
        if err != nil {
4✔
57
                return ErrInvalidData
1✔
58
        }
1✔
59
        if bundleID.IsZero() {
2✔
60
                return ErrInvalidData
×
61
        }
×
62

63
        ms.keysLock.Lock()
2✔
64
        defer ms.keysLock.Unlock()
2✔
65
        // Create a context with a timeout
2✔
66
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
2✔
67
        defer cancel()
2✔
68

2✔
69
        // Delete the process bundle from the database using the ID
2✔
70
        filter := bson.M{"_id": bundleID}
2✔
71
        result, err := ms.processBundles.DeleteOne(ctx, filter)
2✔
72
        if err != nil {
2✔
73
                return fmt.Errorf("failed to delete process bundle: %w", err)
×
74
        }
×
75

76
        if result.DeletedCount == 0 {
3✔
77
                return ErrNotFound
1✔
78
        }
1✔
79

80
        return nil
1✔
81
}
82

83
// ProcessBundle retrieves a process bundle from the database based on its ID.
84
// Returns the bundle with all its associated data including census information and processes.
85
func (ms *MongoStorage) ProcessBundle(hbBundleID internal.HexBytes) (*ProcessesBundle, error) {
26✔
86
        bundleID, err := primitive.ObjectIDFromHex(hbBundleID.String())
26✔
87
        if err != nil {
26✔
88
                return nil, ErrInvalidData
×
89
        }
×
90
        if bundleID.IsZero() {
26✔
91
                return nil, ErrInvalidData
×
92
        }
×
93

94
        // Create a context with a timeout
95
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
26✔
96
        defer cancel()
26✔
97

26✔
98
        bundle := &ProcessesBundle{}
26✔
99
        if err := ms.processBundles.FindOne(ctx, bson.M{"_id": bundleID}).Decode(bundle); err != nil {
27✔
100
                return nil, fmt.Errorf("failed to get process bundle: %w", err)
1✔
101
        }
1✔
102

103
        return bundle, nil
25✔
104
}
105

106
// ProcessBundles retrieves all process bundles from the database.
107
// Returns a slice of all process bundles with their complete information.
108
func (ms *MongoStorage) ProcessBundles() ([]*ProcessesBundle, error) {
2✔
109
        // Create a context with a timeout
2✔
110
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
2✔
111
        defer cancel()
2✔
112

2✔
113
        cursor, err := ms.processBundles.Find(ctx, bson.M{})
2✔
114
        if err != nil {
2✔
115
                return nil, fmt.Errorf("failed to find process bundles: %w", err)
×
116
        }
×
117
        defer func() {
4✔
118
                err := cursor.Close(ctx)
2✔
119
                if err != nil {
2✔
120
                        fmt.Println("failed to close cursor")
×
121
                }
×
122
        }()
123

124
        var bundles []*ProcessesBundle
2✔
125
        if err := cursor.All(ctx, &bundles); err != nil {
2✔
126
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
127
        }
×
128

129
        return bundles, nil
2✔
130
}
131

132
// ProcessBundlesByProcess retrieves process bundles that contain a specific process ID.
133
// This allows finding all bundles that include a particular process.
134
func (ms *MongoStorage) ProcessBundlesByProcess(processID []byte) ([]*ProcessesBundle, error) {
4✔
135
        if len(processID) == 0 {
5✔
136
                return nil, ErrInvalidData
1✔
137
        }
1✔
138

139
        // Create a context with a timeout
140
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
3✔
141
        defer cancel()
3✔
142

3✔
143
        // Find bundles where the processes array contains a process with the given ID
3✔
144
        filter := bson.M{"processes": processID}
3✔
145
        cursor, err := ms.processBundles.Find(ctx, filter)
3✔
146
        if err != nil {
3✔
147
                return nil, fmt.Errorf("failed to find process bundles by process ID: %w", err)
×
148
        }
×
149
        defer func() {
6✔
150
                err := cursor.Close(ctx)
3✔
151
                if err != nil {
3✔
152
                        fmt.Println("failed to close cursor")
×
153
                }
×
154
        }()
155

156
        var bundles []*ProcessesBundle
3✔
157
        if err := cursor.All(ctx, &bundles); err != nil {
3✔
158
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
159
        }
×
160

161
        return bundles, nil
3✔
162
}
163

164
// ProcessBundlesByOrg retrieves process bundles that belong to a specific organization.
165
// This allows finding all bundles created by a particular organization.
166
func (ms *MongoStorage) ProcessBundlesByOrg(orgAddress string) ([]*ProcessesBundle, error) {
×
167
        if len(orgAddress) == 0 {
×
168
                return nil, ErrInvalidData
×
169
        }
×
170

171
        // Create a context with a timeout
172
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
×
173
        defer cancel()
×
174

×
175
        // Find bundles where the orgAddress matches the given address
×
176
        filter := bson.M{"orgAddress": orgAddress}
×
177
        cursor, err := ms.processBundles.Find(ctx, filter)
×
178
        if err != nil {
×
179
                return nil, fmt.Errorf("failed to find process bundles by organization: %w", err)
×
180
        }
×
181
        defer func() {
×
182
                err := cursor.Close(ctx)
×
183
                if err != nil {
×
184
                        fmt.Println("failed to close cursor")
×
185
                }
×
186
        }()
187

188
        var bundles []*ProcessesBundle
×
189
        if err := cursor.All(ctx, &bundles); err != nil {
×
190
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
191
        }
×
192

193
        return bundles, nil
×
194
}
195

196
// AddProcessesToBundle adds processes to an existing bundle if they don't already exist.
197
// It checks each process to avoid duplicates and only updates the database if new processes were added.
198
func (ms *MongoStorage) AddProcessesToBundle(hbBundleID internal.HexBytes, processes []internal.HexBytes) error {
5✔
199
        bundleID, err := primitive.ObjectIDFromHex(hbBundleID.String())
5✔
200
        if err != nil {
6✔
201
                return ErrInvalidData
1✔
202
        }
1✔
203
        if len(processes) == 0 {
5✔
204
                return ErrInvalidData
1✔
205
        }
1✔
206

207
        bundle, err := ms.ProcessBundle(hbBundleID)
3✔
208
        if err != nil {
3✔
209
                return fmt.Errorf("failed to get process bundle: %w", err)
×
210
        }
×
211

212
        if bundle.ID.IsZero() {
3✔
213
                bundle.ID = primitive.NewObjectID()
×
214
        }
×
215

216
        ms.keysLock.Lock()
3✔
217
        defer ms.keysLock.Unlock()
3✔
218
        // Create a context with a timeout
3✔
219
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
3✔
220
        defer cancel()
3✔
221

3✔
222
        // Check each process and add it if it doesn't already exist in the bundle
3✔
223
        processesAdded := false
3✔
224
        for _, newProcess := range processes {
7✔
225
                exists := false
4✔
226
                for _, existingProcess := range bundle.Processes {
13✔
227
                        if bytes.Equal(existingProcess, newProcess) {
10✔
228
                                exists = true
1✔
229
                                break
1✔
230
                        }
231
                }
232
                if !exists {
7✔
233
                        bundle.Processes = append(bundle.Processes, newProcess)
3✔
234
                        processesAdded = true
3✔
235
                }
3✔
236
        }
237

238
        // If no processes were added, return early
239
        if !processesAdded {
4✔
240
                return nil
1✔
241
        }
1✔
242

243
        // Update the bundle in the database
244
        filter := bson.M{"_id": bundleID}
2✔
245
        update := bson.M{"$set": bson.M{"processes": bundle.Processes}}
2✔
246
        if _, err := ms.processBundles.UpdateOne(ctx, filter, update); err != nil {
2✔
247
                return fmt.Errorf("failed to update process bundle: %w", err)
×
248
        }
×
249

250
        return nil
2✔
251
}
252

253
// NewBundleID generates a new unique ObjectID for a process bundle.
254
// This is used when creating a new bundle to ensure it has a unique identifier.
255
func (*MongoStorage) NewBundleID() primitive.ObjectID {
1✔
256
        return primitive.NewObjectID()
1✔
257
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc