Commit c4601fc0 authored by Andreas Hennings's avatar Andreas Hennings
Browse files

some code to start with

parent d448465a
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\nicedpq;

class IndentedText {

  protected $text;
  protected $indent;

  function __construct(&$text, $indent = '') {
    $this->text =& $text;
    $this->indent = $indent;
  }

  function indent() {
    return new IndentedText($this->text, $this->indent . '  ');
  }

  function println($str = '') {
    $this->text .= "\n" . $this->indent;
    $this->pr($str);
  }

  function pr($str) {
    $this->text .= str_replace("\n", "\n" . $this->indent, $str);
  }

  function printList($list, $separator = ',') {
    if (is_string($list)) {
      $list = explode($separator . ' ', $list);
    }
    $this->println(implode("$separator\n", $list));
  }
}
+129 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\nicedpq;

class QueryPrinter {

  function printSelect($out, $q) {

    $q = SelectQueryInspector::extractAttributes($q);

    // SELECT
    $out->println('SELECT');
    if ($q->distinct) {
      $out->println(' DISTINCT');
    }

    // FIELDS and EXPRESSIONS
    $this->printFields($out->indent(), $q);


    // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
    $out->println("FROM");
    $this->printFrom($out->indent(), $q);

    // WHERE
    if (count($q->where)) {
      $out->println("WHERE");
      $this->printCondition($out->indent(), $q->where);
    }

    // GROUP BY
    if ($q->group) {
      $out->println('GROUP BY');
      $out->indent()->printList($q->group);
    }

    // HAVING
    if (count($q->having)) {
      // There is an implicit string cast on $q->having.
      $out->println("HAVING " . $q->having);
    }

    // ORDER BY
    if ($q->order) {
      $out->println("ORDER BY");
      $fields = array();
      foreach ($q->order as $field => $direction) {
        $fields[] = $field . ' ' . $direction;
      }
      $out->indent()->printList($fields);
    }

    // RANGE
    // There is no universal SQL standard for handling range or limit clauses.
    // Fortunately, all core-supported databases use the same range syntax.
    // Databases that need a different syntax can override this method and
    // do whatever alternate logic they need to.
    if (!empty($q->range)) {
      $out->println("LIMIT " . (int) $q->range['length'] . " OFFSET " . (int) $q->range['start']);
    }

    // UNION is a little odd, as the select queries to combine are passed into
    // this query, but syntactically they all end up on the same level.
    if ($q->union) {
      foreach ($q->union as $union) {
        $out->println($union['type'] . ' ' . (string) $union['query']);
      }
    }

    if ($q->forUpdate) {
      $out->println('FOR UPDATE');
    }
  }

  protected function printFields($out, $q) {
    $fields = array();
    foreach ($q->tables as $alias => $table) {
      if (!empty($table['all_fields'])) {
        $fields[] = $q->connection->escapeTable($alias) . '.*';
      }
    }
    foreach ($q->fields as $alias => $field) {
      // Always use the AS keyword for field aliases, as some
      // databases require it (e.g., PostgreSQL).
      $fields[] = (isset($field['table']) ? $q->connection->escapeTable($field['table']) . '.' : '') . $q->connection->escapeField($field['field']) . ' AS ' . $q->connection->escapeAlias($field['alias']);
    }
    foreach ($q->expressions as $alias => $expression) {
      $fields[] = $expression['expression'] . ' AS ' . $q->connection->escapeAlias($expression['alias']);
    }
    $out->printList($fields);
  }

  protected function printFrom($out, $q) {
    foreach ($q->tables as $alias => $table) {
      $out->println();
      if (isset($table['join type'])) {
        $out->pr($table['join type'] . ' JOIN ');
      }

      // If the table is a subquery, compile it and integrate it into this query.
      if ($table['table'] instanceof SelectQueryInterface) {
        // Run preparation steps on this sub-query before converting to string.
        $subquery = $table['table'];
        $subquery->preExecute();
        $subquery->__toString();
        $out->pr('(');
        $this->printSelect($out->indent(), $subquery);
        $out->println(')');
      }
      else {
        // $out->pr('{' . $q->connection->escapeTable($table['table']) . '}');
        $out->pr($q->connection->escapeTable($table['table']));
      }

      // Don't use the AS keyword for table aliases, as some
      // databases don't support it (e.g., Oracle).
      $out->pr(' ' . $q->connection->escapeTable($table['alias']));

      if (!empty($table['condition'])) {
        $out->pr(' ON ');
        $out->indent()->printList($table['condition'], ' AND');
      }
    }
  }

  protected function printCondition($out, $cond) {
    $out->printList(trim($cond), ' AND');
  }
}
+14 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\nicedpq;

class SelectQueryInspector extends \SelectQuery {

  static extractAttributes($q) {
    $result = new stdClass;
    foreach ($q as $key => $value) {
      $q->$key = $value;
    }
    return $result;
  }
}

nicedpq.module

0 → 100644
+18 −0
Original line number Diff line number Diff line
<?php

use Drupal\nicedpq as m;

function nicedpq($q, $return = FALSE) {

  // Make sure it gets compiled.
  $q->__toString();

  $text = '';
  $s = new m\IndentedText($text);
  $p = new m\QueryPrinter();
  $p->printSelect($s, $q);
  if ($return) {
    return $text;
  }
  dpm($text);
}