package com.github.davidmoten.rx.jdbc;

import static org.junit.Assert.assertEquals;

import java.sql.SQLException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.junit.Ignore;
import org.junit.Test;

import com.github.davidmoten.rx.jdbc.annotations.Column;

import rx.Observable;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.observers.TestSubscriber;

public class DatabaseExampleTest {

    @Test
    public void testCreateAndUseAnInMemoryDatabase() throws SQLException {
        // create an h2 in-memory database that does not get dropped when all
        // connections closed
        Database db = Database.from("jdbc:h2:mem:demo1;DB_CLOSE_DELAY=-1");
        db.update(
                "create table person (name varchar(50) primary key, score int not null,dob date, registered timestamp)")
                .count().toBlocking().single();

        assertEquals(2, db.update("insert into person(name,score) values(?,?)")
                .parameters("FRED", 21, "JOE", 34).execute());

        // use java 8 lambdas if you have them !
        db.select("select name, score from person").autoMap(Person.class)
                .forEach(new Action1<Person>() {
                    @Override
                    public void call(Person person) {
                        System.out.println(person.name() + " has score " + person.score());
                    }
                });
        db.close();
    }

    static interface Person {
        @Column
        String name();

        @Column
        int score();
    }

    @Test
    public void testParameterOperatorBackpressure() {
        // use composition to find the first person alphabetically with
        // a score less than the person with the last name alphabetically
        // whose name is not XAVIER. Two threads and connections will be used.

        Database db = DatabaseCreator.db();
        TestSubscriber<String> ts = TestSubscriber.create(0);
        Observable.just("FRED", "FRED").repeat()
                .lift(db.select("select name from person where name = ?").parameterOperator()
                        .getAs(String.class))
                .subscribe(ts);
        ts.requestMore(1);
        ts.assertValueCount(1);
        ts.unsubscribe();
    }

    @Test
    // ignore because infinite and doesn't test results yet apart from critical
    // failure
    @Ignore
    public void testBackpressureIssue38() {
        Database db = DatabaseCreator.db();
        final Long start = System.currentTimeMillis();
        final CountDownLatch latch = new CountDownLatch(1);
        Observable.interval(0, 1, TimeUnit.MILLISECONDS).onBackpressureLatest()
                // .doOnNext(t -> System.out.println("start " + t))
                .lift(db.select("SELECT * FROM (VALUES (?)) AS v").parameterOperator()
                        .getAs(String.class))
                // .doOnNext(t -> System.out.println("result " + t))
                .concatMap(new Func1<String, Observable<String>>() {

                    @Override
                    public Observable<String> call(String t) {
                        return Observable.<String> empty().delay(100, TimeUnit.MILLISECONDS)
                                .startWith(t);
                    }
                }).subscribe(new Subscriber<String>() {

                    @Override
                    public void onCompleted() {
                        System.out.println("completed");
                        latch.countDown();
                    }

                    @Override
                    public void onError(Throwable e) {
                        System.out.println("Something went wrong ");
                        e.printStackTrace();
                        latch.countDown();

                    }

                    @Override
                    public void onNext(String t) {
                        System.out.println("item " + t + " received at "
                                + (System.currentTimeMillis() - start) + "ms");

                    }
                });
        try {
            latch.await();
        } catch (InterruptedException e)
        // ignore
        {
            throw new RuntimeException(e);
        }
    }

}

@@ -109,16 +109,39 @@
 eption;%0A
+import java.util.List;%0A
 import j
@@ -2329,32 +2329,746 @@
 cribe();%0A    %7D%0A%0A
+    @Test%0A    public void testParameterListOperatorWithError() %7B%0A        // use composition to find the first person alphabetically with%0A        // a score less than the person with the last name alphabetically%0A        // whose name is not XAVIER. Two threads and connections will be used.%0A%0A        Database db = DatabaseCreator.db();%0A        TestSubscriber%3CString%3E ts = TestSubscriber.create();%0A        RuntimeException ex = new RuntimeException();%0A        Observable.%3CObservable%3CObject%3E%3Eerror(ex)%0A                .lift(db.select(%22select name from person where name = ?%22).parameterListOperator()%0A                        .getAs(String.class))%0A                .subscribe(ts);%0A        ts.assertError(ex);%0A    %7D%0A    %0A
     @Test%0A    //

add test error in parameterList