<?php
	function sql_cross($table_left, $table_right)
	{
		$table_result = [];
		array_map
		(
			function ($row_left) use (&$table_left,&$table_right,&$table_result)
			{
				array_map
				(
					function ($row_right) use (&$table_left,&$table_right,&$table_result,&$row_left)
					{
						$row_result = [];
						foreach ($row_left as $key_left => $value_left) $row_result[$key_left] = $value_left;
						foreach ($row_right as $key_right => $value_right) $row_result[$key_right] = $value_right;
						array_push($table_result, $row_result);
					},
					$table_right
				);
			},
			$table_left
		);
		return $table_result;
	}
	
	function sql_cross_all($tables_source)
	{
		$n = count($tables_source);
		if ($n == 1)
		{
			return $tables_source[0];
		}
		else
		{
			return sql_cross(sql_cross_all(array_slice($tables_source, $n-1)), $tables_source[$n-1]);
		}
	}
	
	function sql_project($table_source, $columns)
	{
		return (
			array_map
			(
				function ($row_in) use (&$columns)
				{
					$row_out = [];
					foreach ($row_in as $key_in => $value_in)
					{
						if (array_search($key_in, $columns) !== false)
						{
							$row_out[$key_in] = $value_in;
						}
					}
					return $row_out;
				},
				$table_source
			)
		);
	}
	
	function sql_delete($table_source, $columns)
	{
		return (
			array_map
			(
				function ($row_in) use (&$columns)
				{
					$row_out = [];
					foreach ($row_in as $key_in => $value_in)
					{
						if (array_search($key_in, $columns) === false)
						{
							$row_out[$key_in] = $value_in;
						}
					}
					return $row_out;
				},
				$table_source
			)
		);
	}
	
	function sql_add($table_source, $columns, $assigners = [])
	{
		return (
			array_map
			(
				function ($row_in) use (&$columns, &$assigners)
				{
					$row_out = $row_in;
					foreach ($columns as $column)
					{
						$row_out[$column] = (array_key_exists($column, $assigners) ? $assigners[$column]($row_in) : null);
					}
					return $row_out;
				},
				$table_source
			)
		);
	}
	
	function sql_rename($table_source, $column_from, $column_to)
	{
		return (
			array_map
			(
				function ($row_in) use (&$column_from,&$column_to)
				{
					$row_out = [];
					foreach ($row_in as $column => $value)
					{
						$row_out[($column == $column_from) ? $column_to : $column] = $row_in[$column];
					}
					return $row_out;
				},
				$table_source
			)
		);
	}
	
	function sql_select($table_source, $predicate)
	{
		return (
			array_filter
			(
				$table_source,
				$predicate
			)
		);
	}
	
	function sql_group($table_source, $column, $aggregators)
	{
		$groups = [];
		array_map
		(
			function ($row_source) use (&$table_source,&$column,&$groups)
			{
				$value = $row_source[$column];
				$group = null;
				$index = null;
				// foreach ($groups as $group_)
				for ($index_ = 0; $index_ < count($groups); $index_ += 1)
				{
					$group_ = $groups[$index_];
					if ($group_["value"] == $value)
					{
						$group = $group_;
						$index = $index_;
						break;
					}
				}
				if ($group == null)
				{
					$group = ["value" => $value, "members" => []];
					$index = count($groups);
					array_push($groups, $group);
				}
				// array_push($group["members"], $row_source);
				array_push($groups[$index]["members"], $row_source);
			},
			$table_source
		);
		$table_result = array_map
		(
			function ($group) use (&$column,&$aggregators)
			{
				$row_result = [];
				$row_result[$column] = $group["value"];
				foreach ($aggregators as $aggregator_key => $aggregator_value)
				{
					$args = array_map(function ($member) use (&$aggregator_key) {return $member[$aggregator_key];}, $group["members"]);
					$row_result[$aggregator_key] = $aggregator_value($args);
				}
				return $row_result;
			},
			$groups
		);
		return $table_result;
	}
	
	function sql_snap($table_source)
	{
		$columns = [];
		$table_result = [];
		array_map
		(
			function ($row_source)
			{
				
			},
			$table_source
		);
		return $table_result;
	}
	
	/*
	function sql_sort($table_source, $column)
	{
		
	}
	 */
 ?>