/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * Licensed 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 woolpack.crud;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import woolpack.adapter.HSQLDBConstants;


import junit.framework.TestCase;

public class CrudConstantsTest extends TestCase {

	public void testInsertFull() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("mySeq", Arrays.asList((Object)"mySeq0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		map.put("myInt", Arrays.asList((Object)"myInt0"));
		final Expression expression = CrudConstants.INSERT.newInstance(info, map);
		assertEquals("INSERT INTO my_table(my_id, my_seq, my_string, my_int) VALUES (?, ?, ?, ?)", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("mySeq", 0),
				new InputMapPointer("myString", 0),
				new InputMapPointer("myInt", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testInsertPart() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		final Expression expression = CrudConstants.INSERT.newInstance(info, map);
		assertEquals("INSERT INTO my_table(my_id, my_string) VALUES (?, ?)", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("myString", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testSelectFull() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("mySeq", Arrays.asList((Object)"mySeq0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		map.put("myInt", Arrays.asList((Object)"myInt0"));
		final Expression expression = CrudConstants.SELECT.newInstance(info, map);
		assertEquals("SELECT my_id, my_seq, my_string, my_int FROM my_table" +
				" WHERE my_id = ? AND my_seq = ? AND my_string = ? AND my_int = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("mySeq", 0),
				new InputMapPointer("myString", 0),
				new InputMapPointer("myInt", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testSelectPart() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		final Expression expression = CrudConstants.SELECT.newInstance(info, map);
		assertEquals("SELECT my_id, my_seq, my_string, my_int FROM my_table WHERE my_id = ? AND my_string = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("myString", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testSelectOrder1() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("mySeq", Arrays.asList((Object)"mySeq0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		map.put("myInt", Arrays.asList((Object)"myInt0"));
		map.put("myStringOrder", Arrays.asList((Object)"2"));
		map.put("myIdOrder", Arrays.asList((Object)"-3"));
		final Expression expression = CrudConstants.getSelectExpressionFactory2(Pattern.compile("(.*)Order")).newInstance(info, map);
		assertEquals("SELECT my_id, my_seq, my_string, my_int FROM my_table" +
				" WHERE my_id = ? AND my_seq = ? AND my_string = ? AND my_int = ?" +
				" ORDER BY MY_STRING ASC, MY_ID DESC", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("mySeq", 0),
				new InputMapPointer("myString", 0),
				new InputMapPointer("myInt", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testSelectRange() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myInt", Arrays.asList((Object)Integer.valueOf(3), Integer.valueOf(5)));
		final Expression expression = CrudConstants.SELECT.newInstance(info, map);
		assertEquals("SELECT my_id, my_seq, my_string, my_int FROM my_table WHERE my_int >= ? AND my_int <= ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myInt", 0),
				new InputMapPointer("myInt", 1)
				),
				expression.getInputMapPointerList());
	}

	public void testUpdateFull() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("mySeq", Arrays.asList((Object)"mySeq0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		map.put("myInt", Arrays.asList((Object)"myInt0"));
		final Expression expression = CrudConstants.UPDATE.newInstance(info, map);
		assertEquals("UPDATE my_table SET my_string = ?, my_int = ?  WHERE my_id = ? AND my_seq = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myString", 0),
				new InputMapPointer("myInt", 0),
				new InputMapPointer("myId", 0),
				new InputMapPointer("mySeq", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testUpdatePart() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		final Expression expression = CrudConstants.UPDATE.newInstance(info, map);
		assertEquals("UPDATE my_table SET my_string = ?  WHERE my_id = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myString", 0),
				new InputMapPointer("myId", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testDeleteFull() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("mySeq", Arrays.asList((Object)"mySeq0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		map.put("myInt", Arrays.asList((Object)"myInt0"));
		final Expression expression = CrudConstants.DELETE.newInstance(info, map);
		assertEquals("DELETE FROM my_table WHERE my_id = ? AND my_seq = ? AND my_string = ? AND my_int = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("mySeq", 0),
				new InputMapPointer("myString", 0),
				new InputMapPointer("myInt", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testDeletePart() {
		final TableInfo info = CrudAllTests.getTableInfo();
		final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
		map.put("myId", Arrays.asList((Object)"myId0"));
		map.put("myString", Arrays.asList((Object)"myString0"));
		final Expression expression = CrudConstants.DELETE.newInstance(info, map);
		assertEquals("DELETE FROM my_table WHERE my_id = ? AND my_string = ?", expression.getQuery());
		assertEquals(Arrays.asList(
				new InputMapPointer("myId", 0),
				new InputMapPointer("myString", 0)
				),
				expression.getInputMapPointerList());
	}

	public void testGetTableInfoList() {
		final DataSource dataSource = HSQLDBConstants.getMemoryDataSource("mydb0_CrudConstantsTest0");
		new FixUpdater("create memory table my_table (" +
				"my_id integer, " +
				"my_seq integer, " +
				"my_string varchar, " +
				"my_int integer, " +
				"constraint MYTALBE0P primary key (my_id, my_seq))", dataSource).update(null);
		
		final List<TableInfo> result = CrudConstants.getTableInfoList(dataSource);
		assertEquals(1, result.size());
		assertEquals("MY_TABLE", result.get(0).getName());
		assertEquals(Arrays.asList("MY_ID", "MY_SEQ", "MY_STRING", "MY_INT"), result.get(0).getColumnCollection());
		assertEquals(Arrays.asList("MY_ID", "MY_SEQ"), result.get(0).getPrimaryKeyCollection());
	}
	
	public void testConvertJavaNameTableInfoMap() {
		final TableInfo info0 = CrudAllTests.getTableInfo();
		final TableInfo info1 = CrudAllTests.getTableInfo();
		info1.setName("my_table1");
		final Map<String, TableInfo> result = CrudConstants.convertJavaNameTableInfoMap(Arrays.asList(info0, info1));
		final Map<String, TableInfo> expected = new HashMap<String, TableInfo>();
		expected.put("myTable", info0);
		expected.put("myTable1", info1);
		assertEquals(expected, result);
	}
	
	public void testGetCrudFactory() {
		final DataSource dataSource = HSQLDBConstants.getMemoryDataSource("mydb1_CrudConstantsTest1");
		new FixUpdater("create memory table my_table (" +
				"my_id integer, " +
				"my_seq integer, " +
				"my_string varchar, " +
				"my_int integer, " +
				"constraint MYTALBE0P primary key (my_id, my_seq))", dataSource).update(null);
		final CrudFactory crudFactory = CrudConstants.getCrudFactory(
				dataSource,
				Pattern.compile("(.*)Order"),
				100,
				"startPosition",
				"recodeCount");
		
		// insert
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("myString", Arrays.asList((Object)"myString0"));
			map.put("myInt", Arrays.asList((Object)Integer.valueOf(0)));
			crudFactory.newInsertUpdatable("myTable", map).update(map);
		}
		
		// select
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(0)));
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			final Map<String, Object> expected = new HashMap<String, Object>();
			expected.put("myId", Integer.valueOf(0));
			expected.put("mySeq", Integer.valueOf(0));
			expected.put("myString", "myString0");
			expected.put("myInt", Integer.valueOf(0));
			assertEquals(Arrays.asList(expected), result);
		}
		
		// update
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("myString", Arrays.asList((Object)"myString1"));
			map.put("myInt", Arrays.asList((Object)Integer.valueOf(1)));
			crudFactory.newUpdateUpdatable("myTable", map).update(map);
		}
		
		// select
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(0)));
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			final Map<String, Object> expected = new HashMap<String, Object>();
			expected.put("myId", Integer.valueOf(0));
			expected.put("mySeq", Integer.valueOf(0));
			expected.put("myString", "myString1");
			expected.put("myInt", Integer.valueOf(1));
			assertEquals(Arrays.asList(expected), result);
		}
		
		// insert
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(1)));
			map.put("myString", Arrays.asList((Object)"myString10"));
			map.put("myInt", Arrays.asList((Object)Integer.valueOf(10)));
			crudFactory.newInsertUpdatable("myTable", map).update(map);
		}
		
		// select all
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			
			final Map<String, Object> expected0 = new HashMap<String, Object>();
			expected0.put("myId", Integer.valueOf(0));
			expected0.put("mySeq", Integer.valueOf(0));
			expected0.put("myString", "myString1");
			expected0.put("myInt", Integer.valueOf(1));
			
			final Map<String, Object> expected1 = new HashMap<String, Object>();
			expected1.put("myId", Integer.valueOf(0));
			expected1.put("mySeq", Integer.valueOf(1));
			expected1.put("myString", "myString10");
			expected1.put("myInt", Integer.valueOf(10));
			
			assertEquals(Arrays.asList(expected0, expected1), result);
		}
		
		// select order
		{
			final CrudFactory crudFactory2 = CrudConstants.getCrudFactory(
					dataSource,
					Pattern.compile("(.*)Order"),
					100,
					null,
					null);
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("mySeqOrder", Arrays.asList((Object)"-1"));
			final List<Map<String, Object>> result = crudFactory2.newSelectQuery("myTable", map).select(map);
			
			final Map<String, Object> expected0 = new HashMap<String, Object>();
			expected0.put("myId", Integer.valueOf(0));
			expected0.put("mySeq", Integer.valueOf(0));
			expected0.put("myString", "myString1");
			expected0.put("myInt", Integer.valueOf(1));
			
			final Map<String, Object> expected1 = new HashMap<String, Object>();
			expected1.put("myId", Integer.valueOf(0));
			expected1.put("mySeq", Integer.valueOf(1));
			expected1.put("myString", "myString10");
			expected1.put("myInt", Integer.valueOf(10));
			
			assertEquals(Arrays.asList(expected1, expected0), result);
		}
		
		// select part
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(1)));
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			final Map<String, Object> expected = new HashMap<String, Object>();
			expected.put("myId", Integer.valueOf(0));
			expected.put("mySeq", Integer.valueOf(1));
			expected.put("myString", "myString10");
			expected.put("myInt", Integer.valueOf(10));
			
			assertEquals(Arrays.asList(expected), result);
		}
		
		// select and row constraint1
		{
			final CrudFactory crudFactory2 = CrudConstants.getCrudFactory(
					dataSource,
					Pattern.compile("(.*)Order"),
					1,
					null,
					null);
			
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			final List<Map<String, Object>> result = crudFactory2.newSelectQuery("myTable", map).select(map);
			
			final Map<String, Object> expected0 = new HashMap<String, Object>();
			expected0.put("myId", Integer.valueOf(0));
			expected0.put("mySeq", Integer.valueOf(0));
			expected0.put("myString", "myString1");
			expected0.put("myInt", Integer.valueOf(1));
			
			assertEquals(Arrays.asList(expected0), result);
		}
		
		// select and row constraint2
		{
			final CrudFactory crudFactory2 = CrudConstants.getCrudFactory(
					dataSource,
					Pattern.compile("(.*)Order"),
					100,
					"startPosition",
					"count");
			
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("startPosition", Arrays.asList((Object)"0"));
			map.put("count", Arrays.asList((Object)"1"));
			final List<Map<String, Object>> result = crudFactory2.newSelectQuery("myTable", map).select(map);
			
			final Map<String, Object> expected0 = new HashMap<String, Object>();
			expected0.put("myId", Integer.valueOf(0));
			expected0.put("mySeq", Integer.valueOf(0));
			expected0.put("myString", "myString1");
			expected0.put("myInt", Integer.valueOf(1));
			
			assertEquals(Arrays.asList(expected0), result);
		}
		
		// select and row constraint3
		{
			final CrudFactory crudFactory2 = CrudConstants.getCrudFactory(
					dataSource,
					Pattern.compile("(.*)Order"),
					100,
					"startPosition",
					"count");
			
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("startPosition", Arrays.asList((Object)"1"));
			map.put("count", Arrays.asList((Object)"1"));
			final List<Map<String, Object>> result = crudFactory2.newSelectQuery("myTable", map).select(map);
			
			final Map<String, Object> expected1 = new HashMap<String, Object>();
			expected1.put("myId", Integer.valueOf(0));
			expected1.put("mySeq", Integer.valueOf(1));
			expected1.put("myString", "myString10");
			expected1.put("myInt", Integer.valueOf(10));
			
			assertEquals(Arrays.asList(expected1), result);
		}
		
		// delete
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("myString", Arrays.asList((Object)"myString1"));
			crudFactory.newDeleteUpdatable("myTable", map).update(map);
		} 
		
		// select
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			final Map<String, Object> expected = new HashMap<String, Object>();
			expected.put("myId", Integer.valueOf(0));
			expected.put("mySeq", Integer.valueOf(1));
			expected.put("myString", "myString10");
			expected.put("myInt", Integer.valueOf(10));
			assertEquals(Arrays.asList(expected), result);
		}
		
		// delete
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			map.put("myId", Arrays.asList((Object)Integer.valueOf(0)));
			map.put("mySeq", Arrays.asList((Object)Integer.valueOf(1)));
			crudFactory.newDeleteUpdatable("myTable", map).update(map);
		} 
		
		// select
		{
			final Map<String, List<Object>> map = new HashMap<String, List<Object>>();
			final List<Map<String, Object>> result = crudFactory.newSelectQuery("myTable", map).select(map);
			assertTrue(result.isEmpty());
		}
	}
}
