<commit_before><?php
/**
 * Lithium: the most rad php framework
 *
 * @copyright     Copyright 2011, Union of RAD (http://union-of-rad.org)
 * @license       http://opensource.org/licenses/bsd-license.php The BSD License
 *
 */

namespace lithium\data\source\database\adapter;

use SQLite3 as SQLite;
use SQLite3Result;
use lithium\data\model\QueryException;

/**
 * Sqlite database driver
 *
 * @todo fix encoding methods to use class query methods instead of sqlite3 natives
 */
class Sqlite3 extends \lithium\data\source\Database {

	protected $_classes = array(
		'entity' => 'lithium\data\entity\Record',
		'set' => 'lithium\data\collection\RecordSet',
		'relationship' => 'lithium\data\model\Relationship',
		'result' => 'lithium\data\source\database\adapter\sqlite3\Result'
	);

	/**
	 * Pair of opening and closing quote characters used for quoting identifiers in queries.
	 *
	 * @link http://www.sqlite.org/lang_keywords.html
	 * @var array
	 */
	protected $_quotes = array('"', '"');

	/**
	 * Sqlite column type definitions.
	 *
	 * @var array
	 */
	protected $_columns = array(
		'primary_key' => array('name' => 'integer primary key'),
		'string' => array('name' => 'varchar', 'limit' => '255'),
		'text' => array('name' => 'text'),
		'integer' => array('name' => 'integer', 'limit' => 11, 'formatter' => 'intval'),
		'float' => array('name' => 'float', 'formatter' => 'floatval'),
		'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
		'timestamp' => array(
			'name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'
		),
		'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
		'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
		'binary' => array('name' => 'blob'),
		'boolean' => array('name' => 'boolean')
	);

	/**
	 * Constructs the Sqlite adapter
	 *
	 * @see lithium\data\source\Database::__construct()
	 * @see lithium\data\Source::__construct()
	 * @see lithium\data\Connections::add()
	 * @param array $config Configuration options for this class. For additional configuration,
	 *        see `lithium\data\source\Database` and `lithium\data\Source`. Available options
	 *        defined by this class:
	 *        - `'database'` _string_: database name. Defaults to none
	 *        - `'flags'` _integer_: Optional flags used to determine how to open the SQLite
	 *          database. By default, open uses SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE.
	 *        - `'key'` _string_: An optional encryption key used when encrypting and decrypting
	 *          an SQLite database.
	 *
	 * Typically, these parameters are set in `Connections::add()`, when adding the adapter to the
	 * list of active connections.
	 * @return The adapter instance.
	 */
	public function __construct(array $config = array()) {
		$defaults = array(
			'database'   => '',
			'flags'      => SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE,
			'key'        => NULL
		);
		parent::__construct($config + $defaults);
	}

	/**
	 * Check for required PHP extension, or supported database feature.
	 *
	 * @param string $feature Test for support for a specific feature, i.e. `'transactions'`.
	 * @return boolean Returns `true` if the particular feature (or if Sqlite) support is enabled,
	 *         otherwise `false`.
	 */
	public static function enabled($feature = null) {
		if (!$feature) {
			return extension_loaded('sqlite3');
		}
		$features = array(
			'arrays' => false,
			'transactions' => false,
			'booleans' => true,
			'relationships' => true
		);
		return isset($features[$feature]) ? $features[$feature] : null;
	}

	/**
	 * Connects to the database using options provided to the class constructor.
	 *
	 * @return boolean True if the database could be connected, else false
	 */
	public function connect() {
		$this->connection = new SQLite(
			$this->_config['database'], $this->_config['flags'], $this->_config['key']
		);
		return $this->_isConnected = (boolean) $this->connection;
	}

	/**
	 * Disconnects the adapter from the database.
	 *
	 * @return boolean True on success, else false.
	 */
	public function disconnect() {
		return !$this->_isConnected || !($this->_isConnected = !$this->connection->close());
	}

