mirror of
https://github.com/danog/postgres.git
synced 2024-12-04 02:17:44 +01:00
98 lines
3.0 KiB
PHP
98 lines
3.0 KiB
PHP
<?php
|
|
|
|
namespace Amp\Postgres\Internal;
|
|
|
|
use Amp\Postgres\ParseException;
|
|
|
|
class ArrayParser {
|
|
/**
|
|
* @param string $data
|
|
* @param callable|null $cast
|
|
* @param string $delimiter
|
|
*
|
|
* @return array Parsed column data.
|
|
*
|
|
* @throws \Amp\Postgres\ParseException
|
|
*/
|
|
public function parse(string $data, callable $cast = null, string $delimiter = ','): array {
|
|
$parser = $this->parser($data, $cast, $delimiter);
|
|
$data = \iterator_to_array($parser);
|
|
|
|
if ($parser->getReturn() !== '') {
|
|
throw new ParseException("Data left in buffer after parsing");
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function parser(string $data, callable $cast = null, string $delimiter = ','): \Generator {
|
|
$data = \trim($data);
|
|
|
|
if ($data[0] !== '{' || \substr($data, -1) !== '}') {
|
|
throw new ParseException("Missing opening or closing brackets");
|
|
}
|
|
|
|
$data = \ltrim(\substr($data, 1));
|
|
|
|
do {
|
|
if ($data === '') {
|
|
throw new ParseException("Missing closing bracket");
|
|
}
|
|
|
|
if ($data[0] === '{') { // Array
|
|
$parser = $this->parser($data, $cast, $delimiter);
|
|
yield \iterator_to_array($parser);
|
|
list($data, $end) = $this->trim($parser->getReturn(), 0);
|
|
continue;
|
|
}
|
|
|
|
if ($data[0] === '"') { // Quoted value
|
|
$position = 1;
|
|
do {
|
|
$position = \strpos($data, '"', $position);
|
|
if ($position === false) {
|
|
throw new ParseException("Could not find matching quote in quoted value");
|
|
}
|
|
} while ($data[$position - 1] === '\\' && ++$position); // Check for escaped "
|
|
|
|
$yield = \str_replace('\\"', '"', \substr($data, 1, $position - 1));
|
|
|
|
list($data, $end) = $this->trim($data, $position + 1);
|
|
} else { // Unquoted value
|
|
$position = 0;
|
|
while (isset($data[$position]) && $data[$position] !== $delimiter && $data[$position] !== '}') {
|
|
++$position;
|
|
}
|
|
|
|
$yield = \trim(\substr($data, 0, $position));
|
|
|
|
list($data, $end) = $this->trim($data, $position);
|
|
}
|
|
|
|
if (\strcasecmp($yield, "NULL") === 0) {
|
|
yield null;
|
|
} elseif ($cast) {
|
|
yield $cast($yield);
|
|
} else {
|
|
yield $yield;
|
|
}
|
|
} while ($end !== '}');
|
|
|
|
return $data;
|
|
}
|
|
|
|
private function trim(string $data, int $position): array {
|
|
do {
|
|
if (!isset($data[$position])) {
|
|
throw new ParseException("Unexpected end of data");
|
|
}
|
|
|
|
$end = $data[$position];
|
|
} while (\ltrim($end) === '' && isset($data[++$position]));
|
|
|
|
$data = \ltrim(\substr($data, $position + 1));
|
|
|
|
return [$data, $end];
|
|
}
|
|
}
|