package org.minimalj.backend.db;

import java.sql.PreparedStatement;
import java.sql.SQLException;

import org.minimalj.util.CodeUtils;
import org.minimalj.util.IdUtils;
import org.minimalj.util.LoggingRuntimeException;
import org.minimalj.util.StringUtils;

/**
 * Minimal-J internal<p>
 * 
 * Rows in a immutable table are created and reused. But
 * they are never changed nor deleted.
 * 
 * Code tables don't need an id. The unique field in
 * the code class is used instead of a generated id.
 * 
 */
public class CodeTable<T> extends Table<T> {
	
	protected final String selectByCodeQuery;
	
	public CodeTable(DbPersistence dbPersistence, Class<T> clazz) {
		super(dbPersistence, clazz);
		if (!CodeUtils.isCode(clazz)) {
			throw new IllegalArgumentException(clazz.getName());
		}
		this.selectByCodeQuery = selectByCodeQuery();
	}
	
	@Override
	protected void addSpecialColumns(DbSyntax syntax, StringBuilder s) {
		// for codes an INT column as ID is enough
		syntax.addIdColumn(s, false);
	}
	
	@Override
	public void createTable(DbSyntax syntax) {
		super.createTable(syntax);
		execute(syntax.createUniqueIndex(getTableName(), StringUtils.toDbName(CodeUtils.getCodeProperty(clazz).getFieldName())));
	}

	public void update(T object) {
		Object code = CodeUtils.getCode(object);
		Object existingObject = readByCode(code);
		long id = IdUtils.getId(existingObject);
		super.update(id, object);
	}
	
	public T readByCode(Object code) {
		try {
			PreparedStatement selectByCodeStatement = getStatement(dbPersistence.getConnection(), selectByCodeQuery, false);
			selectByCodeStatement.setObject(1, code);
			T object = executeSelect(selectByCodeStatement);
			return object;
		} catch (SQLException x) {
			throw new LoggingRuntimeException(x, sqlLogger, "Couldn't read " + getTableName() + " with code " + code);
		}
	}

	protected String selectByCodeQuery() {
		StringBuilder query = new StringBuilder();
		query.append("SELECT * FROM "); query.append(getTableName()); 
		query.append(" WHERE ");
		query.append(StringUtils.toDbName(CodeUtils.getCodeProperty(clazz).getFieldName()));
		query.append(" = ?");
		return query.toString();
	}

}

@@ -65,16 +65,44 @@
 ement;%0D%0A
+import java.sql.ResultSet;%0D%0A
 import j
@@ -167,43 +167,8 @@
 s;%0D%0A
-import org.minimalj.util.IdUtils;%0D%0A
 impo
@@ -605,16 +605,62 @@
 Query;%0D%0A
+%09protected final String selectIdByCodeQuery;%0D%0A
 %09%0D%0A%09publ
@@ -894,16 +894,76 @@
 deQuery(
+false);%0D%0A%09%09this.selectIdByCodeQuery = selectByCodeQuery(true
 );%0D%0A%09%7D%0D%0A
@@ -1435,36 +1435,24 @@
 %0D%0A%09%09
-Object existingObject
+long id
  = read
+Id
 ByCo
@@ -1466,52 +1466,8 @@
 );%0D%0A
-%09%09long id = IdUtils.getId(existingObject);%0D%0A
 %09%09su
@@ -1931,16 +1931,604 @@
 %0D%0A%09%7D%0D%0A%0D%0A
+%09public int readIdByCode(Object code) %7B%0D%0A%09%09try %7B%0D%0A%09%09%09PreparedStatement selectByCodeStatement = getStatement(dbPersistence.getConnection(), selectIdByCodeQuery, false);%0D%0A%09%09%09selectByCodeStatement.setObject(1, code);%0D%0A%09%09%09try (ResultSet resultSet = selectByCodeStatement.executeQuery()) %7B%0D%0A%09%09%09%09if (!resultSet.next()) %7B%0D%0A%09%09%09%09%09throw new IllegalArgumentException(%22No id found for code %22 + code);%0D%0A%09%09%09%09%7D%0D%0A%09%09%09%09return resultSet.getInt(1);%0D%0A%09%09%09%7D%0D%0A%09%09%7D catch (SQLException x) %7B%0D%0A%09%09%09throw new LoggingRuntimeException(x, sqlLogger, %22Couldn't read %22 + getTableName() + %22 with code %22 + code);%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%0D%0A
 %09protect
@@ -2555,16 +2555,30 @@
 deQuery(
+boolean onlyId
 ) %7B%0D%0A%09%09S
@@ -2643,17 +2643,77 @@
 %22SELECT 
-*
+%22); %0D%0A%09%09query.append(onlyId ? %22ID%22 : %22*%22); %0D%0A%09%09query.append(%22
  FROM %22)
@@ -2714,16 +2714,20 @@
 ROM %22); 
+%0D%0A%09%09
 query.ap

update corrected