<commit_before><?php
/*
 * Tikapot Model Query System
 *
 */

require_once(home_dir . "framework/database.php");
require_once(home_dir . "framework/model.php");
require_once(home_dir . "framework/model_cache.php");
require_once(home_dir . "framework/utils.php");

class ModelQueryException extends Exception { }

class ModelQuery implements Iterator, Countable
{
	private $_model, $_query, $_objects, $_count, $_has_run, $_built_queries, $_position, $_sanitized, $_using, $_table, $_can_cache;
	
	/**
	 * $query should conform to the following structure (each line optional):
	 *  (
	 *    WHERE => (COL => Val, "op"=>"OR", COL => (Val, OPER), etc),   Default OPER: = Default OP: AND
	 *    ORDER BY => (COL, (COL, DESC/ASC), etc),          Default: ASC
	 *    GROUP BY => (COL, COL, etc)
	 *    ONLY => (COL, COL, etc),
	 *    LIMIT => num,
	 *    OFFSET => num,
	 *  )
	 */
	public function __construct($model, $query = array(), $using = "default", $table = "", $can_cache = true) {
		if (!$model)
			throw new ModelQueryException($GLOBALS['i18n']['framework']["mqerr1"]);
		$this->_count = false;
		$this->_position = 0;
		$this->_has_run = False;
		$this->_sanitized = False;
		$this->_model = $model;
		$this->_built_queries = array();
		$this->_query = $query;
		$this->_using = $using;
		$this->_table = $table;
		$this->_can_cache = $can_cache;
	}
	
	private function sanitize_column($obj, $col) {
		if ($col == "pk")
			$col = $obj->get_pk_name();
		return $col;
	}
	
	protected function sanitize_query($query) {
		if (!is_array($query))
			throw new ModelQueryException($GLOBALS['i18n']['framework']["mqerr2"]);
		$parsed_query = array();
		if (array_key_exists("WHERE", $query)) {
			$parsed_query["WHERE"] = array(); // Ensure WHERE is always first
		}
		$db = Database::create($this->_using);
		if (!$db)
			return false;
		$class = get_class($this->_model);
		$this->_model->create_table($this->_table);
		foreach ($query as $clause => $criterion) {
			$arr = array();
			if (is_array($criterion)) {
				foreach ($criterion as $col => $val) {
					switch ($clause) {
						case "WHERE":
							if ($col == "op") {
								$arr["op"] = $val;
							} else {
								$col = $this->sanitize_column($this->_model, $col);
								$field = $this->_model->get_field($col);
								if (is_array($val)) {
									if ($val[1] == "IN") {
										$str = "";
										if (is_array($val[0])) {
											$str = "(";
											foreach ($val[0] as $item) {
												if (strlen($str) > 1)
													$str .= ",";
												$str .= $field->sql_value($db, $item);
											}
											$str .= ")";
										} else {
											$str = $db->escape_string($val[0]);
										}
										$arr[$col] = array($str, $val[1]);
									} else {
										$arr[$col] = array($field->sql_value($db, $val[0]), $db->escape_string($val[1]));
									}
								} else {
									$arr[$col] = $field->sql_value($db, $val);
								}
							}
							break;
						case "ORDER BY":
							if (is_array($val))
								$arr[] = array($db->escape_string($this->sanitize_column($this->_model, $val[0])), $db->escape_string($val[1]));
							else
								$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
						case "GROUP BY":
							$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
						case "ONLY":
							$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
					}
				}
			} else {
				if ($clause == "LIMIT" || $clause == "OFFSET") {
					$arr = intVal($criterion);
				}
			}
			$parsed_query[$clause] = $arr;
		}
		return $parsed_query;
	}
	
	/* Allows for lazy evaluation */
	private function _ensure_run() {
		if (!$this->_has_run)
			$this->_run();
	}
	
	protected function _get_object_from_result($result) {
		$class = get_class($this->_model);

		// Try to get from Cache
		if (isset($result['id'])) {
			$obj = ModelCache::get($class, $result['id']);
			if ($obj) {
				return $obj;
			}
		}


		$obj = new $class();
		$obj->load_values($result, true);

		ModelCache::set($obj);

		return $obj;
	}
	
