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 com.datastax.oss.driver.api.querybuilder.insert;
  
  import static com.datastax.oss.driver.api.querybuilder.Assertions.assertThat;
  import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.bindMarker;
  import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.insertInto;
  import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.literal;
  import static org.assertj.core.api.Assertions.catchThrowable;
  
  import com.datastax.oss.driver.api.core.data.CqlVector;
  import com.datastax.oss.driver.api.querybuilder.term.Term;
  import com.datastax.oss.driver.internal.querybuilder.insert.DefaultInsert;
  import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
  import java.util.Map;
  import org.junit.Test;
  
  public class RegularInsertTest {
  
    @Test
    public void should_generate_column_assignments() {
      assertThat(insertInto("foo").value("a", literal(1)).value("b", literal(2)))
          .hasCql("INSERT INTO foo (a,b) VALUES (1,2)");
      assertThat(insertInto("ks", "foo").value("a", literal(1)).value("b", literal(2)))
          .hasCql("INSERT INTO ks.foo (a,b) VALUES (1,2)");
      assertThat(insertInto("foo").value("a", bindMarker()).value("b", bindMarker()))
          .hasCql("INSERT INTO foo (a,b) VALUES (?,?)");
    }
  
    @Test
    public void should_generate_vector_literals() {
      assertThat(insertInto("foo").value("a", literal(CqlVector.newInstance(0.1, 0.2, 0.3))))
          .hasCql("INSERT INTO foo (a) VALUES ([0.1, 0.2, 0.3])");
    }
  
    @Test
    public void should_keep_last_assignment_if_column_listed_twice() {
      assertThat(
              insertInto("foo")
                  .value("a", bindMarker())
                  .value("b", bindMarker())
                  .value("a", literal(1)))
          .hasCql("INSERT INTO foo (b,a) VALUES (?,1)");
    }
  
    @Test
    public void should_generate_bulk_column_assignments() {
      Map<String, Term> assignments = ImmutableMap.of("a", literal(1), "b", literal(2));
      assertThat(insertInto("ks", "foo").values(assignments))
          .hasCql("INSERT INTO ks.foo (a,b) VALUES (1,2)");
  
      assertThat(
              insertInto("ks", "foo")
                  .value("a", literal(2))
                  .value("c", literal(3))
                  .values(assignments))
          .hasCql("INSERT INTO ks.foo (c,a,b) VALUES (3,1,2)");
    }
  
    @Test
    public void should_generate_if_not_exists_clause() {
      assertThat(insertInto("foo").value("a", bindMarker()).ifNotExists())
          .hasCql("INSERT INTO foo (a) VALUES (?) IF NOT EXISTS");
    }
  
    @Test
    public void should_generate_using_timestamp_clause() {
      assertThat(insertInto("foo").value("a", bindMarker()).usingTimestamp(1))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TIMESTAMP 1");
      assertThat(insertInto("foo").value("a", bindMarker()).usingTimestamp(bindMarker()))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TIMESTAMP ?");
    }
  
    @Test
    public void should_use_last_timestamp_if_called_multiple_times() {
      assertThat(
              insertInto("foo")
                  .value("a", bindMarker())
                  .usingTimestamp(1)
                  .usingTimestamp(2)
                  .usingTimestamp(3))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TIMESTAMP 3");
    }
  
    @Test
    public void should_generate_if_not_exists_and_timestamp_clauses() {
      assertThat(insertInto("foo").value("a", bindMarker()).ifNotExists().usingTimestamp(1))
          .hasCql("INSERT INTO foo (a) VALUES (?) IF NOT EXISTS USING TIMESTAMP 1");
    }
  
    @Test
    public void should_generate_ttl_clause() {
      assertThat(insertInto("foo").value("a", bindMarker()).usingTtl(10))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TTL 10");
    }
  
    @Test
    public void should_use_last_ttl_if_called_multiple_times() {
      assertThat(insertInto("foo").value("a", bindMarker()).usingTtl(10).usingTtl(20).usingTtl(30))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TTL 30");
    }
  
    @Test
    public void should_generate_using_timestamp_and_ttl_clauses() {
      assertThat(insertInto("foo").value("a", bindMarker()).usingTtl(10).usingTimestamp(30l))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TIMESTAMP 30 AND TTL 10");
      // order of TTL and TIMESTAMP method calls should not change the order of the generated clauses
      assertThat(insertInto("foo").value("a", bindMarker()).usingTimestamp(30l).usingTtl(10))
          .hasCql("INSERT INTO foo (a) VALUES (?) USING TIMESTAMP 30 AND TTL 10");
    }
  
    @Test
    public void should_throw_exception_with_invalid_ttl() {
      DefaultInsert defaultInsert =
          (DefaultInsert) insertInto("foo").value("a", bindMarker()).usingTtl(10);
  
      Throwable t =
          catchThrowable(
              () ->
                  new DefaultInsert(
                      defaultInsert.getKeyspace(),
                      defaultInsert.getTable(),
                      (Term) defaultInsert.getJson(),
                      defaultInsert.getMissingJsonBehavior(),
                      defaultInsert.getAssignments(),
                      defaultInsert.getTimestamp(),
                      new Object(), // invalid TTL object
                      defaultInsert.isIfNotExists()));
  
      assertThat(t)
          .isInstanceOf(IllegalArgumentException.class)
          .hasMessage("TTL value must be a BindMarker or an Integer");
    }
  
    @Test
    public void should_throw_exception_with_invalid_timestamp() {
      DefaultInsert defaultInsert =
          (DefaultInsert) insertInto("foo").value("a", bindMarker()).usingTimestamp(1);
  
      Throwable t =
          catchThrowable(
              () ->
                  new DefaultInsert(
                      defaultInsert.getKeyspace(),
                      defaultInsert.getTable(),
                      (Term) defaultInsert.getJson(),
                      defaultInsert.getMissingJsonBehavior(),
                      defaultInsert.getAssignments(),
                      new Object(), // invalid timestamp object)
                      defaultInsert.getTtlInSeconds(),
                      defaultInsert.isIfNotExists()));
      assertThat(t)
          .isInstanceOf(IllegalArgumentException.class)
          .hasMessage("TIMESTAMP value must be a BindMarker or a Long");
    }
  }
  