package com.vladmihalcea.book.hpjp.hibernate.type;

import com.vladmihalcea.book.hpjp.util.AbstractPostgreSQLIntegrationTest;
import org.hibernate.Session;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.junit.Test;

import javax.persistence.*;
import java.net.UnknownHostException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.atomic.AtomicReference;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * @author Vlad Mihalcea
 */
public class IPv4TypeTest extends AbstractPostgreSQLIntegrationTest {

    @Override
    protected Class<?>[] entities() {
        return new Class<?>[] {
            Event.class
        };
    }

    private Event _event;

    @Override
    public void afterInit() {
        doInJDBC(connection -> {
            try (Statement statement = connection.createStatement()) {
                statement.executeUpdate("CREATE INDEX ON event USING gist (ip inet_ops)");
            } catch (SQLException e) {
                fail(e.getMessage());
            }
        });

        _event = doInJPA(entityManager -> {
            entityManager.persist(new Event());

            Event event = new Event();
            event.setIp("192.168.0.123/24");
            entityManager.persist(event);

            return event;
        });
    }

    @Test
    public void testFindById() {
        Event updatedEvent = doInJPA(entityManager -> {
            Event event = entityManager.find(Event.class, _event.getId());

            assertEquals("192.168.0.123/24", event.getIp().getAddress());
            assertEquals("192.168.0.123", event.getIp().toInetAddress().getHostAddress());

            event.setIp("192.168.0.231/24");

            return event;
        });

        assertEquals("192.168.0.231/24", updatedEvent.getIp().getAddress());
    }

    @Test
    public void testJPQLQuery() {
        doInJPA(entityManager -> {
            Event event = entityManager.createQuery(
                "select e " +
                "from Event e " +
                "where " +
                "   ip is not null", Event.class)
            .getSingleResult();

            assertEquals("192.168.0.123/24", event.getIp().getAddress());
        });
    }

    @Test
    public void testNativeQuery() {
        doInJPA(entityManager -> {
            Event event = (Event) entityManager.createNativeQuery(
                "SELECT e.* " +
                "FROM event e " +
                "WHERE " +
                "   e.ip && CAST(:network AS inet) = true", Event.class)
            .setParameter("network", "192.168.0.1/24")
            .getSingleResult();

            assertEquals("192.168.0.123/24", event.getIp().getAddress());
        });
    }


    @Test
    public void testJDBCQuery() {
        doInJPA(entityManager -> {
            Session session = entityManager.unwrap(Session.class);
            session.doWork(connection -> {
                try(PreparedStatement ps = connection.prepareStatement(
                    "SELECT * " +
                    "FROM Event e " +
                    "WHERE " +
                    "   e.ip && ?::inet = true"
                )) {
                    ps.setObject(1, "192.168.0.1/24");
                    ResultSet rs = ps.executeQuery();
                    while(rs.next()) {
                        Long id = rs.getLong(1);
                        String ip = rs.getString(2);
                        assertEquals("192.168.0.123/24", ip);
                    }
                }
            });
        });
    }

    @Entity(name = "Event")
    @Table(name = "event")
    @TypeDef(name = "ipv4", typeClass = IPv4Type.class, defaultForType = IPv4.class)
    public static class Event {

        @Id
        @GeneratedValue
        private Long id;

        @Column(name = "ip", columnDefinition = "inet")
        private IPv4 ip;

        public Long getId() {
            return id;
        }

        public IPv4 getIp() {
            return ip;
        }

        public void setIp(String address) {
            this.ip = new IPv4(address);
        }
    }
}

@@ -2077,24 +2077,27 @@
 createQuery(
+%22%22%22
 %0A           
@@ -2105,17 +2105,16 @@
     
-%22
 select e
  %22 +
@@ -2109,20 +2109,16 @@
 select e
- %22 +
 %0A       
@@ -2126,17 +2126,16 @@
         
-%22
 from Eve
@@ -2130,36 +2130,32 @@
     from Event e
- %22 +
 %0A               
@@ -2159,18 +2159,13 @@
     
-%22
 where
- %22 +
 %0A   
@@ -2177,17 +2177,16 @@
         
-%22
    ip is
@@ -2194,16 +2194,35 @@
 not null
+%0A                %22%22
 %22, Event
@@ -2502,16 +2502,19 @@
 veQuery(
+%22%22%22
 %0A       
@@ -2518,25 +2518,24 @@
             
-%22
 SELECT e.* %22
@@ -2532,20 +2532,16 @@
 LECT e.*
- %22 +
 %0A       
@@ -2545,25 +2545,24 @@
             
-%22
 FROM event e
@@ -2557,28 +2557,24 @@
 FROM event e
- %22 +
 %0A           
@@ -2574,34 +2574,29 @@
             
-%22
 WHERE
- %22 +
 %0A           
@@ -2592,33 +2592,32 @@
                 
-%22
    e.ip && CAST(
@@ -2640,16 +2640,35 @@
 ) = true
+%0A                %22%22
 %22, Event
@@ -3117,16 +3117,19 @@
 atement(
+%22%22%22
 %0A       
@@ -3145,17 +3145,16 @@
     
-%22
 SELECT *
  %22 +
@@ -3149,20 +3149,16 @@
 SELECT *
- %22 +
 %0A       
@@ -3170,17 +3170,16 @@
         
-%22
 FROM Eve
@@ -3182,20 +3182,16 @@
  Event e
- %22 +
 %0A       
@@ -3207,19 +3207,16 @@
     
-%22
 WHERE
- %22 +%0A
+%0A  
     
@@ -3230,18 +3230,16 @@
         
- %22
    e.ip 
@@ -3255,16 +3255,39 @@
 t = true
+%0A                    %22%22
 %22%0A      

Switch to Text Blocks