content: /*
   * 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.redis;
  
  import org.apache.calcite.model.JsonCustomTable;
  import org.apache.calcite.schema.Table;
  import org.apache.calcite.schema.impl.AbstractSchema;
  
  import org.apache.commons.lang3.StringUtils;
  
  import com.google.common.cache.CacheBuilder;
  import com.google.common.cache.CacheLoader;
  import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Maps;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.stream.Collectors;
  
  import static java.util.Objects.requireNonNull;
  
  /**
   * Schema mapped onto a set of URLs / HTML tables. Each table in the schema
   * is an HTML table on a URL.
   */
  class RedisSchema extends AbstractSchema {
    public final String host;
    public final int port;
    public final int database;
    public final String password;
    public final List<Map<String, Object>> tables;
  
    RedisSchema(String host,
        int port,
        int database,
        String password,
        List<Map<String, Object>> tables) {
      this.host = host;
      this.port = port;
      this.database = database;
      this.password = password;
      this.tables = tables;
    }
  
    @Override protected Map<String, Table> getTableMap() {
      JsonCustomTable[] jsonCustomTables = new JsonCustomTable[tables.size()];
      Set<String> tableNames = Arrays.stream(tables.toArray(jsonCustomTables))
          .map(e -> e.name).collect(Collectors.toSet());
      return Maps.asMap(ImmutableSet.copyOf(tableNames),
          CacheBuilder.newBuilder()
              .build(CacheLoader.from(this::table)));
    }
  
    private Table table(String tableName) {
      RedisConfig redisConfig = new RedisConfig(host, port, database, password);
      return RedisTable.create(RedisSchema.this, tableName, redisConfig, null);
    }
  
    public RedisTableFieldInfo getTableFieldInfo(String tableName) {
      RedisTableFieldInfo tableFieldInfo = new RedisTableFieldInfo();
      List<LinkedHashMap<String, Object>> fields = new ArrayList<>();
      String dataFormat = "";
      String keyDelimiter = "";
      @SuppressWarnings({"unchecked", "rawtypes"})
      List<JsonCustomTable> jsonCustomTables =
          (List<JsonCustomTable>) (List) this.tables;
      for (JsonCustomTable jsonCustomTable : jsonCustomTables) {
        if (jsonCustomTable.name.equals(tableName)) {
          Map<String, Object> map =
              requireNonNull(jsonCustomTable.operand, "operand");
          if (map.get("dataFormat") == null) {
            throw new RuntimeException("dataFormat is null");
          }
          if (map.get("fields") == null) {
            throw new RuntimeException("fields is null");
          }
          dataFormat = map.get("dataFormat").toString();
          fields = (List<LinkedHashMap<String, Object>>) map.get("fields");
          if (map.get("keyDelimiter") != null) {
            keyDelimiter = map.get("keyDelimiter").toString();
          }
          break;
        }
      }
      tableFieldInfo.setTableName(tableName);
      tableFieldInfo.setDataFormat(dataFormat);
      tableFieldInfo.setFields(fields);
      if (StringUtils.isNotEmpty(keyDelimiter)) {
        tableFieldInfo.setKeyDelimiter(keyDelimiter);
      }
      return tableFieldInfo;
    }
  }
  