Skip to content

Commit 2ea0b28

Browse files
authored
chore: adding UUID scalar (#55)
NOTE: added an equals verify test which suggests overriding `hashcode` also refs: #4 fixes: #52
1 parent e7ce5b1 commit 2ea0b28

File tree

3 files changed

+266
-0
lines changed

3 files changed

+266
-0
lines changed

Diff for: lib/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies {
4040
testImplementation('org.junit.jupiter:junit-jupiter-api:5.10.0')
4141
testImplementation('org.mockito:mockito-core:5.4.0')
4242
testImplementation('org.mockito:mockito-junit-jupiter:5.4.0')
43+
testImplementation('nl.jqno.equalsverifier:equalsverifier:3.15')
4344
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.10.0')
4445

4546
testImplementation 'org.assertj:assertj-core:3.24.2'

Diff for: lib/src/main/java/io/cloudquery/scalar/UUID.java

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package io.cloudquery.scalar;
2+
3+
import org.apache.arrow.vector.types.pojo.ArrowType;
4+
import org.apache.arrow.vector.types.pojo.ArrowType.FixedSizeBinary;
5+
6+
import java.nio.ByteBuffer;
7+
import java.util.Objects;
8+
9+
public class UUID implements Scalar {
10+
private static final int BYTE_WIDTH = 16;
11+
private static final FixedSizeBinary dt = new FixedSizeBinary(BYTE_WIDTH);
12+
13+
private java.util.UUID value;
14+
15+
public UUID() {
16+
}
17+
18+
public UUID(Object value) throws ValidationException {
19+
this.set(value);
20+
}
21+
22+
@Override
23+
public boolean isValid() {
24+
return this.value != null;
25+
}
26+
27+
@Override
28+
public ArrowType dataType() {
29+
return dt;
30+
}
31+
32+
@Override
33+
public void set(Object value) throws ValidationException {
34+
if (value == null) {
35+
this.value = null;
36+
return;
37+
}
38+
39+
if (value instanceof Scalar scalar) {
40+
if (!scalar.isValid()) {
41+
this.value = null;
42+
return;
43+
}
44+
45+
if (scalar instanceof UUID uuid) {
46+
this.value = uuid.value;
47+
return;
48+
}
49+
50+
this.set(scalar.get());
51+
return;
52+
}
53+
54+
if (value instanceof java.util.UUID uuid) {
55+
this.value = uuid;
56+
return;
57+
}
58+
59+
if (value instanceof CharSequence sequence) {
60+
this.value = java.util.UUID.fromString(sequence.toString());
61+
return;
62+
}
63+
64+
if (value instanceof byte[] b) {
65+
if (b.length != BYTE_WIDTH) {
66+
throw new ValidationException("[]byte must be " + BYTE_WIDTH + " bytes to convert to UUID", this.dataType(), b);
67+
}
68+
ByteBuffer byteBuffer = ByteBuffer.wrap(b);
69+
long mostSig = byteBuffer.getLong();
70+
long leastSig = byteBuffer.getLong();
71+
this.value = new java.util.UUID(mostSig, leastSig);
72+
return;
73+
}
74+
75+
throw new ValidationException(ValidationException.NO_CONVERSION_AVAILABLE, this.dataType(), value);
76+
}
77+
78+
@Override
79+
public Object get() {
80+
return this.value;
81+
}
82+
83+
@Override
84+
public final boolean equals(Object other) {
85+
if (other instanceof UUID o) {
86+
return this.value == o.value || Objects.equals(this.value, o.value);
87+
}
88+
return false;
89+
}
90+
91+
@Override
92+
public final int hashCode() {
93+
return Objects.hash(value);
94+
}
95+
96+
@Override
97+
public String toString() {
98+
if (this.value != null) {
99+
return this.value.toString();
100+
}
101+
return NULL_VALUE_STRING;
102+
}
103+
}

Diff for: lib/src/test/java/io/cloudquery/scalar/UUIDTest.java

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package io.cloudquery.scalar;
2+
3+
import nl.jqno.equalsverifier.EqualsVerifier;
4+
import nl.jqno.equalsverifier.Warning;
5+
import org.apache.arrow.vector.types.pojo.ArrowType;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
9+
import static org.junit.jupiter.api.Assertions.assertEquals;
10+
import static org.junit.jupiter.api.Assertions.assertFalse;
11+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
12+
import static org.junit.jupiter.api.Assertions.assertNull;
13+
import static org.junit.jupiter.api.Assertions.assertThrows;
14+
import static org.junit.jupiter.api.Assertions.assertTrue;
15+
16+
public class UUIDTest {
17+
private static final byte[] COMPLETE_BYTE_SEQUENCE = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
18+
private static final byte[] INCOMPLETE_BYTE_SEQUENCE = {1, 2, 3, 4};
19+
20+
@Test
21+
public void testNew() {
22+
assertDoesNotThrow(() -> {
23+
new UUID();
24+
});
25+
}
26+
27+
@Test
28+
public void testNewWithValidParam() {
29+
assertDoesNotThrow(() -> {
30+
new UUID("123e4567-e89b-12d3-a456-426614174000");
31+
new UUID(java.util.UUID.randomUUID());
32+
new UUID(COMPLETE_BYTE_SEQUENCE);
33+
34+
Scalar s = new UUID(java.util.UUID.randomUUID());
35+
new UUID(s);
36+
}
37+
);
38+
}
39+
40+
@Test
41+
public void testNewWithInvalidParam() {
42+
assertThrows(ValidationException.class, () -> {
43+
new UUID(false);
44+
});
45+
46+
assertThrows(ValidationException.class, () -> {
47+
new UUID(INCOMPLETE_BYTE_SEQUENCE);
48+
});
49+
}
50+
51+
@Test
52+
public void testToString() {
53+
UUID uuid = new UUID();
54+
assertEquals(Scalar.NULL_VALUE_STRING, uuid.toString());
55+
56+
java.util.UUID u = java.util.UUID.randomUUID();
57+
assertDoesNotThrow(() -> {
58+
uuid.set(u);
59+
});
60+
assertEquals(u.toString(), uuid.toString());
61+
62+
assertDoesNotThrow(() -> {
63+
uuid.set(u.toString());
64+
});
65+
assertEquals(u.toString(), uuid.toString());
66+
}
67+
68+
@Test
69+
public void testDataType() {
70+
UUID uuid = new UUID();
71+
assertEquals(new ArrowType.FixedSizeBinary(16), uuid.dataType());
72+
}
73+
74+
@Test
75+
public void testIsValid() {
76+
UUID uuid = new UUID();
77+
assertFalse(uuid.isValid());
78+
79+
assertDoesNotThrow(() -> {
80+
uuid.set(java.util.UUID.randomUUID());
81+
});
82+
assertTrue(uuid.isValid());
83+
}
84+
85+
@Test
86+
public void testSet() {
87+
UUID uuid = new UUID();
88+
assertDoesNotThrow(() -> {
89+
uuid.set("123e4567-e89b-12d3-a456-426614174000");
90+
uuid.set(java.util.UUID.randomUUID());
91+
uuid.set(COMPLETE_BYTE_SEQUENCE);
92+
93+
Scalar s = new UUID(java.util.UUID.randomUUID());
94+
uuid.set(s);
95+
});
96+
}
97+
98+
@Test
99+
public void testSetWithInvalidParam() {
100+
UUID uuid = new UUID();
101+
assertThrows(ValidationException.class, () -> {
102+
uuid.set(false);
103+
});
104+
assertThrows(ValidationException.class, () -> {
105+
uuid.set(INCOMPLETE_BYTE_SEQUENCE);
106+
});
107+
}
108+
109+
@Test
110+
public void testGet() {
111+
UUID uuid = new UUID();
112+
assertFalse(uuid.isValid());
113+
assertNull(uuid.get());
114+
115+
java.util.UUID u = java.util.UUID.randomUUID();
116+
assertDoesNotThrow(() -> {
117+
uuid.set(u);
118+
});
119+
assertTrue(uuid.isValid());
120+
assertEquals(u, uuid.get());
121+
}
122+
123+
@Test
124+
public void testEquals() {
125+
UUID uuid1 = new UUID();
126+
UUID uuid2 = new UUID();
127+
128+
assertEquals(uuid1, uuid2);
129+
assertNotEquals(uuid1, null);
130+
assertNotEquals(uuid1, new Bool());
131+
assertNotEquals(null, uuid1);
132+
133+
assertDoesNotThrow(() -> {
134+
uuid1.set(java.util.UUID.randomUUID());
135+
});
136+
assertNotEquals(uuid1, uuid2);
137+
138+
java.util.UUID u = java.util.UUID.randomUUID();
139+
assertDoesNotThrow(() -> {
140+
uuid1.set(u);
141+
assertEquals(uuid1, new UUID(u));
142+
});
143+
}
144+
145+
@Test
146+
public void testCorrectEndianBehaviour() {
147+
String expectUUID = "00010203-0405-0607-0809-0a0b0c0d0e0f";
148+
149+
UUID uuid = new UUID();
150+
assertDoesNotThrow(() -> {
151+
uuid.set(COMPLETE_BYTE_SEQUENCE);
152+
assertEquals(expectUUID, uuid.toString());
153+
});
154+
}
155+
156+
@Test
157+
public void equalsContractVerification() {
158+
EqualsVerifier.forClass(UUID.class).
159+
suppress(Warning.NONFINAL_FIELDS). // Scalar classes are intentionally mutable
160+
verify();
161+
}
162+
}

0 commit comments

Comments
 (0)