content: /*
   * Copyright (c)  2022. Aliyun.com All right reserved. This software is the
   * confidential and proprietary information of Aliyun.com ("Confidential
   * Information"). You shall not disclose such Confidential Information and shall
   * use it only in accordance with the terms of the license agreement you entered
   * into with Aliyun.com.
   */
  
  package com.aliyun.fastmodel.transform.hologres.client.generator;
  
  import java.util.List;
  import java.util.stream.Collectors;
  
  import com.aliyun.fastmodel.transform.api.client.CodeGenerator;
  import com.aliyun.fastmodel.transform.api.client.dto.property.BaseClientProperty;
  import com.aliyun.fastmodel.transform.api.client.dto.property.StringProperty;
  import com.aliyun.fastmodel.transform.api.client.dto.request.DdlGeneratorModelRequest;
  import com.aliyun.fastmodel.transform.api.client.dto.request.DdlReverseSqlRequest;
  import com.aliyun.fastmodel.transform.api.client.dto.result.DdlGeneratorResult;
  import com.aliyun.fastmodel.transform.api.client.dto.result.DdlTableResult;
  import com.aliyun.fastmodel.transform.api.client.dto.table.Column;
  import com.aliyun.fastmodel.transform.api.client.dto.table.Table;
  import com.aliyun.fastmodel.transform.api.client.dto.table.TableConfig;
  import com.aliyun.fastmodel.transform.api.client.generator.DefaultCodeGenerator;
  import com.aliyun.fastmodel.transform.api.dialect.DialectMeta;
  import com.aliyun.fastmodel.transform.api.dialect.DialectName;
  import com.aliyun.fastmodel.transform.api.dialect.DialectNode;
  import com.aliyun.fastmodel.transform.hologres.client.property.HologresPropertyKey;
  import com.aliyun.fastmodel.transform.hologres.dialect.HologresVersion;
  import com.aliyun.fastmodel.transform.hologres.parser.tree.datatype.HologresDataTypeName;
  import com.google.common.collect.Lists;
  import org.junit.Test;
  
  import static org.junit.Assert.assertEquals;
  
  /**
   * code generator
   *
   * @author panguanjing
   * @date 2022/6/10
   */
  public class HologresCodeGeneratorModelTest {
  
      @Test
      public void testGeneratorNewTable() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = getTable("c1", "c1", 1000L);
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining(",\n")), "BEGIN;\n"
              + "CREATE TABLE IF NOT EXISTS a (\n"
              + "   c1 TEXT NOT NULL\n"
              + ");\n"
              + "CALL SET_TABLE_PROPERTY('a', 'time_to_live_in_seconds', '1000');\n"
              + "COMMENT ON COLUMN a.c1 IS 'comment';\n"
              + "COMMIT;");
      }
  
      @Test
      public void testGeneratorNewTableWithBefore() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = getTable("c1", "c1", 1000L);
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          Table beforeTable = getTable("c1", "c1", 500L);
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .before(beforeTable)
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining(",\n")), "BEGIN;\n"
              + "CALL SET_TABLE_PROPERTY('a', 'time_to_live_in_seconds', '1000');\n"
              + "COMMIT;");
      }
  
      @Test
      public void testGeneratorNewTableWithRenameColumn() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = getTable("c1", "c2", 1000L);
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          Table beforeTable = getTable("c1", "c1", 500L);
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .before(beforeTable)
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining("\n")), "BEGIN;\n"
              + "ALTER TABLE a RENAME COLUMN c1 TO c2;\n"
              + "COMMIT;\n"
              + "BEGIN;\n"
              + "CALL SET_TABLE_PROPERTY('a', 'time_to_live_in_seconds', '1000');\n"
              + "COMMIT;");
      }
  
      @Test
      public void testGeneratorNewTableWithAddColumn() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = getTable("c1", "c2", 1000L);
          table.getColumns().add(
              Column.builder()
                  .name("c3")
                  .dataType("json")
                  .build()
          );
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          Table beforeTable = getTable("c1", "c1", 500L);
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .before(beforeTable)
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining("\n")), "BEGIN;\n"
              + "ALTER TABLE a RENAME COLUMN c1 TO c2;\n"
              + "COMMIT;\n"
              + "BEGIN;\n"
              + "ALTER TABLE IF EXISTS a ADD COLUMN c3 JSON;\n"
              + "COMMIT;\n"
              + "BEGIN;\n"
              + "CALL SET_TABLE_PROPERTY('a', 'time_to_live_in_seconds', '1000');\n"
              + "COMMIT;");
      }
  
      @Test
      public void testGeneratorNewTableWithDropColumn() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = getTable("c1", "c2", 1000L);
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          Table beforeTable = getTable("c1", "c1", 500L);
          beforeTable.getColumns().add(
              Column.builder()
                  .name("c3")
                  .dataType("json")
                  .build()
          );
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .before(beforeTable)
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining("\n")), "BEGIN;\n"
              + "ALTER TABLE a RENAME COLUMN c1 TO c2;\n"
              + "COMMIT;\n"
              + "ALTER TABLE a DROP COLUMN c3;\n"
              + "BEGIN;\n"
              + "CALL SET_TABLE_PROPERTY('a', 'time_to_live_in_seconds', '1000');\n"
              + "COMMIT;");
      }
  
      @Test
      public void testGeneratorNewTableWithSchema() {
          CodeGenerator codeGenerator = new DefaultCodeGenerator();
          Table table = Table.builder()
              .schema("sc")
              .name("tb")
              .columns(getColumns("c1", "c1"))
              .build();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
  
          DdlGeneratorModelRequest request = DdlGeneratorModelRequest.builder()
              .before(null)
              .after(table)
              .config(config)
              .build();
          DdlGeneratorResult generate = codeGenerator.generate(request);
          List<DialectNode> dialectNodes = generate.getDialectNodes();
          assertEquals(dialectNodes.stream().map(DialectNode::getNode).collect(Collectors.joining(",\n")), "BEGIN;\n"
              + "CREATE TABLE IF NOT EXISTS sc.tb (\n"
              + "   c1 TEXT NOT NULL\n"
              + ");\n\n"
              + "COMMENT ON COLUMN sc.tb.c1 IS 'comment';\n"
              + "COMMIT;");
      }
  
      private Table getTable(String id, String name, long lifeCycleSeconds) {
          List<Column> columns = getColumns(id, name);
          return Table.builder()
              .name("a")
              .columns(columns)
              .lifecycleSeconds(lifeCycleSeconds)
              .build();
      }
  
      private List<Column> getColumns(String id, String name) {
          return Lists.newArrayList(
              Column.builder()
                  .id(id)
                  .name(name)
                  .dataType("text")
                  .comment("comment")
                  .build()
          );
      }
  
      @Test
      public void testConvertToTable() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlReverseSqlRequest request = DdlReverseSqlRequest.builder()
              .database("d1")
              .schema("c1")
              .code("create table if not exists a (b text);")
              .dialectMeta(DialectMeta.DEFAULT_HOLO).build();
          DdlTableResult reverse = defaultCodeGenerator.reverse(request);
          Table table = reverse.getTable();
          assertEquals(table.getDatabase(), "d1");
          assertEquals(table.getSchema(), "c1");
          assertEquals(table.getName(), "a");
          assertEquals(table.getColumns().size(), 1);
      }
  
      /**
       * 如果注释里含有单引号的问题
       */
      @Test
      public void testGeneratorWithCommentInvalid() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlGeneratorModelRequest request = new DdlGeneratorModelRequest();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          request.setConfig(config);
          request.setAfter(Table.builder()
              .name("abc")
              .columns(getColumns(null, "a"))
              .comment("'abc")
              .build());
          DdlGeneratorResult generate = defaultCodeGenerator.generate(request);
          assertEquals("BEGIN;\n"
              + "CREATE TABLE IF NOT EXISTS abc (\n"
              + "   a TEXT NOT NULL\n"
              + ");\n"
              + "COMMENT ON TABLE abc IS '''abc';\n"
              + "COMMENT ON COLUMN abc.a IS 'comment';\n"
              + "COMMIT;", generate.getDialectNodes().get(0).getNode());
      }
  
      @Test
      public void testGeneratorWithSchema() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlGeneratorModelRequest request = new DdlGeneratorModelRequest();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          request.setConfig(config);
          request.setAfter(Table.builder()
              .name("abc")
              .schema("schema")
              .columns(getColumns(null, "a"))
              .comment("'abc")
              .build());
          DdlGeneratorResult generate = defaultCodeGenerator.generate(request);
          assertEquals("BEGIN;\n"
              + "CREATE TABLE IF NOT EXISTS \"schema\".abc (\n"
              + "   a TEXT NOT NULL\n"
              + ");\n"
              + "COMMENT ON TABLE \"schema\".abc IS '''abc';\n"
              + "COMMENT ON COLUMN \"schema\".abc.a IS 'comment';\n"
              + "COMMIT;", generate.getDialectNodes().get(0).getNode());
      }
  
      @Test
      public void testGeneratorWithDefaultValue() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlGeneratorModelRequest request = new DdlGeneratorModelRequest();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          request.setConfig(config);
          List<Column> columns = Lists.newArrayList(
              Column.builder()
                  .name("d_v")
                  .dataType("text")
                  .defaultValue("abc")
                  .comment("comment")
                  .build()
          );
          request.setAfter(Table.builder()
              .name("abc")
              .schema("schema")
              .columns(columns)
              .comment("'abc")
              .build());
          DdlGeneratorResult generate = defaultCodeGenerator.generate(request);
          assertEquals("BEGIN;\n"
              + "CREATE TABLE IF NOT EXISTS \"schema\".abc (\n"
              + "   d_v TEXT NOT NULL DEFAULT 'abc'\n"
              + ");\n"
              + "COMMENT ON TABLE \"schema\".abc IS '''abc';\n"
              + "COMMENT ON COLUMN \"schema\".abc.d_v IS 'comment';\n"
              + "COMMIT;", generate.getDialectNodes().get(0).getNode());
      }
  
      @Test
      public void testGeneratorWithRoaringbitmap() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlGeneratorModelRequest request = new DdlGeneratorModelRequest();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.DEFAULT_HOLO)
              .caseSensitive(false)
              .build();
          request.setConfig(config);
          List<Column> a = Lists.newArrayList(
              Column.builder()
                  .id("c1")
                  .name("c1")
                  .dataType(HologresDataTypeName.ROARING_BITMAP.getValue())
                  .comment("comment")
                  .nullable(true)
                  .build()
          );
          request.setAfter(Table.builder()
              .name("abc")
              .schema("schema")
              .columns(a)
              .comment("'abc")
              .build());
          DdlGeneratorResult generate = defaultCodeGenerator.generate(request);
          assertEquals("BEGIN;\n"
              + "CREATE EXTENSION IF NOT EXISTS ROARINGBITMAP;\n"
              + "CREATE TABLE IF NOT EXISTS \"schema\".abc (\n"
              + "   c1 ROARINGBITMAP\n"
              + ");\n"
              + "COMMENT ON TABLE \"schema\".abc IS '''abc';\n"
              + "COMMENT ON COLUMN \"schema\".abc.c1 IS 'comment';\n"
              + "COMMIT;", generate.getDialectNodes().get(0).getNode());
      }
  
      @Test
      public void testGeneratorDynamicTable() {
          DefaultCodeGenerator defaultCodeGenerator = new DefaultCodeGenerator();
          DdlGeneratorModelRequest request = new DdlGeneratorModelRequest();
          TableConfig config = TableConfig.builder()
              .dialectMeta(DialectMeta.getByNameAndVersion(DialectName.HOLOGRES.getName(), HologresVersion.V3))
              .caseSensitive(false)
              .build();
          request.setConfig(config);
          List<Column> a = Lists.newArrayList(
              Column.builder()
                  .id("c1")
                  .name("c1")
                  .build()
          );
          List<BaseClientProperty> properties = Lists.newArrayList();
          StringProperty property = new StringProperty();
          property.setKey("refresh_mode");
          property.setValue("incremental");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey("auto_refresh_enable");
          property.setValue("true");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey("incremental_auto_refresh_schd_start_time");
          property.setValue("2024-09-15 23:50:0");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey("incremental_auto_refresh_interval");
          property.setValue("3 minutes");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey("incremental_guc_hg_computing_resource");
          property.setValue("serverless");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey("incremental_guc_hg_experimental_serverless_computing_required_cores");
          property.setValue("30");
          properties.add(property);
  
          property = new StringProperty();
          property.setKey(HologresPropertyKey.TASK_DEFINITION.getValue());
          property.setValue("select\n"
              + "        l_returnflag,\n"
              + "        l_linestatus,\n"
              + "        count(*) as count_order\n"
              + "from\n"
              + "        hologres_dataset_tpch_100g.lineitem\n"
              + "where\n"
              + "        l_shipdate <= date '1998-12-01' - interval '120' day\n"
              + "group by\n"
              + "        l_returnflag,\n"
              + "        l_linestatus\n"
              + ";");
          properties.add(property);
          /**
           * refresh_mode='incremental',
           * auto_refresh_enable='true',
           * incremental_auto_refresh_schd_start_time='2024-09-15 23:50:0',
           * incremental_auto_refresh_interval='3 minutes',
           * incremental_guc_hg_computing_resource='serverless',
           * incremental_guc_hg_experimental_serverless_computing_required_cores='30'
           */
          Table table = Table.builder()
              .dynamic(true)
              .ifNotExist(false)
              .name("abc")
              .schema("schema")
              .columns(a)
              .comment("abc")
              .properties(properties)
              .build();
          request.setAfter(table);
          DdlGeneratorResult generate = defaultCodeGenerator.generate(request);
          assertEquals("BEGIN;\n"
              + "CREATE DYNAMIC TABLE \"schema\".abc (\n"
              + "   c1\n"
              + ")\n"
              + "WITH (\n"
              + "   refresh_mode='incremental',\n"
              + "   auto_refresh_enable='true',\n"
              + "   incremental_auto_refresh_schd_start_time='2024-09-15 23:50:0',\n"
              + "   incremental_auto_refresh_interval='3 minutes',\n"
              + "   incremental_guc_hg_computing_resource='serverless',\n"
              + "   incremental_guc_hg_experimental_serverless_computing_required_cores='30'\n"
              + ") AS\n"
              + "select\n"
              + "        l_returnflag,\n"
              + "        l_linestatus,\n"
              + "        count(*) as count_order\n"
              + "from\n"
              + "        hologres_dataset_tpch_100g.lineitem\n"
              + "where\n"
              + "        l_shipdate <= date '1998-12-01' - interval '120' day\n"
              + "group by\n"
              + "        l_returnflag,\n"
              + "        l_linestatus\n"
              + ";\n"
              + "COMMIT;\n"
              + "BEGIN;\n"
              + "COMMENT ON TABLE \"schema\".abc IS 'abc';\n"
              + "COMMIT;", generate.getDialectNodes().get(0).getNode());
      }
  }
  