From 5cfc6194b19d21c8d82bf18b689e1a8c7af89503 Mon Sep 17 00:00:00 2001 From: shollyman Date: Tue, 19 Jun 2018 14:24:16 -0700 Subject: [PATCH] BigQuery: Add ORC format support for load jobs, missing bigtable support. (#3391) * BigQuery: Add ORC format support for load jobs. Additionally, plumb in the (missing) Bigtable format support for federated tables. * add overrides, unit testing * Wire bigtable up into formatoptions * add copyright headers. * Convert BigtableColumn and BigtableColumnFamily to autovalue generation. * excise unused imports, address codacy kvetching about declaration order. * Address reviewer comments: formatting/whitespace, serializable, asserts * unused imports (asserts) --- .../google/cloud/bigquery/BigtableColumn.java | 137 +++++++++++++++ .../cloud/bigquery/BigtableColumnFamily.java | 144 ++++++++++++++++ .../cloud/bigquery/BigtableOptions.java | 156 ++++++++++++++++++ .../bigquery/ExternalTableDefinition.java | 17 ++ .../google/cloud/bigquery/FormatOptions.java | 32 +++- .../cloud/bigquery/BigtableOptionsTest.java | 115 +++++++++++++ 6 files changed, 597 insertions(+), 4 deletions(-) create mode 100644 google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumn.java create mode 100644 google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumnFamily.java create mode 100644 google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableOptions.java create mode 100644 google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigtableOptionsTest.java diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumn.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumn.java new file mode 100644 index 000000000000..8f18b548cda3 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumn.java @@ -0,0 +1,137 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigquery; + +import com.google.common.base.Function; +import com.google.auto.value.AutoValue; +import java.io.Serializable; +import javax.annotation.Nullable; + +@AutoValue +public abstract class BigtableColumn implements Serializable { + + private static final long serialVersionUID = 1L; + + @Nullable + public abstract String getQualifierEncoded(); + + @Nullable + public abstract String getFieldName(); + + @Nullable + public abstract Boolean getOnlyReadLatest(); + + @Nullable + public abstract String getEncoding(); + + @Nullable + public abstract String getType(); + + @AutoValue.Builder + public abstract static class Builder { + + /** + * Qualifier of the column. + * + * Columns in the parent column family that has this exact qualifier are exposed as . field. If + * the qualifier is valid UTF-8 string, it can be specified in the qualifier_string field. + * Otherwise, a base-64 encoded value must be set to qualifier_encoded. The column field name is + * the same as the column qualifier. However, if the qualifier is not a valid BigQuery field + * identifier, a valid identifier must be provided as field_name. + */ + public abstract Builder setQualifierEncoded(String qualifierEncoded); + + /** + * If the qualifier is not a valid BigQuery field identifier, a valid identifier must be + * provided as the column field name and is used as field name in queries. + */ + public abstract Builder setFieldName(String fieldName); + + /** + * If this is set, only the latest version of value in this column are exposed. + * + * 'onlyReadLatest' can also be set at the column family level. However, the setting at the + * column level takes precedence if 'onlyReadLatest' is set at both levels. + */ + public abstract Builder setOnlyReadLatest(Boolean onlyReadLatest); + + /** + * The encoding of the values when the type is not STRING. Acceptable encoding values are: TEXT + * - indicates values are alphanumeric text strings. BINARY - indicates values are encoded using + * HBase Bytes.toBytes family of functions. + * + * Encoding can also be set at the column family level. However, the setting at the column level + * takes precedence if 'encoding' is set at both levels. + */ + public abstract Builder setEncoding(String encoding); + + /** + * The type to convert the value in cells of this column. + * + * The values are expected to be encoded using HBase Bytes.toBytes function when using the + * BINARY encoding value. Following BigQuery types are allowed (case-sensitive): BYTES STRING + * INTEGER FLOAT BOOLEAN Default type is BYTES. + * + * 'type' can also be set at the column family level. However, the setting at the column level + * takes precedence if 'type' is set at both levels. + */ + public abstract Builder setType(String type); + + public abstract BigtableColumn build(); + } + + static Builder newBuilder() { + return new AutoValue_BigtableColumn.Builder(); + } + + static BigtableColumn fromPb(com.google.api.services.bigquery.model.BigtableColumn column) { + Builder builder = newBuilder(); + builder.setQualifierEncoded(column.getQualifierEncoded()); + builder.setFieldName(column.getFieldName()); + builder.setOnlyReadLatest(column.getOnlyReadLatest()); + builder.setEncoding(column.getEncoding()); + builder.setType(column.getType()); + return builder.build(); + } + + com.google.api.services.bigquery.model.BigtableColumn toPb() { + com.google.api.services.bigquery.model.BigtableColumn column = new com.google.api.services.bigquery.model.BigtableColumn() + .setQualifierEncoded(getQualifierEncoded()) + .setFieldName(getFieldName()) + .setOnlyReadLatest(getOnlyReadLatest()) + .setEncoding(getEncoding()) + .setType(getType()); + return column; + } + + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public BigtableColumn apply( + com.google.api.services.bigquery.model.BigtableColumn pb) { + return BigtableColumn.fromPb(pb); + } + }; + + static final Function TO_PB_FUNCTION = + new Function() { + @Override + public com.google.api.services.bigquery.model.BigtableColumn apply( + BigtableColumn column) { + return column.toPb(); + } + }; +} diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumnFamily.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumnFamily.java new file mode 100644 index 000000000000..2d9993919d33 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableColumnFamily.java @@ -0,0 +1,144 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigquery; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.google.auto.value.AutoValue; +import java.io.Serializable; +import java.util.List; + +/** + * List of column families to expose in the table schema along with their types. This list restricts + * the column families that can be referenced in queries and specifies their value types. + * + * You can use this list to do type conversions - see the 'type' field for more details. If you + * leave this list empty, all column families are present in the table schema and their values are + * read as BYTES. During a query only the column families referenced in that query are read from + * Bigtable. + */ + +@AutoValue +public abstract class BigtableColumnFamily implements Serializable { + + private static final long serialVersionUID = 1L; + + public abstract String getFamilyID(); + + public abstract List getColumns(); + + public abstract String getEncoding(); + + public abstract Boolean getOnlyReadLatest(); + + public abstract String getType(); + + @AutoValue.Builder + public abstract static class Builder { + + /** + * Identifier of the column family. + */ + public abstract Builder setFamilyID(String familyID); + + /** + * Lists of columns that should be exposed as individual fields as opposed to a list of (column + * name, value) pairs. All columns whose qualifier matches a qualifier in this list can be + * accessed as .. Other columns can be accessed as a list through .Column field. + */ + public abstract Builder setColumns(List columns); + + /** + * The encoding of the values when the type is not STRING. + * + * Acceptable encoding values are: TEXT - indicates values are alphanumeric text strings. BINARY + * - indicates values are encoded using HBase Bytes.toBytes family of functions. + * + * This can be overridden for a specific column by listing that column in 'columns' and + * specifying an encoding for it. + */ + public abstract Builder setEncoding(String encoding); + + /** + * If true, only the latest version of values are exposed for all columns in this column family. + * This can be overridden for a specific column by listing that column in 'columns' and + * specifying a different setting for that column. + */ + public abstract Builder setOnlyReadLatest(Boolean onlyReadLatest); + + /** + * The type to convert the value in cells of this column family. The values are expected to be + * encoded using HBase Bytes.toBytes function when using the BINARY encoding value. + * + * Following BigQuery types are allowed (case-sensitive): BYTES STRING INTEGER FLOAT BOOLEAN. + * + * The default type is BYTES. This can be overridden for a specific column by listing that + * column in 'columns' and specifying a type for it. + */ + public abstract Builder setType(String type); + + public abstract BigtableColumnFamily build(); + } + + static Builder newBuilder() { + return new AutoValue_BigtableColumnFamily.Builder(); + } + + static BigtableColumnFamily fromPb( + com.google.api.services.bigquery.model.BigtableColumnFamily columnFamily) { + Builder builder = newBuilder(); + builder.setFamilyID(columnFamily.getFamilyId()); + builder.setColumns(Lists.transform(columnFamily.getColumns(), BigtableColumn.FROM_PB_FUNCTION)); + builder.setEncoding(columnFamily.getEncoding()); + builder.setOnlyReadLatest(columnFamily.getOnlyReadLatest()); + builder.setType(columnFamily.getType()); + return builder.build(); + + } + + com.google.api.services.bigquery.model.BigtableColumnFamily toPb() { + com.google.api.services.bigquery.model.BigtableColumnFamily colFamilyPb = new com.google.api.services.bigquery.model.BigtableColumnFamily() + .setFamilyId(getFamilyID()) + .setEncoding(getEncoding()) + .setOnlyReadLatest(getOnlyReadLatest()) + .setType(getType()); + if (getColumns() != null) { + colFamilyPb.setColumns(Lists.transform(getColumns(), BigtableColumn.TO_PB_FUNCTION)); + } + return colFamilyPb; + } + + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public BigtableColumnFamily apply( + com.google.api.services.bigquery.model.BigtableColumnFamily pb) { + return BigtableColumnFamily.fromPb(pb); + } + }; + + static final Function TO_PB_FUNCTION = + new Function() { + @Override + public com.google.api.services.bigquery.model.BigtableColumnFamily apply( + BigtableColumnFamily columnFamily) { + return columnFamily.toPb(); + } + }; +} + + + diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableOptions.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableOptions.java new file mode 100644 index 000000000000..2d0e4692749a --- /dev/null +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigtableOptions.java @@ -0,0 +1,156 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigquery; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Lists; +import java.util.List; +import java.util.Objects; + +public class BigtableOptions extends FormatOptions { + + private static final long serialVersionUID = 1L; + + private final Boolean ignoreUnspecifiedColumnFamilies; + private final Boolean readRowkeyAsString; + private final List columnFamilies; + + public Boolean getIgnoreUnspecifiedColumnFamilies() { + return ignoreUnspecifiedColumnFamilies; + } + + public Boolean getReadRowkeyAsString() { + return readRowkeyAsString; + } + + public List getColumnFamilies() { + return columnFamilies; + } + + static final class Builder { + + private Boolean ignoreUnspecifiedColumnFamilies; + private Boolean readRowkeyAsString; + private List columnFamilies; + + private Builder() { + } + + private Builder(BigtableOptions bigtableOptions) { + this.ignoreUnspecifiedColumnFamilies = bigtableOptions.ignoreUnspecifiedColumnFamilies; + this.readRowkeyAsString = bigtableOptions.readRowkeyAsString; + this.columnFamilies = bigtableOptions.columnFamilies; + } + + /** + * If field is true, then the column families that are not specified in columnFamilies list are + * not exposed in the table schema. Otherwise, they are read with BYTES type values. The default + * value is false. + */ + Builder setIgnoreUnspecifiedColumnFamilies(Boolean ignoreUnspecifiedColumnFamilies) { + this.ignoreUnspecifiedColumnFamilies = ignoreUnspecifiedColumnFamilies; + return this; + } + + /** + * If readRowkeyAsString is true, then the rowkey column families will be read and converted to + * string. Otherwise they are read with BYTES type values and users need to manually cast them + * with CAST if necessary. The default value is false. + */ + Builder setReadRowkeyAsString(Boolean readRowkeyAsString) { + this.readRowkeyAsString = readRowkeyAsString; + return this; + } + + /** + * List of column families to expose in the table schema along with their types. + * + * This list restricts the column families that can be referenced in queries and specifies their + * value types. You can use this list to do type conversions - see the 'type' field for more + * details. If you leave this list empty, all column families are present in the table schema + * and their values are read as BYTES. During a query only the column families referenced in + * that query are read from Bigtable. + */ + Builder setColumnFamilies(List columnFamilies) { + this.columnFamilies = columnFamilies; + return this; + } + + BigtableOptions build() { + return new BigtableOptions(this); + } + + } + + BigtableOptions(Builder builder) { + super(FormatOptions.BIGTABLE); + ignoreUnspecifiedColumnFamilies = builder.ignoreUnspecifiedColumnFamilies; + readRowkeyAsString = builder.readRowkeyAsString; + columnFamilies = builder.columnFamilies; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("ignoreUnspecifiedColumnFamilies", ignoreUnspecifiedColumnFamilies) + .add("readRowkeyAsString", readRowkeyAsString) + .add("columnFamilies", columnFamilies) + .toString(); + } + + @Override + public final int hashCode() { + return Objects.hash(ignoreUnspecifiedColumnFamilies, readRowkeyAsString, columnFamilies); + } + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || !obj.getClass().equals(BigtableOptions.class)) { + return false; + } + BigtableOptions other = (BigtableOptions) obj; + return ignoreUnspecifiedColumnFamilies == other.ignoreUnspecifiedColumnFamilies + && readRowkeyAsString == other.readRowkeyAsString + && Objects.equals(columnFamilies, other.columnFamilies); + } + + public static Builder newBuilder() { + return new Builder(); + } + + static BigtableOptions fromPb(com.google.api.services.bigquery.model.BigtableOptions options) { + Builder builder = newBuilder(); + builder.setIgnoreUnspecifiedColumnFamilies(options.getIgnoreUnspecifiedColumnFamilies()); + builder.setReadRowkeyAsString(options.getReadRowkeyAsString()); + builder.setColumnFamilies( + Lists.transform(options.getColumnFamilies(), BigtableColumnFamily.FROM_PB_FUNCTION)); + return builder.build(); + } + + com.google.api.services.bigquery.model.BigtableOptions toPb() { + com.google.api.services.bigquery.model.BigtableOptions options = new com.google.api.services.bigquery.model.BigtableOptions() + .setIgnoreUnspecifiedColumnFamilies(ignoreUnspecifiedColumnFamilies) + .setReadRowkeyAsString(readRowkeyAsString); + if (columnFamilies != null) { + options + .setColumnFamilies(Lists.transform(columnFamilies, BigtableColumnFamily.TO_PB_FUNCTION)); + } + return options; + } +} diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java index d63918b9bb45..626e7ec41503 100644 --- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java @@ -64,7 +64,15 @@ public abstract static class Builder * bucket's name. Size limits related to load jobs apply to external data sources, plus an * additional limit of 10 GB maximum size across all URIs. * + * For Google Cloud Bigtable URIs: + * Exactly one URI can be specified and it has be a fully specified and valid + * HTTPS URL for a Google Cloud Bigtable table. + * + * For Google Cloud Datastore backup URIs: + * Exactly one URI can be specified. Also, the '*' wildcard character is not allowed. + * * @see Quota + * */ public Builder setSourceUris(List sourceUris) { return setSourceUrisImmut(ImmutableList.copyOf(sourceUris)); @@ -239,6 +247,9 @@ com.google.api.services.bigquery.model.ExternalDataConfiguration toExternalDataC if (getFormatOptions() != null && FormatOptions.GOOGLE_SHEETS.equals(getFormatOptions().getType())) { externalConfigurationPb.setGoogleSheetsOptions(((GoogleSheetsOptions) getFormatOptions()).toPb()); } + if (getFormatOptions() != null && FormatOptions.BIGTABLE.equals(getFormatOptions().getType())) { + externalConfigurationPb.setBigtableOptions(((BigtableOptions) getFormatOptions()).toPb()); + } if (getAutodetect() != null) { externalConfigurationPb.setAutodetect(getAutodetect()); } @@ -346,6 +357,9 @@ static ExternalTableDefinition fromPb(Table tablePb) { if (externalDataConfiguration.getGoogleSheetsOptions() != null) { builder.setFormatOptions(GoogleSheetsOptions.fromPb(externalDataConfiguration.getGoogleSheetsOptions())); } + if (externalDataConfiguration.getBigtableOptions() != null) { + builder.setFormatOptions(BigtableOptions.fromPb(externalDataConfiguration.getBigtableOptions())); + } builder.setMaxBadRecords(externalDataConfiguration.getMaxBadRecords()); builder.setAutodetect(externalDataConfiguration.getAutodetect()); } @@ -376,6 +390,9 @@ static ExternalTableDefinition fromExternalDataConfiguration( if (externalDataConfiguration.getGoogleSheetsOptions() != null) { builder.setFormatOptions(GoogleSheetsOptions.fromPb(externalDataConfiguration.getGoogleSheetsOptions())); } + if (externalDataConfiguration.getBigtableOptions() != null) { + builder.setFormatOptions(BigtableOptions.fromPb(externalDataConfiguration.getBigtableOptions())); + } if (externalDataConfiguration.getMaxBadRecords() != null) { builder.setMaxBadRecords(externalDataConfiguration.getMaxBadRecords()); } diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FormatOptions.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FormatOptions.java index 2b64f446add8..71414fd8fc2b 100644 --- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FormatOptions.java +++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/FormatOptions.java @@ -26,15 +26,24 @@ /** * Base class for Google BigQuery format options. These class define the format of external data * used by BigQuery, for either federated tables or load jobs. + * + * Load jobs support the following formats: AVRO, CSV, DATASTORE_BACKUP, GOOGLE_SHEETS, JSON, ORC, + * PARQUET + * + * Federated tables can be defined against following formats: AVRO, BIGTABLE, CSV, DATASTORE_BACKUP, + * GOOGLE_SHEETS, JSON */ public class FormatOptions implements Serializable { static final String CSV = "CSV"; static final String JSON = "NEWLINE_DELIMITED_JSON"; + static final String BIGTABLE = "BIGTABLE"; static final String DATASTORE_BACKUP = "DATASTORE_BACKUP"; static final String AVRO = "AVRO"; static final String GOOGLE_SHEETS = "GOOGLE_SHEETS"; static final String PARQUET = "PARQUET"; + static final String ORC = "ORC"; + private static final long serialVersionUID = -443376052020423691L; private final String type; @@ -43,7 +52,6 @@ public class FormatOptions implements Serializable { this.type = type; } - /** * Returns the external data format, as a string. */ @@ -97,6 +105,13 @@ public static FormatOptions avro() { return new FormatOptions(AVRO); } + /** + * Default options for BIGTABLE format. + */ + public static FormatOptions bigtable() { + return BigtableOptions.newBuilder().build(); + } + /** * Default options for GOOGLE_SHEETS format. */ @@ -111,9 +126,16 @@ public static FormatOptions parquet() { return new FormatOptions(PARQUET); } - /** - * Default options for the provided format. - */ + /** + * Default options for the ORC format. + */ + public static FormatOptions orc() { + return new FormatOptions(ORC); + } + + /** + * Default options for the provided format. + */ public static FormatOptions of(String format) { if (checkNotNull(format).equals(CSV)) { return csv(); @@ -121,6 +143,8 @@ public static FormatOptions of(String format) { return datastoreBackup(); } else if (format.equals(GOOGLE_SHEETS)) { return googleSheets(); + } else if (format.equals(BIGTABLE)) { + return bigtable(); } return new FormatOptions(format); } diff --git a/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigtableOptionsTest.java b/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigtableOptionsTest.java new file mode 100644 index 000000000000..bcf886ecaed9 --- /dev/null +++ b/google-cloud-clients/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigtableOptionsTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigquery; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import org.junit.Test; + +public class BigtableOptionsTest { + + private static final BigtableColumn COL1 = BigtableColumn.newBuilder() + .setQualifierEncoded("aaa") + .setFieldName("field1") + .setOnlyReadLatest(true) + .setEncoding("BINARY") + .setType("BYTES") + .build(); + private static final BigtableColumn COL2 = BigtableColumn.newBuilder() + .setQualifierEncoded("bbb") + .setFieldName("field2") + .setOnlyReadLatest(true) + .setEncoding("TEXT") + .setType("STRING") + .build(); + private static final BigtableColumnFamily TESTFAMILY = BigtableColumnFamily.newBuilder() + .setFamilyID("fooFamily") + .setEncoding("TEXT") + .setOnlyReadLatest(true) + .setType("INTEGER") + .setColumns(ImmutableList.of(COL1, COL2)) + .build(); + private static final BigtableOptions OPTIONS = BigtableOptions.newBuilder() + .setIgnoreUnspecifiedColumnFamilies(true) + .setReadRowkeyAsString(true) + .setColumnFamilies(ImmutableList.of(TESTFAMILY)) + .build(); + + @Test + public void testConstructors() { + // column + assertThat(COL1.getQualifierEncoded()).isEqualTo("aaa"); + assertThat(COL1.getFieldName()).isEqualTo("field1"); + assertThat(COL1.getOnlyReadLatest()).isEqualTo(true); + assertThat(COL1.getEncoding()).isEqualTo("BINARY"); + assertThat(COL1.getType()).isEqualTo("BYTES"); + + // family + assertThat(TESTFAMILY.getFamilyID()).isEqualTo("fooFamily"); + assertThat(TESTFAMILY.getEncoding()).isEqualTo("TEXT"); + assertThat(TESTFAMILY.getOnlyReadLatest()).isEqualTo(true); + assertThat(TESTFAMILY.getType()).isEqualTo("INTEGER"); + assertThat(TESTFAMILY.getColumns()).isEqualTo(ImmutableList.of(COL1, COL2)); + + // options + assertThat(OPTIONS.getIgnoreUnspecifiedColumnFamilies()).isEqualTo(true); + assertThat(OPTIONS.getReadRowkeyAsString()).isEqualTo(true); + assertThat(OPTIONS.getColumnFamilies()).isEqualTo(ImmutableList.of(TESTFAMILY)); + } + + @Test + public void testToAndFromPb() { + compareBigtableColumn(COL1, BigtableColumn.fromPb(COL1.toPb())); + compareBigtableColumnFamily(TESTFAMILY, BigtableColumnFamily.fromPb(TESTFAMILY.toPb())); + compareBigtableOptions(OPTIONS, BigtableOptions.fromPb(OPTIONS.toPb())); + } + + @Test + public void testEquals() { + compareBigtableColumn(COL1, COL1); + compareBigtableColumnFamily(TESTFAMILY, TESTFAMILY); + compareBigtableOptions(OPTIONS, OPTIONS); + } + + private void compareBigtableColumn(BigtableColumn expected, BigtableColumn value) { + assertThat(expected).isEqualTo(value); + assertThat(expected.getEncoding()).isEqualTo(value.getEncoding()); + assertThat(expected.getFieldName()).isEqualTo(value.getFieldName()); + assertThat(expected.getQualifierEncoded()).isEqualTo(value.getQualifierEncoded()); + assertThat(expected.getOnlyReadLatest()).isEqualTo(value.getOnlyReadLatest()); + assertThat(expected.getType()).isEqualTo(value.getType()); + } + + private void compareBigtableColumnFamily(BigtableColumnFamily expected, + BigtableColumnFamily value) { + assertThat(expected).isEqualTo(value); + assertThat(expected.getFamilyID()).isEqualTo(value.getFamilyID()); + assertThat(expected.getOnlyReadLatest()).isEqualTo(value.getOnlyReadLatest()); + assertThat(expected.getColumns()).isEqualTo(value.getColumns()); + assertThat(expected.getEncoding()).isEqualTo(value.getEncoding()); + assertThat(expected.getType()).isEqualTo(value.getType()); + + } + + private void compareBigtableOptions(BigtableOptions expected, BigtableOptions value) { + assertThat(expected).isEqualTo(value); + assertThat(expected.getIgnoreUnspecifiedColumnFamilies()) + .isEqualTo(value.getIgnoreUnspecifiedColumnFamilies()); + assertThat(expected.getReadRowkeyAsString()).isEqualTo(value.getReadRowkeyAsString()); + assertThat(expected.getColumnFamilies()).isEqualTo(value.getColumnFamilies()); + } +} \ No newline at end of file