feat(wcs): add shared domain contracts
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
package com.ruoyi.wcs.domain.shared;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class DomainEvent {
|
||||||
|
private final String eventId;
|
||||||
|
private final String aggregateId;
|
||||||
|
private final long sequence;
|
||||||
|
private final Instant occurredAt;
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
public DomainEvent(String eventId, String aggregateId, long sequence,
|
||||||
|
Instant occurredAt, String type) {
|
||||||
|
this.eventId = requireText(eventId, "eventId");
|
||||||
|
this.aggregateId = requireText(aggregateId, "aggregateId");
|
||||||
|
if (sequence < 1L) {
|
||||||
|
throw new IllegalArgumentException("sequence must be positive");
|
||||||
|
}
|
||||||
|
this.sequence = sequence;
|
||||||
|
this.occurredAt = Objects.requireNonNull(occurredAt, "occurredAt");
|
||||||
|
this.type = requireText(type, "type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEventId() {
|
||||||
|
return eventId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAggregateId() {
|
||||||
|
return aggregateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSequence() {
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getOccurredAt() {
|
||||||
|
return occurredAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requireText(String value, String field) {
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException(field + " must not be blank");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ruoyi.wcs.domain.shared;
|
||||||
|
|
||||||
|
public final class DomainRuleViolation extends RuntimeException {
|
||||||
|
public DomainRuleViolation(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ruoyi.wcs.domain.shared;
|
||||||
|
|
||||||
|
public interface IdGenerator {
|
||||||
|
String nextId();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ruoyi.wcs.domain.shared;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public interface WcsClock {
|
||||||
|
Instant now();
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.ruoyi.wcs.domain.shared;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
class SharedContractsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectsBlankEventIdentity() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () ->
|
||||||
|
new DomainEvent("", "ORDER-1", 1L, Instant.EPOCH, "OrderAccepted"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectsInvalidEventSequence() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () ->
|
||||||
|
new DomainEvent("E-1", "ORDER-1", 0L, Instant.EPOCH, "OrderAccepted"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void exposesDeterministicEventFields() {
|
||||||
|
Instant occurredAt = Instant.parse("2026-08-04T00:00:00Z");
|
||||||
|
DomainEvent event = new DomainEvent("E-1", "ORDER-1", 2L,
|
||||||
|
occurredAt, "OrderPlanned");
|
||||||
|
|
||||||
|
assertEquals("E-1", event.getEventId());
|
||||||
|
assertEquals("ORDER-1", event.getAggregateId());
|
||||||
|
assertEquals(2L, event.getSequence());
|
||||||
|
assertEquals(occurredAt, event.getOccurredAt());
|
||||||
|
assertEquals("OrderPlanned", event.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user