com.datastax.oss.driver.internal.core.metadata.schema.queries.CassandraSchemaRows Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.datastax.oss.driver.internal.core.metadata.schema.queries;
import com.datastax.dse.driver.api.core.metadata.DseNodeProperties;
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.Version;
import com.datastax.oss.driver.api.core.metadata.Node;
import com.datastax.oss.driver.internal.core.adminrequest.AdminRow;
import com.datastax.oss.driver.internal.core.metadata.schema.parsing.DataTypeClassNameParser;
import com.datastax.oss.driver.internal.core.metadata.schema.parsing.DataTypeCqlNameParser;
import com.datastax.oss.driver.internal.core.metadata.schema.parsing.DataTypeParser;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableList;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableListMultimap;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMultimap;
import com.datastax.oss.driver.shaded.guava.common.collect.Multimap;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.jcip.annotations.Immutable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Immutable
public class CassandraSchemaRows implements SchemaRows {
private final Node node;
private final DataTypeParser dataTypeParser;
private final List keyspaces;
private final List virtualKeyspaces;
private final Multimap tables;
private final Multimap virtualTables;
private final Multimap views;
private final Multimap types;
private final Multimap functions;
private final Multimap aggregates;
private final Map> columns;
private final Map> virtualColumns;
private final Map> indexes;
private final Map> vertices;
private final Map> edges;
private CassandraSchemaRows(
Node node,
DataTypeParser dataTypeParser,
List keyspaces,
List virtualKeyspaces,
Multimap tables,
Multimap virtualTables,
Multimap views,
Map> columns,
Map> virtualColumns,
Map> indexes,
Multimap types,
Multimap functions,
Multimap aggregates,
Map> vertices,
Map> edges) {
this.node = node;
this.dataTypeParser = dataTypeParser;
this.keyspaces = keyspaces;
this.virtualKeyspaces = virtualKeyspaces;
this.tables = tables;
this.virtualTables = virtualTables;
this.views = views;
this.columns = columns;
this.virtualColumns = virtualColumns;
this.indexes = indexes;
this.types = types;
this.functions = functions;
this.aggregates = aggregates;
this.vertices = vertices;
this.edges = edges;
}
@NonNull
@Override
public Node getNode() {
return node;
}
@Override
public DataTypeParser dataTypeParser() {
return dataTypeParser;
}
@Override
public List keyspaces() {
return keyspaces;
}
@Override
public List virtualKeyspaces() {
return virtualKeyspaces;
}
@Override
public Multimap tables() {
return tables;
}
@Override
public Multimap virtualTables() {
return virtualTables;
}
@Override
public Multimap views() {
return views;
}
@Override
public Multimap types() {
return types;
}
@Override
public Multimap functions() {
return functions;
}
@Override
public Multimap aggregates() {
return aggregates;
}
@Override
public Map> columns() {
return columns;
}
@Override
public Map> virtualColumns() {
return virtualColumns;
}
@Override
public Map> indexes() {
return indexes;
}
@Override
public Map> vertices() {
return vertices;
}
@Override
public Map> edges() {
return edges;
}
public static class Builder {
private static final Logger LOG = LoggerFactory.getLogger(Builder.class);
private final Node node;
private final DataTypeParser dataTypeParser;
private final String tableNameColumn;
private final KeyspaceFilter keyspaceFilter;
private final String logPrefix;
private final ImmutableList.Builder keyspacesBuilder = ImmutableList.builder();
private final ImmutableList.Builder virtualKeyspacesBuilder = ImmutableList.builder();
private final ImmutableMultimap.Builder tablesBuilder =
ImmutableListMultimap.builder();
private final ImmutableMultimap.Builder virtualTablesBuilder =
ImmutableListMultimap.builder();
private final ImmutableMultimap.Builder viewsBuilder =
ImmutableListMultimap.builder();
private final ImmutableMultimap.Builder typesBuilder =
ImmutableListMultimap.builder();
private final ImmutableMultimap.Builder functionsBuilder =
ImmutableListMultimap.builder();
private final ImmutableMultimap.Builder aggregatesBuilder =
ImmutableListMultimap.builder();
private final Map>
columnsBuilders = new LinkedHashMap<>();
private final Map>
virtualColumnsBuilders = new LinkedHashMap<>();
private final Map>
indexesBuilders = new LinkedHashMap<>();
private final Map>
verticesBuilders = new LinkedHashMap<>();
private final Map>
edgesBuilders = new LinkedHashMap<>();
public Builder(Node node, KeyspaceFilter keyspaceFilter, String logPrefix) {
this.node = node;
this.keyspaceFilter = keyspaceFilter;
this.logPrefix = logPrefix;
if (isCassandraV3OrAbove(node)) {
this.tableNameColumn = "table_name";
this.dataTypeParser = new DataTypeCqlNameParser();
} else {
this.tableNameColumn = "columnfamily_name";
this.dataTypeParser = new DataTypeClassNameParser();
}
}
private static boolean isCassandraV3OrAbove(Node node) {
// We already did those checks in DefaultSchemaQueriesFactory.
// We could pass along booleans (isCassandraV3, isDse...), but passing the whole Node is
// better for maintainability, in case we need to do more checks in downstream components in
// the future.
Version dseVersion = (Version) node.getExtras().get(DseNodeProperties.DSE_VERSION);
if (dseVersion != null) {
dseVersion = dseVersion.nextStable();
return dseVersion.compareTo(Version.V5_0_0) >= 0;
} else {
Version cassandraVersion = node.getCassandraVersion();
if (cassandraVersion == null) {
cassandraVersion = Version.V3_0_0;
} else {
cassandraVersion = cassandraVersion.nextStable();
}
return cassandraVersion.compareTo(Version.V3_0_0) >= 0;
}
}
public Builder withKeyspaces(Iterable rows) {
for (AdminRow row : rows) {
put(keyspacesBuilder, row);
}
return this;
}
public Builder withVirtualKeyspaces(Iterable rows) {
for (AdminRow row : rows) {
put(virtualKeyspacesBuilder, row);
}
return this;
}
public Builder withTables(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, tablesBuilder);
}
return this;
}
public Builder withVirtualTables(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, virtualTablesBuilder);
}
return this;
}
public Builder withViews(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, viewsBuilder);
}
return this;
}
public Builder withTypes(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, typesBuilder);
}
return this;
}
public Builder withFunctions(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, functionsBuilder);
}
return this;
}
public Builder withAggregates(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspace(row, aggregatesBuilder);
}
return this;
}
public Builder withColumns(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspaceAndTable(row, columnsBuilders);
}
return this;
}
public Builder withVirtualColumns(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspaceAndTable(row, virtualColumnsBuilders);
}
return this;
}
public Builder withIndexes(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspaceAndTable(row, indexesBuilders);
}
return this;
}
public Builder withVertices(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspaceAndTable(row, verticesBuilders);
}
return this;
}
public Builder withEdges(Iterable rows) {
for (AdminRow row : rows) {
putByKeyspaceAndTable(row, edgesBuilders);
}
return this;
}
private void put(ImmutableList.Builder builder, AdminRow row) {
String keyspace = row.getString("keyspace_name");
if (keyspace == null) {
LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix);
} else if (keyspaceFilter.includes(keyspace)) {
builder.add(row);
}
}
private void putByKeyspace(
AdminRow row, ImmutableMultimap.Builder builder) {
String keyspace = row.getString("keyspace_name");
if (keyspace == null) {
LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix);
} else if (keyspaceFilter.includes(keyspace)) {
builder.put(CqlIdentifier.fromInternal(keyspace), row);
}
}
private void putByKeyspaceAndTable(
AdminRow row,
Map> builders) {
String keyspace = row.getString("keyspace_name");
String table = row.getString(tableNameColumn);
if (keyspace == null) {
LOG.warn("[{}] Skipping system row with missing keyspace name", logPrefix);
} else if (table == null) {
LOG.warn("[{}] Skipping system row with missing table name", logPrefix);
} else if (keyspaceFilter.includes(keyspace)) {
ImmutableMultimap.Builder builder =
builders.computeIfAbsent(
CqlIdentifier.fromInternal(keyspace), s -> ImmutableListMultimap.builder());
builder.put(CqlIdentifier.fromInternal(table), row);
}
}
public CassandraSchemaRows build() {
return new CassandraSchemaRows(
node,
dataTypeParser,
keyspacesBuilder.build(),
virtualKeyspacesBuilder.build(),
tablesBuilder.build(),
virtualTablesBuilder.build(),
viewsBuilder.build(),
build(columnsBuilders),
build(virtualColumnsBuilders),
build(indexesBuilders),
typesBuilder.build(),
functionsBuilder.build(),
aggregatesBuilder.build(),
build(verticesBuilders),
build(edgesBuilders));
}
private static Map> build(
Map> builders) {
ImmutableMap.Builder> builder = ImmutableMap.builder();
builders
.entrySet()
.forEach(
(entry) -> {
builder.put(entry.getKey(), entry.getValue().build());
});
return builder.build();
}
}
}