Skip to content

Commit 4220e92

Browse files
authored
feat: Scalar Timestamp (#46)
Closes #44
1 parent ef7c613 commit 4220e92

File tree

2 files changed

+251
-0
lines changed

2 files changed

+251
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.cloudquery.scalar;
2+
3+
import org.apache.arrow.vector.types.TimeUnit;
4+
import org.apache.arrow.vector.types.pojo.ArrowType;
5+
6+
import java.time.*;
7+
8+
public class Timestamp implements Scalar {
9+
public static final ZoneId zoneID = ZoneOffset.UTC;
10+
11+
// TODO: add more units support later
12+
private static final ArrowType dt = new ArrowType.Timestamp(TimeUnit.MILLISECOND, zoneID.toString());
13+
14+
protected ZonedDateTime value;
15+
16+
public Timestamp() {
17+
}
18+
19+
public Timestamp(Object value) throws ValidationException {
20+
this.set(value);
21+
}
22+
23+
@Override
24+
public String toString() {
25+
if (this.value != null) {
26+
return this.value.toString();
27+
}
28+
return NULL_VALUE_STRING;
29+
}
30+
31+
@Override
32+
public boolean isValid() {
33+
return this.value != null;
34+
}
35+
36+
@Override
37+
public ArrowType dataType() {
38+
return dt;
39+
}
40+
41+
@Override
42+
public void set(Object value) throws ValidationException {
43+
if (value == null) {
44+
this.value = null;
45+
return;
46+
}
47+
48+
if (value instanceof Scalar scalar) {
49+
if (!scalar.isValid()) {
50+
this.value = null;
51+
return;
52+
}
53+
54+
if (scalar instanceof Timestamp Timestamp) {
55+
this.value = Timestamp.value;
56+
return;
57+
}
58+
59+
this.set(scalar.get());
60+
return;
61+
}
62+
63+
if (value instanceof ZonedDateTime timestamp) {
64+
this.value = timestamp.withZoneSameInstant(zoneID);
65+
return;
66+
}
67+
68+
if (value instanceof LocalDate date) {
69+
this.value = date.atStartOfDay(zoneID);
70+
return;
71+
}
72+
73+
if (value instanceof LocalDateTime date) {
74+
this.value = date.atZone(zoneID);
75+
return;
76+
}
77+
78+
if (value instanceof Integer integer) {
79+
this.value = ZonedDateTime.ofInstant(Instant.ofEpochMilli(integer), ZoneOffset.UTC);
80+
return;
81+
}
82+
83+
if (value instanceof Long longValue) {
84+
this.value = ZonedDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneOffset.UTC);
85+
return;
86+
}
87+
88+
if (value instanceof CharSequence sequence) {
89+
this.value = ZonedDateTime.parse(sequence);
90+
return;
91+
}
92+
93+
throw new ValidationException(ValidationException.NO_CONVERSION_AVAILABLE, this.dataType(), value);
94+
}
95+
96+
@Override
97+
public Object get() {
98+
return this.value; // null or proper value
99+
}
100+
101+
@Override
102+
public boolean equals(Object other) {
103+
if (other == null) {
104+
return false;
105+
}
106+
107+
if (!(other instanceof Timestamp o)) {
108+
return false;
109+
}
110+
111+
return this.value == o.value || this.value.equals(o.value);
112+
}
113+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package io.cloudquery.scalar;
2+
3+
import org.apache.arrow.vector.types.TimeUnit;
4+
import org.apache.arrow.vector.types.pojo.ArrowType;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.time.Instant;
8+
import java.time.ZoneOffset;
9+
import java.time.ZonedDateTime;
10+
11+
import static org.junit.jupiter.api.Assertions.*;
12+
13+
14+
public class TimestampTest {
15+
@Test
16+
public void testNew() {
17+
assertDoesNotThrow(() -> {
18+
new Timestamp();
19+
});
20+
}
21+
22+
@Test
23+
public void testNewWithValidParam() {
24+
assertDoesNotThrow(() -> {
25+
new Timestamp(1);
26+
new Timestamp("2011-12-03T10:15:30+01:00[Europe/Paris]");
27+
new Timestamp(ZonedDateTime.now());
28+
29+
Scalar s = new Timestamp(ZonedDateTime.now());
30+
new Timestamp(s);
31+
});
32+
}
33+
34+
@Test
35+
public void testNewWithInvalidParam() {
36+
assertThrows(ValidationException.class, () -> {
37+
new Timestamp(false);
38+
});
39+
}
40+
41+
@Test
42+
public void testToString() {
43+
Timestamp timestamp = new Timestamp();
44+
assertEquals(Scalar.NULL_VALUE_STRING, timestamp.toString());
45+
46+
assertDoesNotThrow(() -> {
47+
timestamp.set(1);
48+
});
49+
assertEquals("1970-01-01T00:00:00.001Z", timestamp.toString());
50+
51+
String ts = ZonedDateTime.now(ZoneOffset.UTC).toString();
52+
assertDoesNotThrow(() -> {
53+
timestamp.set(ts);
54+
});
55+
assertEquals(ts, timestamp.toString());
56+
}
57+
58+
@Test
59+
public void testDataType() {
60+
Timestamp timestamp = new Timestamp();
61+
assertEquals(new ArrowType.Timestamp(TimeUnit.MILLISECOND, "Z"), timestamp.dataType());
62+
}
63+
64+
@Test
65+
public void testIsValid() {
66+
Timestamp timestamp = new Timestamp();
67+
assertFalse(timestamp.isValid());
68+
69+
assertDoesNotThrow(() -> {
70+
timestamp.set(1L);
71+
});
72+
assertTrue(timestamp.isValid());
73+
}
74+
75+
@Test
76+
public void testSet() {
77+
Timestamp timestamp = new Timestamp();
78+
assertDoesNotThrow(() -> {
79+
timestamp.set(1);
80+
timestamp.set(1L);
81+
timestamp.set("2011-12-03T10:15:30+01:00[Europe/Paris]");
82+
timestamp.set(ZonedDateTime.now());
83+
84+
Scalar s = new Timestamp(ZonedDateTime.now());
85+
timestamp.set(s);
86+
});
87+
}
88+
89+
@Test
90+
public void testSetWithInvalidParam() {
91+
Timestamp timestamp = new Timestamp();
92+
assertThrows(ValidationException.class, () -> {
93+
timestamp.set(false);
94+
});
95+
}
96+
97+
@Test
98+
public void testGet() {
99+
Timestamp timestamp = new Timestamp();
100+
assertFalse(timestamp.isValid());
101+
assertNull(timestamp.get());
102+
103+
ZonedDateTime ts = ZonedDateTime.now(ZoneOffset.UTC);
104+
assertDoesNotThrow(() -> {
105+
timestamp.set(ts);
106+
});
107+
assertTrue(timestamp.isValid());
108+
assertEquals(ts, timestamp.get());
109+
110+
assertDoesNotThrow(() -> {
111+
timestamp.set(0);
112+
});
113+
assertTrue(timestamp.isValid());
114+
assertEquals(Instant.EPOCH.atZone(ZoneOffset.UTC), timestamp.get());
115+
}
116+
117+
@Test
118+
public void testEquals() {
119+
Timestamp a = new Timestamp();
120+
Timestamp b = new Timestamp();
121+
assertEquals(a, b);
122+
assertNotEquals(a, null);
123+
assertNotEquals(a, new Bool()); // we can't cast Bool to Timestamp
124+
assertNotEquals(null, a);
125+
126+
assertDoesNotThrow(() -> {
127+
a.set(-1L);
128+
});
129+
assertNotEquals(a, b);
130+
131+
assertDoesNotThrow(() -> {
132+
for (Object obj : new Object[]{null, 0, 0L, -1, -1L, 1, 1L, "1970-01-01T00:00:00.001Z", Instant.EPOCH.atZone(ZoneOffset.UTC)}) {
133+
a.set(obj);
134+
assertEquals(a, new Timestamp(obj));
135+
}
136+
});
137+
}
138+
}

0 commit comments

Comments
 (0)