Skip to content

Commit 8d2d991

Browse files
committed
feat(core): properly track createdAt and updatedAt values...
...for Resource and Version documents
1 parent 2e7c655 commit 8d2d991

File tree

9 files changed

+158
-57
lines changed

9 files changed

+158
-57
lines changed

core/com.b2international.snowowl.core.rest.tests/src/com/b2international/snowowl/core/rest/resource/ResourceApiTest.java

+76-45
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static org.assertj.core.groups.Tuple.tuple;
2626
import static org.hamcrest.Matchers.equalTo;
2727
import static org.hamcrest.Matchers.iterableWithSize;
28+
import static org.junit.Assert.assertEquals;
2829

2930
import java.util.List;
3031
import java.util.concurrent.TimeUnit;
@@ -36,9 +37,11 @@
3637

3738
import com.b2international.commons.exceptions.BadRequestException;
3839
import com.b2international.snowowl.core.Resource;
40+
import com.b2international.snowowl.core.codesystem.CodeSystem;
3941
import com.b2international.snowowl.core.codesystem.CodeSystemRequests;
4042
import com.b2international.snowowl.core.domain.IComponent;
4143
import com.b2international.snowowl.core.id.IDs;
44+
import com.b2international.snowowl.core.request.CommitResult;
4245
import com.b2international.snowowl.core.request.ResourceConverter;
4346
import com.b2international.snowowl.core.request.ResourceRequests;
4447
import com.b2international.snowowl.core.rest.BundleApiAssert;
@@ -66,6 +69,22 @@ public class ResourceApiTest {
6669
public static void setup() {
6770
bus = Services.bus();
6871
}
72+
73+
@After
74+
public void deleteAllResources() {
75+
ResourceRequests
76+
.prepareSearch()
77+
.buildAsync()
78+
.execute(Services.bus())
79+
.getSync(1, TimeUnit.MINUTES)
80+
.forEach(resource -> {
81+
ResourceRequests
82+
.prepareDelete(resource.getId())
83+
.build(RestExtensions.USER, "Delete " + resource.getId())
84+
.execute(Services.bus())
85+
.getSync(1, TimeUnit.MINUTES);
86+
});
87+
}
6988

7089
@Test
7190
public void noResourcesPresent() {
@@ -131,58 +150,42 @@ public void searchAfter() throws Exception {
131150
createDefaultCodeSystem(id1, oid1);
132151

133152
CodeSystemRequests.prepareSearchCodeSystem()
134-
.filterById(id1)
135-
.setSearchAfter("codesystem")
136-
.buildAsync()
137-
.execute(bus)
138-
.getSync();
153+
.filterById(id1)
154+
.setSearchAfter("codesystem")
155+
.buildAsync()
156+
.execute(bus)
157+
.getSync();
139158
}
140159

141160
private void createCodeSystemWithStatus(final String shortName, final String status) {
142-
CodeSystemRequests
143-
.prepareNewCodeSystem()
144-
.setId(shortName)
145-
.setTitle(shortName)
146-
.setUrl(SnomedTerminologyComponentConstants.SNOMED_URI_DEV + "/" + shortName)
147-
.setDescription(DEFAULT_CODE_SYSTEM_DESCRIPTION)
148-
.setLanguage(DEFAULT_CODE_SYSTEM_LANGUAGE)
149-
.setToolingId(DEFAULT_CODE_SYSTEM_TOOLING_ID)
150-
.setStatus(status)
151-
.setOid("https://b2i.sg/" + shortName)
152-
.build(RestExtensions.USER, String.format("New code system %s", shortName))
153-
.execute(bus).getSync();
161+
CodeSystemRequests.prepareNewCodeSystem()
162+
.setId(shortName)
163+
.setTitle(shortName)
164+
.setUrl(SnomedTerminologyComponentConstants.SNOMED_URI_DEV + "/" + shortName)
165+
.setDescription(DEFAULT_CODE_SYSTEM_DESCRIPTION)
166+
.setLanguage(DEFAULT_CODE_SYSTEM_LANGUAGE)
167+
.setToolingId(DEFAULT_CODE_SYSTEM_TOOLING_ID)
168+
.setStatus(status)
169+
.setOid("https://b2i.sg/" + shortName)
170+
.build(RestExtensions.USER, String.format("New code system %s", shortName))
171+
.execute(bus).getSync();
154172

155173
}
156174

157175
private void createDefaultCodeSystem(final String shortName, final String oid) {
158-
CodeSystemRequests
159-
.prepareNewCodeSystem()
160-
.setId(shortName)
161-
.setTitle(String.format("%s - %s", shortName, oid))
162-
.setUrl(SnomedTerminologyComponentConstants.SNOMED_URI_DEV + "/" + shortName)
163-
.setDescription(DEFAULT_CODE_SYSTEM_DESCRIPTION)
164-
.setLanguage(DEFAULT_CODE_SYSTEM_LANGUAGE)
165-
.setToolingId(DEFAULT_CODE_SYSTEM_TOOLING_ID)
166-
.setOid(oid).build(RestExtensions.USER, String.format("New code system %s", shortName))
167-
.execute(bus).getSync();
176+
CodeSystemRequests.prepareNewCodeSystem()
177+
.setId(shortName)
178+
.setTitle(String.format("%s - %s", shortName, oid))
179+
.setUrl(SnomedTerminologyComponentConstants.SNOMED_URI_DEV + "/" + shortName)
180+
.setDescription(DEFAULT_CODE_SYSTEM_DESCRIPTION)
181+
.setLanguage(DEFAULT_CODE_SYSTEM_LANGUAGE)
182+
.setToolingId(DEFAULT_CODE_SYSTEM_TOOLING_ID)
183+
.setOid(oid)
184+
.build(RestExtensions.USER, String.format("New code system %s", shortName))
185+
.execute(bus)
186+
.getSync();
168187
}
169188

170-
@After
171-
public void deleteAllResources() {
172-
ResourceRequests
173-
.prepareSearch()
174-
.buildAsync()
175-
.execute(Services.bus())
176-
.getSync(1, TimeUnit.MINUTES)
177-
.forEach(resource -> {
178-
ResourceRequests
179-
.prepareDelete(resource.getId())
180-
.build(RestExtensions.USER, "Delete " + resource.getId())
181-
.execute(Services.bus())
182-
.getSync(1, TimeUnit.MINUTES);
183-
});
184-
}
185-
186189
@Test
187190
public void sortByResourceTypeAsc() {
188191
final String id1 = "A";
@@ -217,8 +220,8 @@ public void sortByResourceTypeDesc() {
217220
BundleApiAssert.createBundle(BundleApiAssert.prepareBundleCreateRequestBody(id4));
218221

219222
assertResourceSearch(ImmutableMap.of("sort", ImmutableList.of("typeRank:desc", "title:asc")))
220-
.statusCode(200)
221-
.body("items.id", Matchers.contains(id1, id2, id3, id4));
223+
.statusCode(200)
224+
.body("items.id", Matchers.contains(id1, id2, id3, id4));
222225
}
223226

224227
@Test
@@ -239,4 +242,32 @@ public void expandPathLabels() {
239242
.body("resourcePathSegments", Matchers.contains(IComponent.ROOT_ID, rootBundleId, subBundleId))
240243
.body("resourcePathLabels", Matchers.contains(ResourceConverter.ROOT_LABEL, "Bundle " + rootBundleId, "Bundle " + subBundleId));
241244
}
245+
246+
@Test
247+
public void createdAtAndUpdatedAt() throws Exception {
248+
createDefaultCodeSystem(DEFAULT_CODE_SYSTEM_SHORT_NAME, DEFAULT_CODE_SYSTEM_OID);
249+
250+
// assert that createdAt and updatedAt values are the same after create
251+
CodeSystem createdCodeSystem = assertResourceGet(DEFAULT_CODE_SYSTEM_SHORT_NAME)
252+
.statusCode(200)
253+
.extract()
254+
.as(CodeSystem.class);
255+
assertEquals(createdCodeSystem.getCreatedAt(), createdCodeSystem.getUpdatedAt());
256+
257+
CommitResult updateResult = CodeSystemRequests.prepareUpdateCodeSystem(DEFAULT_CODE_SYSTEM_SHORT_NAME)
258+
.setCopyright("Updated copyright")
259+
.build(RestExtensions.USER, String.format("Updated copyright %s", DEFAULT_CODE_SYSTEM_SHORT_NAME))
260+
.execute(bus)
261+
.getSync();
262+
263+
// assert that createdAt and updatedAt values are the same after create
264+
CodeSystem updatedCodeSystem = assertResourceGet(DEFAULT_CODE_SYSTEM_SHORT_NAME)
265+
.statusCode(200)
266+
.extract()
267+
.as(CodeSystem.class);
268+
// createdAt stays as is, but updatedAt got updated to a time after the marked value
269+
assertEquals(createdCodeSystem.getCreatedAt(), updatedCodeSystem.getCreatedAt());
270+
assertEquals((Long) updateResult.getCommitTimestamp(), updatedCodeSystem.getUpdatedAt());
271+
}
272+
242273
}

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/Resource.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public static final class Fields {
4545
public static final String RESOURCE_TYPE = ResourceDocument.Fields.RESOURCE_TYPE;
4646
public static final String TYPE_RANK = ResourceDocument.Fields.TYPE_RANK;
4747
public static final String CREATED_AT = ResourceDocument.Fields.CREATED_AT;
48+
public static final String UPDATED_AT = ResourceDocument.Fields.UPDATED_AT;
4849

4950
// TerminologyResource subtype specific fields, but for convenience and single API access, they are defined here
5051
public static final String OID = ResourceDocument.Fields.OID;
@@ -58,6 +59,7 @@ public static final class Fields {
5859
OWNER,
5960
OID,
6061
CREATED_AT,
62+
UPDATED_AT,
6163
RESOURCE_TYPE,
6264
TYPE_RANK
6365
);
@@ -115,6 +117,9 @@ public static abstract class Expand {
115117
// The timestamp when the resource was created originally
116118
private Long createdAt;
117119

120+
// The timestamp when the resource was last modified (either its contents or its properties)
121+
private Long updatedAt;
122+
118123
/**
119124
* @return the type of the resource
120125
*/
@@ -258,13 +263,21 @@ public String getBundleId() {
258263
public void setBundleId(String bundleId) {
259264
this.bundleId = bundleId;
260265
}
266+
267+
public Long getCreatedAt() {
268+
return createdAt;
269+
}
261270

262271
public void setCreatedAt(Long createdAt) {
263272
this.createdAt = createdAt;
264273
}
265274

266-
public Long getCreatedAt() {
267-
return createdAt;
275+
public Long getUpdatedAt() {
276+
return updatedAt;
277+
}
278+
279+
public void setUpdatedAt(Long updatedAt) {
280+
this.updatedAt = updatedAt;
268281
}
269282

270283
/**

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/bundle/Bundle.java

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public static Bundle from(ResourceDocument doc) {
104104
bundle.setBundleAncestorIds(doc.getBundleAncestorIds());
105105
bundle.setBundleId(doc.getBundleId());
106106
bundle.setCreatedAt(doc.getCreatedAt());
107+
bundle.setUpdatedAt(doc.getUpdatedAt());
107108
return bundle;
108109
}
109110
}

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/codesystem/CodeSystem.java

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public static CodeSystem from(ResourceDocument doc) {
7979
codeSystem.setBundleAncestorIds(doc.getBundleAncestorIds());
8080
codeSystem.setBundleId(doc.getBundleId());
8181
codeSystem.setCreatedAt(doc.getCreatedAt());
82+
codeSystem.setUpdatedAt(doc.getUpdatedAt());
8283
codeSystem.setOid(doc.getOid());
8384
codeSystem.setBranchPath(doc.getBranchPath());
8485
codeSystem.setToolingId(doc.getToolingId());

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/internal/ResourceDocument.java

+26-3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public static final class Fields extends RevisionDocument.Fields {
8686
public static final String USAGE = "usage";
8787
public static final String PURPOSE = "purpose";
8888
public static final String CREATED_AT = "createdAt";
89+
public static final String UPDATED_AT = "updatedAt";
8990
public static final String BUNDLE_ANCESTOR_IDS = "bundleAncestorIds";
9091
public static final String BUNDLE_ID = "bundleId";
9192

@@ -113,6 +114,7 @@ public static final class Fields extends RevisionDocument.Fields {
113114
OWNER,
114115
USAGE,
115116
CREATED_AT,
117+
UPDATED_AT,
116118
BUNDLE_ID,
117119
OID,
118120
BRANCH_PATH,
@@ -272,7 +274,9 @@ public static Builder builder(ResourceDocument from) {
272274
.toolingId(from.getToolingId())
273275
.extensionOf(from.getExtensionOf())
274276
.upgradeOf(from.getUpgradeOf())
275-
.settings(from.getSettings());
277+
.settings(from.getSettings())
278+
.createdAt(from.getCreatedAt())
279+
.updatedAt(from.getUpdatedAt());
276280
}
277281

278282
/**
@@ -306,6 +310,7 @@ public static final class Builder extends RevisionDocument.RevisionDocumentBuild
306310

307311
// derived fields, access only
308312
private Long createdAt;
313+
private Long updatedAt;
309314

310315
@JsonCreator
311316
private Builder() {
@@ -412,6 +417,11 @@ Builder createdAt(Long createdAt) {
412417
return getSelf();
413418
}
414419

420+
public Builder updatedAt(Long updatedAt) {
421+
this.updatedAt = updatedAt;
422+
return getSelf();
423+
}
424+
415425
@Override
416426
protected Builder getSelf() {
417427
return this;
@@ -441,7 +451,8 @@ public ResourceDocument build() {
441451
extensionOf,
442452
upgradeOf,
443453
settings,
444-
createdAt
454+
createdAt,
455+
updatedAt
445456
);
446457
}
447458

@@ -480,6 +491,7 @@ public ResourceDocument build() {
480491

481492
// derived fields, getters only, mapping generation requires a field to be specified
482493
private final Long createdAt;
494+
private final Long updatedAt;
483495

484496
// mapping only field, no actual purpose or use, required to support multi-index search with doc type VersionDocument
485497
@SuppressWarnings("unused")
@@ -507,7 +519,8 @@ public ResourceDocument(
507519
final ResourceURI extensionOf,
508520
final ResourceURI upgradeOf,
509521
final Map<String, Object> settings,
510-
final Long createdAt) {
522+
final Long createdAt,
523+
final Long updatedAt) {
511524
super(id, iconId);
512525
this.resourceType = resourceType;
513526
this.url = url;
@@ -529,6 +542,7 @@ public ResourceDocument(
529542
this.upgradeOf = upgradeOf;
530543
this.settings = settings;
531544
this.createdAt = createdAt;
545+
this.updatedAt = updatedAt;
532546
}
533547

534548
@JsonIgnore
@@ -613,8 +627,17 @@ public Map<String, Object> getSettings() {
613627
}
614628

615629
public Long getCreatedAt() {
630+
// XXX this is to get the createdAt value from the first commit timestamp and store it here on the doc
616631
return Optional.ofNullable(createdAt)
617632
.or(() -> Optional.ofNullable(getCreated()).map(RevisionBranchPoint::getTimestamp))
618633
.orElse(null);
619634
}
635+
636+
public Long getUpdatedAt() {
637+
// XXX same as createdAt, the first value is stored from commit timestamp and explicitly cleared on resource updates (see BaseResourceUpdateRequest.execute)
638+
return Optional.ofNullable(updatedAt)
639+
.or(() -> Optional.ofNullable(getCreated()).map(RevisionBranchPoint::getTimestamp))
640+
.orElse(null);
641+
}
642+
620643
}

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/BaseResourceUpdateRequest.java

+2
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ public final Boolean execute(TransactionContext context) {
175175
changed |= updateProperty(purpose, resource::getPurpose, updated::purpose);
176176

177177
if (changed) {
178+
// make sure we null out the updatedAt property we before update
179+
updated.updatedAt(null);
178180
context.update(resource, updated.build());
179181
}
180182

core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/version/VersionCreateRequest.java

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ public Boolean execute(RepositoryContext context) {
193193
.branchPath(resourceToVersion.getRelativeBranchPath(version))
194194
.author(user)
195195
.createdAt(Instant.now().toEpochMilli())
196+
.updatedAt(Instant.now().toEpochMilli())
196197
.toolingId(resourceToVersion.getToolingId())
197198
.url(buildVersionUrl(context, resourceToVersion))
198199
.build());

0 commit comments

Comments
 (0)