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

DataBiosphere / consent / #5580

07 Mar 2025 08:35PM UTC coverage: 79.278% (+0.004%) from 79.274%
#5580

push

web-flow
DT-1284: Improve dataset query performance (#2464)

9 of 10 new or added lines in 4 files covered. (90.0%)

2 existing lines in 2 files now uncovered.

10253 of 12933 relevant lines covered (79.28%)

0.79 hits per line

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

82.29
/src/main/java/org/broadinstitute/consent/http/models/Dataset.java
1
package org.broadinstitute.consent.http.models;
2

3
import com.google.gson.JsonArray;
4
import com.google.gson.JsonPrimitive;
5
import java.util.ArrayList;
6
import java.util.Date;
7
import java.util.HashSet;
8
import java.util.List;
9
import java.util.Objects;
10
import java.util.Optional;
11
import java.util.Set;
12
import org.apache.commons.lang3.StringUtils;
13
import org.broadinstitute.consent.http.models.dataset_registration_v1.ConsentGroup.AccessManagement;
14
import org.broadinstitute.consent.http.models.dataset_registration_v1.builder.DatasetRegistrationSchemaV1Builder;
15
import org.broadinstitute.consent.http.util.ConsentLogger;
16
import org.checkerframework.checker.nullness.qual.NonNull;
17

18
public class Dataset implements ConsentLogger {
19

20
  private Integer datasetId;
21

22
  private String objectId;
23

24
  private String name;
25

26
  // For backwards compatibility with DatasetDTO, this is an alias to the name property.
27
  private String datasetName;
28

29
  private Date createDate;
30

31
  private Integer createUserId;
32

33
  private Date updateDate;
34

35
  private Integer updateUserId;
36

37
  private Integer alias;
38

39
  private String datasetIdentifier;
40

41
  public DataUse dataUse;
42

43
  private String translatedDataUse;
44
  private Integer dacId;
45

46
  private Boolean deletable;
47

48
  private FileStorageObject nihInstitutionalCertificationFile;
49

50
  private Set<DatasetProperty> properties;
51

52
  List<String> propertyName;
53
  private Boolean dacApproval;
54

55
  private User createUser;
56

57
  private Integer studyId;
58

59
  private Study study;
60

61
  public Dataset() {
1✔
62
  }
1✔
63

64
  public Dataset(Integer datasetId, String objectId, String name, Date createDate,
65
      Integer createUserId, Date updateDate, Integer updateUserId, Integer alias) {
×
66
    this.datasetId = datasetId;
×
67
    this.objectId = objectId;
×
68
    this.name = name;
×
69
    this.datasetName = name;
×
70
    this.createDate = createDate;
×
71
    this.createUserId = createUserId;
×
72
    this.updateDate = updateDate;
×
73
    this.updateUserId = updateUserId;
×
74
    this.alias = alias;
×
75
  }
×
76

77
  public Dataset(Integer datasetId, String objectId, String name, Date createDate, Integer alias) {
×
78
    this.datasetId = datasetId;
×
79
    this.objectId = objectId;
×
80
    this.name = name;
×
81
    this.datasetName = name;
×
82
    this.createDate = createDate;
×
83
    this.alias = alias;
×
84
  }
×
85

86
  public Dataset(Integer datasetId, String objectId, String name, Date createDate) {
1✔
87
    this.datasetId = datasetId;
1✔
88
    this.objectId = objectId;
1✔
89
    this.name = name;
1✔
90
    this.datasetName = name;
1✔
91
    this.createDate = createDate;
1✔
92
  }
1✔
93

94
  private static final String PREFIX = "DUOS-";
95

96
  public Dataset(String objectId) {
×
97
    this.objectId = objectId;
×
98
  }
×
99

100
  public Integer getDatasetId() {
101
    return datasetId;
1✔
102
  }
103

104
  public void setDatasetId(Integer datasetId) {
105
    this.datasetId = datasetId;
1✔
106
  }
1✔
107

108
  public String getObjectId() {
109
    return objectId;
×
110
  }
111

112
  public void setObjectId(String objectId) {
113
    this.objectId = objectId;
1✔
114
  }
1✔
115

116
  public String getName() {
117
    return name;
1✔
118
  }
119

120
  public void setName(String name) {
121
    this.name = name;
1✔
122
  }
1✔
123

124
  public String getDatasetName() {
125
    return datasetName;
1✔
126
  }
127

128
  public void setDatasetName(String datasetName) {
129
    this.datasetName = datasetName;
1✔
130
  }
1✔
131

132
  public Date getCreateDate() {
133
    return createDate;
×
134
  }
135

136
  public void setCreateDate(Date createDate) {
137
    this.createDate = createDate;
1✔
138
  }
1✔
139

140
  public Integer getCreateUserId() {
141
    return createUserId;
1✔
142
  }
143

144
  public void setCreateUserId(Integer createUserId) {
145
    this.createUserId = createUserId;
1✔
146
  }
1✔
147

148
  public Date getUpdateDate() {
149
    return updateDate;
1✔
150
  }
151

152
  public void setUpdateDate(Date updateDate) {
153
    this.updateDate = updateDate;
1✔
154
  }
1✔
155

156
  public Integer getUpdateUserId() {
157
    return updateUserId;
1✔
158
  }
159

160
  public void setUpdateUserId(Integer updateUserId) {
161
    this.updateUserId = updateUserId;
1✔
162
  }
1✔
163

164
  public Set<DatasetProperty> getProperties() {
165
    return properties;
1✔
166
  }
167

168
  public List<String> getPropertyName() {
169
    return propertyName;
×
170
  }
171

172

173
  public void setProperties(Set<DatasetProperty> properties) {
174
    this.properties = properties;
1✔
175
  }
1✔
176

177
  public void addProperty(DatasetProperty property) {
178
    if (Objects.isNull(this.properties)) {
1✔
179
      this.properties = new HashSet<>();
1✔
180
    }
181
    this.properties.add(property);
1✔
182
  }
1✔
183

184
  public Boolean getDacApproval() {
185
    return dacApproval;
1✔
186
  }
187

188
  public void setDacApproval(Boolean dacApproval) {
189
    this.dacApproval = dacApproval;
1✔
190
  }
1✔
191

192
  public Integer getAlias() {
193
    return alias;
1✔
194
  }
195

196
  public void setAlias(Integer alias) {
197
    this.alias = alias;
1✔
198
  }
1✔
199

200
  public DataUse getDataUse() {
201
    return dataUse;
1✔
202
  }
203

204
  public void setDataUse(DataUse dataUse) {
205
    this.dataUse = dataUse;
1✔
206
  }
1✔
207

208
  public void setDatasetIdentifier() {
209
    this.datasetIdentifier = parseAliasToIdentifier(this.getAlias());
1✔
210
  }
1✔
211

212
  public String getDatasetIdentifier() {
213
    if (Objects.isNull(this.getAlias())) {
1✔
214
      return null;
1✔
215
    }
216

217
    return parseAliasToIdentifier(this.getAlias());
1✔
218
  }
219

220
  public static String parseAliasToIdentifier(Integer alias) {
221
    return PREFIX + StringUtils.leftPad(alias.toString(), 6, "0");
1✔
222
  }
223

224
  public static Integer parseIdentifierToAlias(String identifier) throws IllegalArgumentException {
225
    try {
226
      String givenPrefix = identifier.substring(0, PREFIX.length());
1✔
227
      if (!givenPrefix.equals(PREFIX)) {
1✔
228
        throw new IllegalArgumentException("Invalid prefix.");
1✔
229
      }
230

231
      String aliasAsString = identifier.substring(PREFIX.length()); // cut off DUOS-
1✔
232
      return Integer.parseInt(aliasAsString); // parse remaining as integer
1✔
233
    } catch (Exception e) {
1✔
234
      throw new IllegalArgumentException(
1✔
235
          "Could not parse identifier (" + identifier + "). Proper format: " + PREFIX + "XXXXXX");
236
    }
237
  }
238

239
  public Integer getDacId() {
240
    return dacId;
1✔
241
  }
242

243
  public void setDacId(Integer dacId) {
244
    this.dacId = dacId;
1✔
245
  }
1✔
246

247
  public String getTranslatedDataUse() {
248
    return translatedDataUse;
1✔
249
  }
250

251
  public void setTranslatedDataUse(String translatedDataUse) {
252
    this.translatedDataUse = translatedDataUse;
1✔
253
  }
1✔
254

255
  public Boolean getDeletable() {
256
    return deletable;
1✔
257
  }
258

259
  public void setDeletable(Boolean deletable) {
260
    this.deletable = deletable;
1✔
261
  }
1✔
262

263
  /**
264
   * Checks if the Dataset matches a raw search query. Searches on all dataset properties and some
265
   * data use properties. Has optional parameter accessManagement which will search datasets on both
266
   * the raw search query and the access management type.
267
   *
268
   * @param query            Raw string query
269
   * @param accessManagement One of controlled, open, or external
270
   * @return if the Dataset matched query
271
   */
272

273
  // TODO: investigate whether we can try to coerce getPropertyValue to a boolean instead of comparing strings
274
  public boolean isDatasetMatch(@NonNull String query, AccessManagement accessManagement) {
275
    String lowerCaseQuery = query.toLowerCase();
1✔
276
    List<String> queryTerms = List.of(lowerCaseQuery.split("\\s+"));
1✔
277

278
    List<String> matchTerms = new ArrayList<>();
1✔
279
    matchTerms.add(this.getName());
1✔
280
    matchTerms.add(this.getDatasetIdentifier());
1✔
281

282
    if (Objects.nonNull(getProperties()) && !getProperties().isEmpty()) {
1✔
283
      Optional<DatasetProperty> accessManagementProp = getProperties()
1✔
284
          .stream()
1✔
285
          .filter((dp) -> Objects.nonNull(dp.getPropertyValue()))
1✔
286
          .filter((dp) -> Objects.equals(dp.getPropertyName(), "Access Management"))
1✔
287
          .findFirst();
1✔
288

289
      if (accessManagementProp.isEmpty()) {
1✔
290
        if (accessManagement.equals(AccessManagement.OPEN)) {
1✔
291
          return false;
×
292
        }
293
      } else if (!accessManagement.toString()
1✔
294
          .equals(accessManagementProp.get().getPropertyValueAsString())) {
1✔
295
        return false;
1✔
296
      }
297

298
      List<String> propVals = getProperties()
1✔
299
          .stream()
1✔
300
          .filter((dp) -> Objects.nonNull(dp.getPropertyValue()))
1✔
301
          .map(DatasetProperty::getPropertyValueAsString)
1✔
302
          .map(String::toLowerCase)
1✔
303
          .toList();
1✔
304
      matchTerms.addAll(propVals);
1✔
305
    }
306

307
    if (Objects.nonNull(dataUse)) {
1✔
308
      if (Objects.nonNull(dataUse.getEthicsApprovalRequired())
1✔
309
          && dataUse.getEthicsApprovalRequired()) {
1✔
310
        matchTerms.add("irb");
1✔
311
      }
312

313
      if (Objects.nonNull(dataUse.getCollaboratorRequired())
1✔
314
          && dataUse.getCollaboratorRequired()) {
1✔
315
        matchTerms.add("collaborator");
1✔
316
      }
317

318
      if (Objects.nonNull(dataUse.getDiseaseRestrictions())) {
1✔
319
        matchTerms.addAll(dataUse.getDiseaseRestrictions());
1✔
320
      }
321
    }
322

323
    return queryTerms
1✔
324
        .stream()
1✔
325
        .filter(Objects::nonNull)
1✔
326
        // all terms must match at least one thing
327
        .allMatch((q) ->
1✔
328
            matchTerms
1✔
329
                .stream()
1✔
330
                .filter(Objects::nonNull)
1✔
331
                .map(String::toLowerCase)
1✔
332
                .anyMatch(
1✔
333
                    (t) -> t.contains(q))
1✔
334
        );
335
  }
336

337
  public Study getStudy() {
338
    return study;
1✔
339
  }
340

341
  public void setStudy(Study study) {
342
    this.study = study;
1✔
343
  }
1✔
344

345
  public Integer getStudyId() {
NEW
346
    return studyId;
×
347
  }
348

349
  public void setStudyId(Integer studyId) {
350
    this.studyId = studyId;
1✔
351
  }
1✔
352

353
  /**
354
   * Determine if the user is a dataset/study creator
355
   *
356
   * @param user User
357
   * @return User is a creator of the dataset/study
358
   */
359
  public boolean isCustodian(User user) {
360
    if (getStudy() != null && getStudy().getProperties() != null) {
1✔
361
      Optional<StudyProperty> dataCustodians = getStudy()
1✔
362
          .getProperties()
1✔
363
          .stream()
1✔
364
          .filter(p -> p.getKey().equals(DatasetRegistrationSchemaV1Builder.dataCustodianEmail))
1✔
365
          .findFirst();
1✔
366
      if (dataCustodians.isPresent()) {
1✔
367
        JsonArray jsonArray = (JsonArray) dataCustodians.get().getValue();
1✔
368
        return jsonArray.contains(new JsonPrimitive(user.getEmail()));
1✔
369
      } else {
370
        logWarn(
×
371
            "No data custodians found for dataset: %s".formatted(getDatasetIdentifier()));
×
372
      }
373
    } else {
×
374
      logWarn(
1✔
375
          "No study properties found for dataset: %s".formatted(getDatasetIdentifier()));
1✔
376
    }
377
    return false;
1✔
378
  }
379

380
  public boolean isCreator(User user) {
381
    if (Objects.equals(user.getUserId(), getCreateUserId())) {
1✔
382
      return true;
1✔
383
    }
384
    return getStudy() != null && Objects.equals(user.getUserId(),
1✔
385
        getStudy().getCreateUserId());
1✔
386
  }
387

388
  @Override
389
  public boolean equals(Object o) {
390
    if (this == o) {
1✔
391
      return true;
1✔
392
    }
393
    if (o == null || getClass() != o.getClass()) {
1✔
394
      return false;
×
395
    }
396
    Dataset dataset = (Dataset) o;
1✔
397
    return com.google.common.base.Objects.equal(datasetId, dataset.datasetId);
1✔
398
  }
399

400
  @Override
401
  public int hashCode() {
402
    return com.google.common.base.Objects.hashCode(datasetId);
1✔
403
  }
404

405
  public FileStorageObject getNihInstitutionalCertificationFile() {
406
    return nihInstitutionalCertificationFile;
1✔
407
  }
408

409
  public void setNihInstitutionalCertificationFile(
410
      FileStorageObject nihInstitutionalCertificationFile) {
411
    this.nihInstitutionalCertificationFile = nihInstitutionalCertificationFile;
1✔
412
  }
1✔
413

414
  public User getCreateUser() {
415
    return createUser;
1✔
416
  }
417

418
  public void setCreateUser(User createUser) {
419
    this.createUser = createUser;
1✔
420
  }
1✔
421

422
}
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

© 2026 Coveralls, Inc