Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clickhouse-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
<artifactId>caffeine</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>dnsjava</groupId>
<artifactId>dnsjava</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,29 @@ public static BigDecimal between(BigDecimal value, String name, BigDecimal minVa
* @param value the string to check
* @return true if the string is null or empty; false otherwise
*/
public static boolean isNullOrEmpty(String value) {
return value == null || value.isEmpty();
public static boolean isNullOrEmpty(CharSequence value) {
return value == null || value.length() == 0;
}

/**
* Checks if the given string is null, empty string or a string only contains
* white spaces.
*
* @param value the string to check
* @return true if the string is null, empty or blank; false otherwise
*/
public static boolean isNullOrBlank(CharSequence value) {
if (isNullOrEmpty(value)) {
return true;
}

for (int i = 0, len = value.length(); i < len; i++) {
if (!Character.isWhitespace(value.charAt(i))) {
return false;
}
}

return true;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.clickhouse.client.data;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import com.google.gson.Gson;

import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

/**
* Utility class for reading and writing objects in JSON format.
*/
public final class JsonStreamUtils {
private static final Gson gson = new Gson();

public static <T> T readObject(InputStream input, Class<T> clazz) throws IOException {
return readObject(input, StandardCharsets.UTF_8, clazz);
}

public static <T> T readObject(InputStream input, Charset charset, Class<T> clazz) throws IOException {
return readObject(new InputStreamReader(input, charset), clazz);
}

public static <T> T readObject(Reader reader, Class<T> clazz) throws IOException {
return gson.fromJson(reader, clazz);
}

public static <T> T readObject(String json, Class<T> clazz) throws IOException {
return gson.fromJson(json, clazz);
}

public static <T> void writeObject(OutputStream output, T object) throws IOException {
writeObject(output, StandardCharsets.UTF_8, object);
}

public static <T> void writeObject(OutputStream output, Charset charset, T object) throws IOException {
OutputStreamWriter writer = new OutputStreamWriter(output, charset);
writeObject(writer, object);
writer.flush();
}

public static <T> void writeObject(Writer writer, T object) throws IOException {
gson.toJson(object, object == null ? Object.class : object.getClass(), gson.newJsonWriter(writer));
}

public static String toJsonString(Object object) {
return gson.toJson(object);
}

private JsonStreamUtils() {
}
}
4 changes: 3 additions & 1 deletion clickhouse-client/src/main/java9/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
com.clickhouse.client.postgresql,
// native is a reserved keyword :<
com.clickhouse.client.tcp,
com.clickhouse.jdbc;
com.clickhouse.jdbc,
ru.yandex.clickhouse;

requires java.base;

requires static java.logging;
requires static com.google.gson;
requires static com.github.benmanes.caffeine;
requires static org.dnsjava;
requires static org.lz4.java;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,21 @@ public void testBetween() {
@Test(groups = { "unit" })
public void testIsNullOrEmpty() {
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(null));
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(new StringBuilder()));
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(new StringBuffer()));
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(""));
Assert.assertFalse(ClickHouseChecker.isNullOrEmpty(" "));
}

@Test(groups = { "unit" })
public void testIsNullOrBlank() {
Assert.assertTrue(ClickHouseChecker.isNullOrBlank(null));
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(new StringBuilder()));
Assert.assertTrue(ClickHouseChecker.isNullOrEmpty(new StringBuffer()));
Assert.assertTrue(ClickHouseChecker.isNullOrBlank(""));
Assert.assertTrue(ClickHouseChecker.isNullOrBlank(" \t\r\n "));
}

