Fixture.java

/*
 * 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.test.catalog;

import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeComparability;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
import org.apache.calcite.rel.type.StructKind;
import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.type.ObjectSqlType;
import org.apache.calcite.sql.type.SqlTypeName;

import java.util.Arrays;

/** Types used during initialization. */
final class Fixture extends AbstractFixture {
  final RelDataType intType = sqlType(SqlTypeName.INTEGER);
  final RelDataType intTypeNull = nullable(intType);
  final RelDataType bigintType = sqlType(SqlTypeName.BIGINT);
  final RelDataType decimalType = sqlType(SqlTypeName.DECIMAL);
  final RelDataType varcharType = sqlType(SqlTypeName.VARCHAR);
  final RelDataType varcharTypeNull = nullable(varcharType);
  final RelDataType varchar5Type = sqlType(SqlTypeName.VARCHAR, 5);
  final RelDataType varchar10Type = sqlType(SqlTypeName.VARCHAR, 10);
  final RelDataType varchar10TypeNull = nullable(varchar10Type);
  final RelDataType varchar20Type = sqlType(SqlTypeName.VARCHAR, 20);
  final RelDataType varchar20TypeNull = nullable(varchar20Type);
  final RelDataType timestampType = sqlType(SqlTypeName.TIMESTAMP);
  final RelDataType timestampTypeWithLocalTimeZone =
      sqlType(SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE);
  final RelDataType timestampTypeNull = nullable(timestampType);
  final RelDataType timestampTypeWithLocalTimeZoneNull =
      nullable(timestampTypeWithLocalTimeZone);
  final RelDataType dateType = sqlType(SqlTypeName.DATE);
  final RelDataType booleanType = sqlType(SqlTypeName.BOOLEAN);
  final RelDataType booleanTypeNull = nullable(booleanType);
  final RelDataType rectilinearCoordType = typeFactory.builder()
      .add("X", intType)
      .add("Y", intType)
      .build();
  final RelDataType rectilinearPeekCoordType = typeFactory.builder()
      .add("X", intType)
      .add("Y", intType)
      .add("unit", varchar20Type)
      .kind(StructKind.PEEK_FIELDS)
      .build();
  final RelDataType rectilinearPeekCoordMultisetType =
      typeFactory.createMultisetType(rectilinearPeekCoordType, -1);
  final RelDataType rectilinearPeekNoExpandCoordType = typeFactory.builder()
      .add("M", intType)
      .add("SUB",
          typeFactory.builder()
              .add("A", intType)
              .add("B", intType)
              .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
              .build())
      .kind(StructKind.PEEK_FIELDS_NO_EXPAND)
      .build();
  final RelDataType singleRecordType = typeFactory.builder()
      .add("TYPE", varchar10Type)
      .build();
  final RelDataType abRecordType = typeFactory.builder()
      .add("A", varchar10Type)
      .add("B", varchar10Type)
      .build();
  final RelDataType skillRecordType = typeFactory.builder()
      .add("TYPE", varchar10Type)
      .add("DESC", varchar20Type)
      .add("OTHERS", abRecordType)
      .build();
  final RelDataType empRecordType = typeFactory.builder()
      .add("EMPNO", intType)
      .add("ENAME", varchar10Type)
      .add("DETAIL", typeFactory.builder()
      .add("SKILLS", array(skillRecordType)).build())
      .kind(StructKind.PEEK_FIELDS)
      .build();
  final RelDataType empListType = array(empRecordType);
  final ObjectSqlType addressType =
      new ObjectSqlType(SqlTypeName.STRUCTURED,
          new SqlIdentifier("ADDRESS", SqlParserPos.ZERO),
          false,
          Arrays.asList(new RelDataTypeFieldImpl("STREET", 0, varchar20Type),
              new RelDataTypeFieldImpl("CITY", 1, varchar20Type),
              new RelDataTypeFieldImpl("ZIP", 2, intType),
              new RelDataTypeFieldImpl("STATE", 3, varchar20Type)),
          RelDataTypeComparability.NONE);
  // Row(f0 int, f1 varchar)
  final RelDataType recordType1 =
      typeFactory.createStructType(Arrays.asList(intType, varcharType),
          Arrays.asList("f0", "f1"));
  // Row(f0 int not null, f1 varchar null)
  final RelDataType recordType2 =
      typeFactory.createStructType(Arrays.asList(intType, nullable(varcharType)),
          Arrays.asList("f0", "f1"));
  // Row(f0 Row(ff0 int not null, ff1 varchar null) null, f1 timestamp not null)
  final RelDataType recordType3 =
      typeFactory.createStructType(
          Arrays.asList(
              nullable(
                  typeFactory.createStructType(
                      Arrays.asList(intType, varcharTypeNull),
                      Arrays.asList("ff0", "ff1"))),
              timestampType),
          Arrays.asList("f0", "f1"));
  // Row(f0 bigint not null, f1 decimal null) array
  final RelDataType recordType4 =
      array(
          typeFactory.createStructType(
              Arrays.asList(bigintType, nullable(decimalType)),
              Arrays.asList("f0", "f1")));
  // Row(f0 varchar not null, f1 timestamp null) multiset
  final RelDataType recordType5 =
      typeFactory.createMultisetType(
          typeFactory.createStructType(
              Arrays.asList(varcharType, timestampTypeNull),
              Arrays.asList("f0", "f1")),
          -1);
  final RelDataType intArrayType = array(intType);
  final RelDataType varchar5ArrayType = array(varchar5Type);
  final RelDataType intArrayArrayType = array(intArrayType);
  final RelDataType varchar5ArrayArrayType = array(varchar5ArrayType);
  final RelDataType intMultisetType = typeFactory.createMultisetType(intType, -1);
  final RelDataType varchar5MultisetType = typeFactory.createMultisetType(varchar5Type, -1);
  final RelDataType intMultisetArrayType = array(intMultisetType);
  final RelDataType varchar5MultisetArrayType = array(varchar5MultisetType);
  final RelDataType intArrayMultisetType = typeFactory.createMultisetType(intArrayType, -1);
  // Row(f0 int array multiset, f1 varchar(5) array) array multiset
  final RelDataType rowArrayMultisetType =
      typeFactory.createMultisetType(
          array(
              typeFactory.createStructType(
                  Arrays.asList(intArrayMultisetType, varchar5ArrayType),
                  Arrays.asList("f0", "f1"))),
          -1);
  final RelDataType int2IntMapType =
      typeFactory.createMapType(intType, intType);
  final RelDataType int2varcharArrayMapType =
      typeFactory.createMapType(intType, array(varcharType));
  final RelDataType varcharMultiset2IntIntMapType =
      typeFactory.createMapType(varchar5MultisetType, int2IntMapType);

  Fixture(RelDataTypeFactory typeFactory) {
    super(typeFactory);
  }

  private RelDataType nullable(RelDataType type) {
    return typeFactory.createTypeWithNullability(type, true);
  }

  private RelDataType sqlType(SqlTypeName typeName, int... args) {
    assert args.length < 3 : "unknown size of additional int args";
    return args.length == 2 ? typeFactory.createSqlType(typeName, args[0], args[1])
        : args.length == 1 ? typeFactory.createSqlType(typeName, args[0])
        : typeFactory.createSqlType(typeName);
  }

  private RelDataType array(RelDataType type) {
    return typeFactory.createArrayType(type, -1);
  }
}

/**
 * Just a little trick to store factory ref before field init in fixture.
 */
abstract class AbstractFixture {
  final RelDataTypeFactory typeFactory;

  AbstractFixture(RelDataTypeFactory typeFactory) {
    this.typeFactory = typeFactory;
  }
}