<commit_before>/*
 *    Copyright 2010, <NAME>

   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 de.splitstudio.androidb;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;
import de.splitstudio.androidb.annotation.Column;
import de.splitstudio.androidb.annotation.ColumnHelper;
import de.splitstudio.androidb.annotation.TableMetaData;

/**
 * {@link Table} is the superclass for your database objects. It provides all CRUD Methods {@link #save()},
 * {@link #insert()}, {@link #delete()}, {@link #update()}, {@link #find()} and {@link #all()} to manipulate your object
 * in the db. It holds the {@link #PRIMARY_KEY} to be able to manage all operations.
 * 
 * @author <NAME>
 * @since 2010
 */
public abstract class Table {

	/** String represantation of the primary key. Don't define a field with the same name! */
	public static final String PRIMARY_KEY = "_id";

	/** SQL template for update */
	public static final String SQL_UPDATE = "UPDATE %s SET %s WHERE " + PRIMARY_KEY + "=%s";

	/** SQL template for insert */
	public static final String SQL_INSERT = "INSERT INTO %s (%s) VALUES (%s)";

	/** SQL template for table creation */
	public static final String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS %s (%s)";

	private static final String SPACE = " ";

	private static final String DELIMITER = ",";

	private static final String EQUAL = "=";

	/** The database. Normally {@link Table} will create its own instance. */
	protected final SQLiteDatabase db;

	/** Set to remember, which tables were already created. */
	static final Set<String> createdTables = new HashSet<String>();

	private static final String TAG = Table.class.getSimpleName();

	/** The filename for the database. */
	public static final String DB_FILENAME = "androidb.sqlite";

	/**
	 * Welcome! Just provide your context, so we can access the physical database file. We will create or open a new
	 * database file, which is called {@link #DB_FILENAME}.<br/>
	 * At last, it tries to create the table in the database ({@link #createIfNecessary()}), when it can't remember to
	 * have this done yet (see {@link #createdTables}.
	 * 
	 * @param context the context to provide your packagename and path to your app folder on the device.
	 */
	public Table(final Context context) {
		this(context, null);
	}

	/**
	 * See {@link #Table(Context)}. Furthermore, you can provide the {@link #_id} for easier use with {@link #find()} or
	 * {@link #delete()}.
	 * 
	 * @param context the context to provide your packagename and path to your app folder on the device.
	 * @param _id the primary key. You should be careful to set the correct id!
	 */
	public Table(final Context context, final Long _id) {
		//create or open db. Sorry for this ugly stuff, but Java needs the constructor call as first entry.
		this(context.openOrCreateDatabase(DB_FILENAME, SQLiteDatabase.CREATE_IF_NECESSARY, null));
		this._id = _id;
	}

	/**
	 * Constructor for easier testing.
	 * 
	 * @param db
	 */
	/* ...able to test*/
	Table(final SQLiteDatabase db) {
		this.db = db;
		createIfNecessary();
		handleUpgrade();
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		db.close();
	}

	private void handleUpgrade() {
		if (getClass().equals(Metadata.class)) {
			return;
		}

		int newVersion = getVersion();
		Metadata metaTable = new Metadata(db);
		if (metaTable.findByName(getTableName())) {
			onUpgrade(metaTable.getTableVersion(), newVersion);
		} else {
			metaTable.setTable(getTableName());
			metaTable.setTableVersion(newVersion);
			if (!metaTable.save()) {
				throw new IllegalStateException("Could not create metadata for Table " + getTableName());
			}
		}
	}

	/** Teh omni-present primary key. NEVER overwrite this field!!! */
	@Column(primaryKey = true, autoIncrement = true, notNull = true)
	protected Long _id = null;

	/**
	 * Checks if this Object was stored in the database.
	 * 
	 * @return <code>false</code> when it was stored in the db.
	 */
	public final boolean isNew() {
		return _id == null || _id < 1L;
	}

	/**
	 * Retrieves the table name. It's always the simple name of your implementing class.
	 * 
	 * @return the table name.
	 */
	public final String getTableName() {
		return this.getClass().getSimpleName();
	}

	/**
	 * Queries over all rows of this Table.
	 * 
	 * @return the Cursor of this db operation. When no rows were selected, the cursor is empty.
	 */
	public Cursor all() {
		return db.query(getTableName(), getColumnNames(), null, null, null, null, null);
	}