	/* Returns the built query */
	protected function _build_query($selection = "*", $limit = 0, $offset = 0) {
		$query = "";
		$count = 0;
		if (!$this->_sanitized) {
			$this->_query = $this->sanitize_query($this->_query);
			$this->_sanitized = true;
		}
		$op = "AND";
		$counting = starts_with($selection, "COUNT");
		foreach ($this->_query as $clause => $criterion) {
			if ($counting && ($clause === "ORDER BY" || $clause === "GROUP BY"))
				continue;
			if (is_array($criterion)) {<commit_msg>Prevent bug causing multiple sanitations<commit_after><?php
/*
 * Tikapot Model Query System
 *
 */

require_once(home_dir . "framework/database.php");
require_once(home_dir . "framework/model.php");
require_once(home_dir . "framework/model_cache.php");
require_once(home_dir . "framework/utils.php");

class ModelQueryException extends Exception { }

class ModelQuery implements Iterator, Countable
{
	private $_model, $_query, $_sanitized_query, $_objects, $_count, $_has_run, $_built_queries, $_position, $_sanitized, $_using, $_table, $_can_cache;
	
	/**
	 * $query should conform to the following structure (each line optional):
	 *  (
	 *    WHERE => (COL => Val, "op"=>"OR", COL => (Val, OPER), etc),   Default OPER: = Default OP: AND
	 *    ORDER BY => (COL, (COL, DESC/ASC), etc),          Default: ASC
	 *    GROUP BY => (COL, COL, etc)
	 *    ONLY => (COL, COL, etc),
	 *    LIMIT => num,
	 *    OFFSET => num,
	 *  )
	 */
	public function __construct($model, $query = array(), $using = "default", $table = "", $can_cache = true) {
		if (!$model)
			throw new ModelQueryException($GLOBALS['i18n']['framework']["mqerr1"]);
		$this->_count = false;
		$this->_position = 0;
		$this->_has_run = False;
		$this->_sanitized = False;
		$this->_model = $model;
		$this->_built_queries = array();
		$this->_query = $query;
		$this->_using = $using;
		$this->_table = $table;
		$this->_can_cache = $can_cache;
	}
	
	private function sanitize_column($obj, $col) {
		if ($col == "pk")
			$col = $obj->get_pk_name();
		return $col;
	}
	
	protected function sanitize_query($query) {
		if (!is_array($query))
			throw new ModelQueryException($GLOBALS['i18n']['framework']["mqerr2"]);
		$parsed_query = array();
		if (array_key_exists("WHERE", $query)) {
			$parsed_query["WHERE"] = array(); // Ensure WHERE is always first
		}
		$db = Database::create($this->_using);
		if (!$db)
			return false;
		$class = get_class($this->_model);
		$this->_model->create_table($this->_table);
		foreach ($query as $clause => $criterion) {
			$arr = array();
			if (is_array($criterion)) {
				foreach ($criterion as $col => $val) {
					switch ($clause) {
						case "WHERE":
							if ($col == "op") {
								$arr["op"] = $val;
							} else {
								$col = $this->sanitize_column($this->_model, $col);
								$field = $this->_model->get_field($col);
								if (is_array($val)) {
									if ($val[1] == "IN") {
										$str = "";
										if (is_array($val[0])) {
											$str = "(";
											foreach ($val[0] as $item) {
												if (strlen($str) > 1)
													$str .= ",";
												$str .= $field->sql_value($db, $item);
											}
											$str .= ")";
										} else {
											$str = $db->escape_string($val[0]);
										}
										$arr[$col] = array($str, $val[1]);
									} else {
										$arr[$col] = array($field->sql_value($db, $val[0]), $db->escape_string($val[1]));
									}
								} else {
									$arr[$col] = $field->sql_value($db, $val);
								}
							}
							break;
						case "ORDER BY":
							if (is_array($val))
								$arr[] = array($db->escape_string($this->sanitize_column($this->_model, $val[0])), $db->escape_string($val[1]));
							else
								$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
						case "GROUP BY":
							$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
						case "ONLY":
							$arr[] = $this->sanitize_column($this->_model, $db->escape_string($val));
							break;
					}
				}
			} else {
				if ($clause == "LIMIT" || $clause == "OFFSET") {
					$arr = intVal($criterion);
				}
			}
			$parsed_query[$clause] = $arr;
		}
		return $parsed_query;
	}
	
	/* Allows for lazy evaluation */
	private function _ensure_run() {
		if (!$this->_has_run)
			$this->_run();
	}
	
	protected function _get_object_from_result($result) {
		$class = get_class($this->_model);

		// Try to get from Cache
		if (isset($result['id'])) {
			$obj = ModelCache::get($class, $result['id']);
			if ($obj) {
				return $obj;
			}
		}


		$obj = new $class();
		$obj->load_values($result, true);

		ModelCache::set($obj);

		return $obj;
	}
	
	/* Returns the built query */
	protected function _build_query($selection = "*", $limit = 0, $offset = 0) {
		$query = "";
		$count = 0;
		if (!$this->_sanitized) {
			$this->_sanitized_query = $this->sanitize_query($this->_query);
			$this->_sanitized = true;
		}
		$op = "AND";
		$counting = starts_with($selection, "COUNT");
		foreach ($this->_sanitized_query as $clause => $criterion) {
			if ($counting && ($clause === "ORDER BY" || $clause === "GROUP BY"))
				continue;
			if (is_array($criterion)) {
{'fraction_non_alphanumeric': 0.19845194581810363, 'fraction_numerical': 0.0043001505052676844, 'mean_word_length': 2.9088235294117646, 'pattern_counts': {'":': 8, '<': 5, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '2818272', 'n_tokens_mistral': 4088, 'n_tokens_neox': 3221, 'n_words': 677}