protected function buildQueryString() {

		$w = [];
		$s = [];

		$qc = $this->quoteChar;

		// start SQL statement

		$this->sql = 'SELECT ';

		// add columns

		if(!$this->columns || !count($this->columns)) {
			$this->sql .= '*';
		}
		else {
			
			$this->sql .= $qc . str_replace('.', $qc . '.' . $qc, implode($qc . ',' . $qc, $this->columns)) . $qc;
				
		}

		// add table

		$this->sql .= ' FROM ' . $qc . preg_replace('/\s+/', $qc . ' ' . $qc, $this->table) . $qc;

		// add alias

		if($this->alias) {
			$this->sql .= ' ' . $qc . $this->alias . $qc;
		}

		// add INNER JOINs

		foreach($this->innerJoins as $join) {
			$this->sql .= sprintf(' INNER JOIN %1$s%2$s%1$s ON %3$s', $qc, preg_replace('/\s+/', $qc . ' ' . $qc, trim($join->table)), $join->on);
		}

		// build WHERE clause

		foreach($this->whereClauses as $where) {

			// complete condition when no operator set

			if(!$where->operator) {
				$w[] = $where->conditionOrColumn;
			}

			// otherwise parse operator

			else {
				if($where->operator === 'IN') {
					$w[] = sprintf(
						'%1$s%2$s%1$s IN (%3$s)',
						$qc,
						str_replace('.', $qc . '.' . $qc, $where->conditionOrColumn),
						implode(', ', array_fill(0, count($where->value), '?'))
					);
				}
				else {
					$w[] = sprintf(
						'%1$s%2$s%1$s %3$s ?',
						$qc,
						str_replace('.', $qc . '.' . $qc, $where->conditionOrColumn),
						$where->operator
					);
				}
			}
		}

		// build SORT clause

		foreach($this->columnSorts as $sort) {
			$s[] = $sort->column . ($sort->asc ? '' : ' DESC');
		}

		if(count($w)) {
			$this->sql .= ' WHERE (' . implode(') AND (', $w) .')';
		}
		if(count($s)) {
			$this->sql .= ' ORDER BY ' . implode(', ', $s);
		}

	}