@Test(groups = { "unit" })
public void testNonEmpty() {
Assert.assertEquals(ClickHouseChecker.nonEmpty(" ", "value"), " ");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
package com.clickhouse.client.data;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Collections;
import java.util.List;

import org.testng.Assert;
import org.testng.annotations.Test;

public class JsonStreamUtilsTest {
static class JsonCompactResponse {
private List<Meta> meta;
private List<List<String>> data;
private List<String> totals;
private Extremes extremes;
private int rows;
private int rows_before_limit_at_least;

public static class Extremes {
private List<String> min;
private List<String> max;

public List<String> getMin() {
return min;
}

public void setMin(List<String> min) {
this.min = min;
}

public List<String> getMax() {
return max;
}

public void setMax(List<String> max) {
this.max = max;
}
}

public static class Meta {
private String name;
private String type;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

@Override
public String toString() {
return "Meta{" + "name='" + name + '\'' + ", type='" + type + '\'' + '}';
}
}

public Extremes getExtremes() {
return extremes;
}

public void setExtremes(Extremes extremes) {
this.extremes = extremes;
}

public List<Meta> getMeta() {
return meta;
}

public void setMeta(List<Meta> meta) {
this.meta = meta;
}

public List<List<String>> getData() {
return data;
}

public void setData(List<List<String>> data) {
this.data = data;
}

public int getRows() {
return rows;
}

public void setRows(int rows) {
this.rows = rows;
}

public int getRows_before_limit_at_least() {
return rows_before_limit_at_least;
}

public void setRows_before_limit_at_least(int rows_before_limit_at_least) {
this.rows_before_limit_at_least = rows_before_limit_at_least;
}

public List<String> getTotals() {
return totals;
}

public void setTotals(List<String> totals) {
this.totals = totals;
}

@Override
public String toString() {
return "ClickHouseResponse{" + "meta=" + meta + ", data=" + data + ", rows=" + rows
+ ", rows_before_limit_at_least=" + rows_before_limit_at_least + '}';
}
}

static class JsonResponseSummary {
private final long read_rows; // number of read rows for selects (may be more than rows in result set)
private final long written_rows; // number of written rows for inserts
private final long read_bytes;
private final long written_bytes;
private final long total_rows_to_read;

public JsonResponseSummary(long read_rows, long written_rows, long read_bytes, long written_bytes,
long total_rows_to_read) {
this.read_rows = read_rows;
this.written_rows = written_rows;
this.read_bytes = read_bytes;
this.written_bytes = written_bytes;
this.total_rows_to_read = total_rows_to_read;
}

public long getReadRows() {
return read_rows;
}

public long getWrittenRows() {
return written_rows;
}

public long getReadBytes() {
return read_bytes;
}

public long getWrittenBytes() {
return written_bytes;
}

public long getTotalRowsToRead() {
return total_rows_to_read;
}
}

@Test(groups = { "unit" })
public void testReadObject() throws IOException {
Assert.assertThrows(NullPointerException.class,
() -> JsonStreamUtils.readObject((InputStream) null, JsonCompactResponse.class));
Assert.assertThrows(NullPointerException.class,
() -> JsonStreamUtils.readObject((Reader) null, JsonCompactResponse.class));

Assert.assertNull(JsonStreamUtils.readObject((String) null, JsonCompactResponse.class));
Assert.assertNull(JsonStreamUtils.readObject("", JsonCompactResponse.class));
Assert.assertNull(JsonStreamUtils.readObject(new ByteArrayInputStream(new byte[0]), JsonCompactResponse.class));

JsonCompactResponse r = JsonStreamUtils.readObject("{}", JsonCompactResponse.class);
Assert.assertNotNull(r);
Assert.assertNull(r.getMeta());
Assert.assertNull(r.getData());
Assert.assertNull(r.getTotals());
Assert.assertNull(r.getExtremes());
Assert.assertEquals(r.getRows(), 0);
Assert.assertEquals(r.getRows_before_limit_at_least(), 0);

// set extremes=1
// select 123 as a group by a with totals limit 5 format JSONCompact
String json = "{\"meta\":[{\"name\":\"123\",\"type\":\"UInt8\"}],\"data\":[[123]],\"totals\":[123],"
+ "\"extremes\":{\"min\":[123],\"max\":[123]},\"rows\":1,\"rows_before_limit_at_least\":1,"
+ "\"statistics\":{\"elapsed\":0.0008974,\"rows_read\":1,\"bytes_read\":1}}";

r = JsonStreamUtils.readObject(new ByteArrayInputStream(json.getBytes()), JsonCompactResponse.class);
Assert.assertNotNull(r);
Assert.assertEquals(r.getMeta().size(), 1);
Assert.assertEquals(r.getMeta().get(0).toString(), "Meta{name='123\', type='UInt8\'}");

Assert.assertEquals(r.getData().size(), 1);
Assert.assertEquals(r.getData().get(0), Collections.singleton("123"));

Assert.assertEquals(r.getTotals(), Collections.singleton("123"));

Assert.assertNotNull(r.getExtremes());
Assert.assertEquals(r.getExtremes().getMin(), Collections.singleton("123"));
Assert.assertEquals(r.getExtremes().getMax(), Collections.singleton("123"));

Assert.assertEquals(r.getRows(), 1);
Assert.assertEquals(r.getRows_before_limit_at_least(), 1);

// map based on property name
JsonResponseSummary rs = JsonStreamUtils.readObject(
"{\"read_rows\":1,\"written_rows\":2,\"read_bytes\":3,\"written_bytes\":4,\"total_rows_to_read\":5}",
JsonResponseSummary.class);

Assert.assertNotNull(rs);
Assert.assertEquals(rs.getReadRows(), 1);
Assert.assertEquals(rs.getWrittenRows(), 2);
Assert.assertEquals(rs.getReadBytes(), 3);
Assert.assertEquals(rs.getWrittenBytes(), 4);
Assert.assertEquals(rs.getTotalRowsToRead(), 5);
}

@Test(groups = { "unit" })
public void testToJsonString() {
Assert.assertEquals(JsonStreamUtils.toJsonString(null), "null");
Assert.assertEquals(JsonStreamUtils.toJsonString(""), "\"\"");
Assert.assertEquals(JsonStreamUtils.toJsonString(1), "1");
Assert.assertEquals(JsonStreamUtils.toJsonString(new Object()), "{}");
Assert.assertEquals(JsonStreamUtils.toJsonString(new JsonCompactResponse()),
"{\"rows\":0,\"rows_before_limit_at_least\":0}");
}

@Test(groups = { "unit" })
public void testWriteObject() throws IOException {
try (ByteArrayOutputStream output = new ByteArrayOutputStream(1024)) {
JsonStreamUtils.writeObject(output, new JsonCompactResponse());
output.flush();
Assert.assertEquals(new String(output.toByteArray()), "{\"rows\":0,\"rows_before_limit_at_least\":0}");
}
}
}
Loading