	/**
	 * Returns the list of tables in the currently-connected database.
	 *
	 * @param string $model The fully-name-spaced class name of the model object making the request.
	 * @return array Returns an array of objects to which models can connect.
	 * @filter This method can be filtered.
	 */
	public function entities($model = null) {
		$config = $this->_config;
		$method = function($self, $params) use ($config) {
			return $self->query("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
		};
		return $this->_filter(__METHOD__, compact('model'), $method);
	}

	/**
	 * Gets the column schema for a given Sqlite3 table.
	 *
	 * @param mixed $entity Specifies the table name for which the schema should be returned, or
	 *        the class name of the model object requesting the schema, in which case the model
	 *        class will be queried for the correct table name.
	 * @param array $meta
	 * @return array Returns an associative array describing the given table's schema, where the
	 *         array keys are the available fields, and the values are arrays describing each
	 *         field, containing the following keys:
	 *         - `'type'`: The field type name
	 * @filter This method can be filtered.
	 */
	public function describe($entity, array $meta = array()) {
		$params = compact('entity', 'meta');
		return $this->_filter(__METHOD__, $params, function($self, $params) {
			extract($params);

			$name = $self->invokeMethod('_entityName', array($entity));
			$columns = $self->read("PRAGMA table_info({$name})", array('return' => 'array'));
			$fields = array();

			foreach ($columns as $column) {
				list($type, $length) = explode('(', $column['type']) + array('', '');
				$length = trim($length, ')');
				$fields[$column['name']] = array(
					'type' => $type,
					'length' => $length,
					'null'     => ($column['notnull'] == 1 ? true : false),
					'default'  => $column['dflt_value'],
				);
			}
			return $fields;
		});
	}

	/**
	 * Get the last insert id from the database.
	 *
	 * @param object $query The given query, usually an instance of `lithium\data\model\Query`.
	 * @return void
	 */
	protected function _insertId($query) {
		return $this->connection->lastInsertRowID();
	}

	/**
	 * Gets or sets the encoding for the connection.
	 *
	 * @param string $encoding If setting the encoding, this is the name of the encoding to set,
	 *               i.e. `'utf8'` or `'UTF-8'` (both formats are valid).
	 * @return boolean|string If setting the encoding; returns `true` on success, or `false` on
	 *         failure. When getting, returns the encoding as a string.
	 */
	public function encoding($encoding = null) {
		$encodingMap = array('UTF-8' => 'utf8');<commit_msg>Take alternative column definitions into account.<commit_after><?php
/**
 * Lithium: the most rad php framework
 *
 * @copyright     Copyright 2011, Union of RAD (http://union-of-rad.org)
 * @license       http://opensource.org/licenses/bsd-license.php The BSD License
 *
 */

namespace lithium\data\source\database\adapter;

use SQLite3 as SQLite;
use SQLite3Result;
use lithium\data\model\QueryException;

/**
 * Sqlite database driver
 *
 * @todo fix encoding methods to use class query methods instead of sqlite3 natives
 */
class Sqlite3 extends \lithium\data\source\Database {

	protected $_classes = array(
		'entity' => 'lithium\data\entity\Record',
		'set' => 'lithium\data\collection\RecordSet',
		'relationship' => 'lithium\data\model\Relationship',
		'result' => 'lithium\data\source\database\adapter\sqlite3\Result'
	);

	/**
	 * Pair of opening and closing quote characters used for quoting identifiers in queries.
	 *
	 * @link http://www.sqlite.org/lang_keywords.html
	 * @var array
	 */
	protected $_quotes = array('"', '"');

	/**
	 * Sqlite column type definitions.
	 *
	 * @var array
	 */
	protected $_columns = array(
		'primary_key' => array('name' => 'integer primary key'),
		'string' => array('name' => 'varchar', 'limit' => '255'),
		'text' => array('name' => 'text'),
		'integer' => array('name' => 'integer', 'limit' => 11, 'formatter' => 'intval'),
		'float' => array('name' => 'float', 'formatter' => 'floatval'),
		'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
		'timestamp' => array(
			'name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'
		),
		'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
		'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
		'binary' => array('name' => 'blob'),
		'boolean' => array('name' => 'boolean')
	);

	/**
	 * Constructs the Sqlite adapter
	 *
	 * @see lithium\data\source\Database::__construct()
	 * @see lithium\data\Source::__construct()
	 * @see lithium\data\Connections::add()
	 * @param array $config Configuration options for this class. For additional configuration,
	 *        see `lithium\data\source\Database` and `lithium\data\Source`. Available options
	 *        defined by this class:
	 *        - `'database'` _string_: database name. Defaults to none
	 *        - `'flags'` _integer_: Optional flags used to determine how to open the SQLite
	 *          database. By default, open uses SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE.
	 *        - `'key'` _string_: An optional encryption key used when encrypting and decrypting
	 *          an SQLite database.
	 *
	 * Typically, these parameters are set in `Connections::add()`, when adding the adapter to the
	 * list of active connections.
	 * @return The adapter instance.
	 */
	public function __construct(array $config = array()) {
		$defaults = array(
			'database'   => '',
			'flags'      => SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE,
			'key'        => NULL
		);
		parent::__construct($config + $defaults);
	}

	/**
	 * Check for required PHP extension, or supported database feature.
	 *
	 * @param string $feature Test for support for a specific feature, i.e. `'transactions'`.
	 * @return boolean Returns `true` if the particular feature (or if Sqlite) support is enabled,
	 *         otherwise `false`.
	 */
	public static function enabled($feature = null) {
		if (!$feature) {
			return extension_loaded('sqlite3');
		}
		$features = array(
			'arrays' => false,
			'transactions' => false,
			'booleans' => true,
			'relationships' => true
		);
		return isset($features[$feature]) ? $features[$feature] : null;
	}

	/**
	 * Connects to the database using options provided to the class constructor.
	 *
	 * @return boolean True if the database could be connected, else false
	 */
	public function connect() {
		$this->connection = new SQLite(
			$this->_config['database'], $this->_config['flags'], $this->_config['key']
		);
		return $this->_isConnected = (boolean) $this->connection;
	}

	/**
	 * Disconnects the adapter from the database.
	 *
	 * @return boolean True on success, else false.
	 */
	public function disconnect() {
		return !$this->_isConnected || !($this->_isConnected = !$this->connection->close());
	}

	/**
	 * Returns the list of tables in the currently-connected database.
	 *
	 * @param string $model The fully-name-spaced class name of the model object making the request.
	 * @return array Returns an array of objects to which models can connect.
	 * @filter This method can be filtered.
	 */
	public function entities($model = null) {
		$config = $this->_config;
		$method = function($self, $params) use ($config) {
			return $self->query("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
		};
		return $this->_filter(__METHOD__, compact('model'), $method);
	}

	/**
	 * Gets the column schema for a given Sqlite3 table.
	 *
	 * A column type may not always be available, i.e. when during creation of
	 * the column no type was declared. Those columns are internally treated
	 * by SQLite3 as having a `NONE` affinity. The final schema will contain no
	 * information about type and length of such columns (both values will be
	 * `null`).
	 *
	 * @param mixed $entity Specifies the table name for which the schema should be returned, or
	 *        the class name of the model object requesting the schema, in which case the model
	 *        class will be queried for the correct table name.
	 * @param array $meta
	 * @return array Returns an associative array describing the given table's schema, where the
	 *         array keys are the available fields, and the values are arrays describing each
	 *         field, containing the following keys:
	 *         - `'type'`: The field type name
	 * @filter This method can be filtered.
	 */
	public function describe($entity, array $meta = array()) {
		$params = compact('entity', 'meta');
		return $this->_filter(__METHOD__, $params, function($self, $params) {
			extract($params);

			$name = $self->invokeMethod('_entityName', array($entity));
			$columns = $self->read("PRAGMA table_info({$name})", array('return' => 'array'));
			$fields = array();

			foreach ($columns as $column) {
				$regex = '(?P<type>[a-zA-Z]+)+(\((?P<length>[0-9]+)\))?';
				preg_match("/{$regex}/", $column['type'], $matches);

				$fields[$column['name']] = array(
					'type' => isset($matches['type']) ? $matches['type'] : null,
					'length' => isset($matches['length']) ? $matches['length'] : null,
					'null'     => ($column['notnull'] == 1 ? true : false),
					'default'  => $column['dflt_value'],
				);
			}
			return $fields;
		});
	}

	/**
	 * Get the last insert id from the database.
	 *
	 * @param object $query The given query, usually an instance of `lithium\data\model\Query`.
	 * @return void
	 */
	protected function _insertId($query) {
		return $this->connection->lastInsertRowID();
	}

	/**
	 * Gets or sets the encoding for the connection.
	 *
	 * @param string $encoding If setting the encoding, this is the name of the encoding to set,
	 *               i.e. `'utf8'` or `'UTF-8'` (both formats are valid).
	 * @return boolean|string If setting the encoding; returns `true` on success, or `false` on
	 *         failure. When getting, returns the encoding as a string.
	 */
	public function encoding($encoding = null) {
		$encodingMap = array('UTF-8' => 'utf8');
{'fraction_non_alphanumeric': 0.15333934392121507, 'fraction_numerical': 0.003675705666134961, 'mean_word_length': 3.5317410433689505, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 143, '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': '5214730', 'n_tokens_mistral': 4687, 'n_tokens_neox': 4230, 'n_words': 1396}