<?php

/**
 * Short Query Notation Library
 *
 * SQN is a small library that allows you to write
 * convention based SQL queries using a short notation.
 * SQL is a very flexible and powerful language. Since SQL
 * does not rely on assumptions you have to specify a lot.
 * The SQN-library uses some basic assumptions regarding
 * naming conventions and in return it gives you a shorter notation.
 *
 * Usage:
 *
 * R::sqn('shop<product<price'); - left joins shop, product and price
 * R::sqn('book<<tag'); - doubly left joins book, and tag using book_tag
 *
 * SQN assumes id fields follow the following conventions:
 *
 * Primary key: id
 * Foreign key: {table}_id
 * No table prefix.
 *
 * SQN can also generate additional aliases:
 *
 * R::sqn( ..., 'area/x,y;place/x,y' ) - area_x area_y place_x place_y
 *
 * @author  Gabor de Mooij
 * @license BSD/GPLv2
 *
 * @copyright
 * copyright (c) G.J.G.T. (Gabor) de Mooij
 * This source file is subject to the BSD License that is bundled
 * with this source code in the file license.txt.
 */
R::ext('sqn', function( $query, $aliases = null, $q = '`' ) {
	$map = [
		'|'  => 'INNER JOIN',
		'||' => 'INNER JOIN',
		'>'  => 'RIGHT JOIN',
		'>>' => 'RIGHT JOIN',
		'<'  => 'LEFT JOIN',
		'<<' => 'LEFT JOIN',
	];
	$select = [];
	$from   = '';
	$joins  = [];
	$prev   = '';
	$ents   = preg_split( '/[^\w_]+/', $query );
	$tokens = preg_split( '/[\w_]+/', $query );
	array_pop($tokens);
	foreach( $ents as $i => $ent ) {
		$select[] = " {$q}{$ent}{$q}.* ";
		if (!$i) {
			$from = $ent;
			$prev = $ent;
			continue;
		}
		if ( $tokens[$i] == '<' || $tokens[$i] == '>' || $tokens[$i] == '|') {
			$join[] = " {$map[$tokens[$i]]} {$q}{$ent}{$q} ON {$q}{$ent}{$q}.{$prev}_id = {$q}{$prev}{$q}.id ";
		}
		if ( $tokens[$i] == '<<' || $tokens[$i] == '>>' || $tokens[$i] == '||') {
			$combi = [$prev, $ent];
			sort( $combi );
			$combi = implode( '_', $combi );
			$select[] = " {$q}{$combi}{$q}.* ";
			$join[] = " {$map[$tokens[$i]]} {$q}{$combi}{$q} ON {$q}{$combi}{$q}.{$prev}_id = {$q}{$prev}{$q}.id ";
			$join[] = " {$map[$tokens[$i]]} {$q}{$ent}{$q} ON {$q}{$combi}{$q}.{$ent}_id = {$q}{$ent}{$q}.id ";
		}
		$prev = $ent;
	}
	if (!is_null($aliases)) {
		$aliases = explode(';', $aliases);
		foreach($aliases as $alias) {
			list($table, $cols) = explode('/', $alias);
			$cols = explode(',', $cols);
			foreach($cols as $col) {
				$select[] = " {$q}{$table}{$q}.{$q}{$col}{$q} AS {$q}{$table}_{$col}{$q} ";
			}
		}
	}
	$selectSQL = implode( ",\n", $select );
	$joinSQL   = implode( "\n", $join );
	return "SELECT{$selectSQL}\n FROM {$q}{$from}{$q}\n{$joinSQL}";
});