	/**
	 * Find a specific row in the table by it's primary key and fills this object. So, _id has to be set before you call
	 * this.
	 * 
	 * @return <code>true</code>, when a single row was found and filled in this object.
	 */
	public boolean find() {
		try {
			if (_id == null || _id < 1L) {
				return false;
			}
			Cursor cursor = db.query(getTableName(), getColumnNames(), PRIMARY_KEY + EQUAL + _id, null, null, null,
				null);
			return fillFirst(cursor);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public boolean find(final Long id) {
		_id = id;
		return find();
	}

	/**
	 * Create a new row in the table and insert all values from this object.
	 * 
	 * @return <code>true</code> when we could save it successfully in the db.
	 */
	public boolean insert() {<commit_msg>don't set id when no entry was found.<commit_after>/*
 *    Copyright 2010, <NAME>

   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 de.splitstudio.androidb;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;
import de.splitstudio.androidb.annotation.Column;
import de.splitstudio.androidb.annotation.ColumnHelper;
import de.splitstudio.androidb.annotation.TableMetaData;

/**
 * {@link Table} is the superclass for your database objects. It provides all CRUD Methods {@link #save()},
 * {@link #insert()}, {@link #delete()}, {@link #update()}, {@link #find()} and {@link #all()} to manipulate your object
 * in the db. It holds the {@link #PRIMARY_KEY} to be able to manage all operations.
 * 
 * @author <NAME>
 * @since 2010
 */
public abstract class Table {

	/** String represantation of the primary key. Don't define a field with the same name! */
	public static final String PRIMARY_KEY = "_id";

	/** SQL template for update */
	public static final String SQL_UPDATE = "UPDATE %s SET %s WHERE " + PRIMARY_KEY + "=%s";

	/** SQL template for insert */
	public static final String SQL_INSERT = "INSERT INTO %s (%s) VALUES (%s)";

	/** SQL template for table creation */
	public static final String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS %s (%s)";

	private static final String SPACE = " ";

	private static final String DELIMITER = ",";

	private static final String EQUAL = "=";

	/** The database. Normally {@link Table} will create its own instance. */
	protected final SQLiteDatabase db;

	/** Set to remember, which tables were already created. */
	static final Set<String> createdTables = new HashSet<String>();

	private static final String TAG = Table.class.getSimpleName();

	/** The filename for the database. */
	public static final String DB_FILENAME = "androidb.sqlite";

	/**
	 * Welcome! Just provide your context, so we can access the physical database file. We will create or open a new
	 * database file, which is called {@link #DB_FILENAME}.<br/>
	 * At last, it tries to create the table in the database ({@link #createIfNecessary()}), when it can't remember to
	 * have this done yet (see {@link #createdTables}.
	 * 
	 * @param context the context to provide your packagename and path to your app folder on the device.
	 */
	public Table(final Context context) {
		this(context, null);
	}

	/**
	 * See {@link #Table(Context)}. Furthermore, you can provide the {@link #_id} for easier use with {@link #find()} or
	 * {@link #delete()}.
	 * 
	 * @param context the context to provide your packagename and path to your app folder on the device.
	 * @param _id the primary key. You should be careful to set the correct id!
	 */
	public Table(final Context context, final Long _id) {
		//create or open db. Sorry for this ugly stuff, but Java needs the constructor call as first entry.
		this(context.openOrCreateDatabase(DB_FILENAME, SQLiteDatabase.CREATE_IF_NECESSARY, null));
		this._id = _id;
	}

	/**
	 * Constructor for easier testing.
	 * 
	 * @param db
	 */
	/* ...able to test*/
	Table(final SQLiteDatabase db) {
		this.db = db;
		createIfNecessary();
		handleUpgrade();
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		db.close();
	}

	private void handleUpgrade() {
		if (getClass().equals(Metadata.class)) {
			return;
		}

		int newVersion = getVersion();
		Metadata metaTable = new Metadata(db);
		if (metaTable.findByName(getTableName())) {
			onUpgrade(metaTable.getTableVersion(), newVersion);
		} else {
			metaTable.setTable(getTableName());
			metaTable.setTableVersion(newVersion);
			if (!metaTable.save()) {
				throw new IllegalStateException("Could not create metadata for Table " + getTableName());
			}
		}
	}

	/** Teh omni-present primary key. NEVER overwrite this field!!! */
	@Column(primaryKey = true, autoIncrement = true, notNull = true)
	protected Long _id = null;

	/**
	 * Checks if this Object was stored in the database.
	 * 
	 * @return <code>false</code> when it was stored in the db.
	 */
	public final boolean isNew() {
		return _id == null || _id < 1L;
	}

	/**
	 * Retrieves the table name. It's always the simple name of your implementing class.
	 * 
	 * @return the table name.
	 */
	public final String getTableName() {
		return this.getClass().getSimpleName();
	}

	/**
	 * Queries over all rows of this Table.
	 * 
	 * @return the Cursor of this db operation. When no rows were selected, the cursor is empty.
	 */
	public Cursor all() {
		return db.query(getTableName(), getColumnNames(), null, null, null, null, null);
	}

	/**
	 * Find a specific row in the table by it's primary key and fills this object. So, _id has to be set before you call
	 * this.
	 * 
	 * @return <code>true</code>, when a single row was found and filled in this object.
	 */
	public boolean find() {
		return find(_id);
	}

	public boolean find(final Long id) {
		try {
			if (id == null || id < 1L) {
				return false;
			}
			Cursor cursor = db
					.query(getTableName(), getColumnNames(), PRIMARY_KEY + EQUAL + id, null, null, null, null);
			return fillFirst(cursor);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Create a new row in the table and insert all values from this object.
	 * 
	 * @return <code>true</code> when we could save it successfully in the db.
	 */
	public boolean insert() {
{'fraction_non_alphanumeric': 0.11195430436556507, 'fraction_numerical': 0.002284781721746226, 'mean_word_length': 3.6565349544072947, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6071391', 'n_tokens_mistral': 3829, 'n_tokens_neox': 3515, 'n_words': 1428}