package org.sfm.jdbc;

import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sfm.beans.DbObject;
import org.sfm.jdbc.impl.ColumnMeta;
import org.sfm.jdbc.impl.CrudFactory;
import org.sfm.jdbc.impl.CrudMeta;
import org.sfm.jdbc.impl.DatabaseMeta;
import org.sfm.reflect.ReflectionService;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class CrudUpsertTest {

    Crud<DbObject, Long> objectCrud;

    {
        try {
            objectCrud =
                    CrudFactory.newInstance(
                    ReflectionService.newInstance().getClassMeta(DbObject.class),
                    ReflectionService.newInstance().getClassMeta(Long.class),
                    new CrudMeta(new DatabaseMeta("PostgreSQL", 5, 5), "TEST",
                            new ColumnMeta[]{
                                    new ColumnMeta("id", Types.INTEGER, true, false),
                                    new ColumnMeta("name", Types.VARCHAR, false, false)
                            }),
                    JdbcMapperFactory.newInstance());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    public void testUpsertDefaultCrud() throws SQLException {

        Connection connection = mock(Connection.class);
        PreparedStatement ps = mock(PreparedStatement.class);

        when(connection.prepareStatement(
                "INSERT INTO TEST(id, name) " +
                        "VALUES(?, ?) " +
                        "ON CONFLICT (id) " +
                        "DO UPDATE " +
                        "SET name = EXCLUDED.name", new String[0])).thenReturn(ps);

        DbObject o = DbObject.newInstance();
        objectCrud.createOrUpdate(connection, o);

        verify(ps).setLong(1, o.getId());
        verify(ps).setString(2, o.getName());
        verify(ps).executeUpdate();
    }

    @Test
    public void testUpsertDefaultCrudBatch() throws SQLException {

        Connection connection = mock(Connection.class);
        PreparedStatement ps = mock(PreparedStatement.class);

        when(connection.prepareStatement(
                "INSERT INTO TEST(id, name) " +
                        "VALUES(?, ?), (?, ?) " +
                        "ON CONFLICT (id) " +
                        "DO UPDATE " +
                        "SET name = EXCLUDED.name")).thenReturn(ps);

        List<DbObject> objects = Arrays.asList(DbObject.newInstance(), DbObject.newInstance());
        objectCrud.createOrUpdate(connection, objects);

        verify(ps).setLong(1, objects.get(0).getId());
        verify(ps).setString(2, objects.get(0).getName());
        verify(ps).setLong(3, objects.get(1).getId());
        verify(ps).setString(4, objects.get(1).getName());

        verify(ps).executeUpdate();
    }
}

@@ -43,43 +43,8 @@
 st;%0A
-import org.mockito.ArgumentCaptor;%0A
 impo
@@ -472,16 +472,53 @@
 Equals;%0A
+import static org.junit.Assert.fail;%0A
 import s
@@ -553,49 +553,8 @@
 ck;%0A
-import static org.mockito.Mockito.times;%0A
 impo
@@ -688,22 +688,26 @@
 , Long%3E 
-object
+postGresql
 Crud;%0A%0A 
@@ -733,30 +733,34 @@
             
-object
+postGresql
 Crud =%0A     
@@ -1431,32 +1431,855 @@
        %7D%0A    %7D%0A%0A
+    Crud%3CDbObject, Long%3E hsqlCrud;%0A%0A    %7B%0A        try %7B%0A            hsqlCrud =%0A                    CrudFactory.newInstance(%0A                            ReflectionService.newInstance().getClassMeta(DbObject.class),%0A                            ReflectionService.newInstance().getClassMeta(Long.class),%0A                            new CrudMeta(new DatabaseMeta(%22HsqlDB%22, 5, 5), %22TEST%22,%0A                                    new ColumnMeta%5B%5D%7B%0A                                            new ColumnMeta(%22id%22, Types.INTEGER, true, false),%0A                                            new ColumnMeta(%22name%22, Types.VARCHAR, false, false)%0A                                    %7D),%0A                            JdbcMapperFactory.newInstance());%0A        %7D catch (SQLException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A    %7D%0A
     @Test%0A    pu
@@ -2801,38 +2801,42 @@
 ance();%0A        
-object
+postGresql
 Crud.createOrUpd
@@ -3583,22 +3583,26 @@
         
-object
+postGresql
 Crud.cre
@@ -3906,11 +3906,496 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void testUpsertHsqlBatch() throws SQLException %7B%0A%0A        try %7B%0A            Connection connection = mock(Connection.class);%0A            PreparedStatement ps = mock(PreparedStatement.class);%0A%0A%0A            List%3CDbObject%3E objects = Arrays.asList(DbObject.newInstance(), DbObject.newInstance());%0A            hsqlCrud.createOrUpdate(connection, objects);%0A%0A            fail();%0A        %7D catch(UnsupportedOperationException e) %7B%0A            // expected%0A        %7D%0A%0A    %7D
 %0A%7D%0A

increase defaultcrud coverage