Java tutorial
/* * 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 org.apache.calcite.adapter.druid; import org.apache.calcite.interpreter.BindableConvention; import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.TableScan; import org.apache.calcite.rel.logical.LogicalTableScan; import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelProtoDataType; import org.apache.calcite.schema.Table; import org.apache.calcite.schema.TranslatableTable; import org.apache.calcite.schema.impl.AbstractTable; import org.apache.calcite.sql.type.SqlTypeName; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.joda.time.DateTime; import org.joda.time.Interval; import org.joda.time.chrono.ISOChronology; import java.util.List; import java.util.Map; import java.util.Set; /** * Table mapped onto a Druid table. */ public class DruidTable extends AbstractTable implements TranslatableTable { public static final String DEFAULT_TIMESTAMP_COLUMN = "__time"; public static final Interval DEFAULT_INTERVAL = new Interval( new DateTime("1900-01-01", ISOChronology.getInstanceUTC()), new DateTime("3000-01-01", ISOChronology.getInstanceUTC())); final DruidSchema schema; final String dataSource; final RelProtoDataType protoRowType; final ImmutableSet<String> metricFieldNames; final ImmutableList<Interval> intervals; final String timestampFieldName; /** * Creates a Druid table. * * @param schema Druid schema that contains this table * @param dataSource Druid data source name * @param protoRowType Field names and types * @param metricFieldNames Names of fields that are metrics * @param intervals Default interval if query does not constrain the time, or null * @param timestampFieldName Name of the column that contains the time */ public DruidTable(DruidSchema schema, String dataSource, RelProtoDataType protoRowType, Set<String> metricFieldNames, String timestampFieldName, List<Interval> intervals) { this.timestampFieldName = Preconditions.checkNotNull(timestampFieldName); this.schema = Preconditions.checkNotNull(schema); this.dataSource = Preconditions.checkNotNull(dataSource); this.protoRowType = protoRowType; this.metricFieldNames = ImmutableSet.copyOf(metricFieldNames); this.intervals = intervals != null ? ImmutableList.copyOf(intervals) : ImmutableList.of(DEFAULT_INTERVAL); for (Interval interval : this.intervals) { assert interval.getChronology() == ISOChronology.getInstanceUTC(); } } /** Creates a {@link DruidTable} * * @param druidSchema Druid schema * @param dataSourceName Data source name in Druid, also table name * @param intervals Intervals, or null to use default * @param fieldMap Mutable map of fields (dimensions plus metrics); * may be partially populated already * @param metricNameSet Mutable set of metric names; * may be partially populated already * @param timestampColumnName Name of timestamp column, or null * @param connection If not null, use this connection to find column * definitions * @return A table */ static Table create(DruidSchema druidSchema, String dataSourceName, List<Interval> intervals, Map<String, SqlTypeName> fieldMap, Set<String> metricNameSet, String timestampColumnName, DruidConnectionImpl connection) { if (connection != null) { connection.metadata(dataSourceName, timestampColumnName, intervals, fieldMap, metricNameSet); } final ImmutableMap<String, SqlTypeName> fields = ImmutableMap.copyOf(fieldMap); return new DruidTable(druidSchema, dataSourceName, new MapRelProtoDataType(fields), ImmutableSet.copyOf(metricNameSet), timestampColumnName, intervals); } public RelDataType getRowType(RelDataTypeFactory typeFactory) { final RelDataType rowType = protoRowType.apply(typeFactory); final List<String> fieldNames = rowType.getFieldNames(); Preconditions.checkArgument(fieldNames.contains(timestampFieldName)); Preconditions.checkArgument(fieldNames.containsAll(metricFieldNames)); return rowType; } public RelNode toRel(RelOptTable.ToRelContext context, RelOptTable relOptTable) { final RelOptCluster cluster = context.getCluster(); final TableScan scan = LogicalTableScan.create(cluster, relOptTable); return DruidQuery.create(cluster, cluster.traitSetOf(BindableConvention.INSTANCE), relOptTable, this, ImmutableList.<RelNode>of(scan)); } /** Creates a {@link RelDataType} from a map of * field names and types. */ private static class MapRelProtoDataType implements RelProtoDataType { private final ImmutableMap<String, SqlTypeName> fields; MapRelProtoDataType(ImmutableMap<String, SqlTypeName> fields) { this.fields = fields; } public RelDataType apply(RelDataTypeFactory typeFactory) { final RelDataTypeFactory.FieldInfoBuilder builder = typeFactory.builder(); for (Map.Entry<String, SqlTypeName> field : fields.entrySet()) { builder.add(field.getKey(), field.getValue()).nullable(true); } return builder.build(); } } } // End DruidTable.java