Skip to content

Commit

Permalink
Merge branch 'master' of github.com:poef/arc-store
Browse files Browse the repository at this point in the history
  • Loading branch information
poef committed May 10, 2021
2 parents 2ae6bbd + 90e25c4 commit dea9c76
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 202 deletions.
22 changes: 10 additions & 12 deletions src/store.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,7 @@ public static function tokenizer($query) {
)
|
(?<string>
(?<quote>(?<![\\\\])[\'])
(?<content>(?:.(?!(?<![\\\\])(?P=quote)))*.?)
(?P=quote)
'(?:\\.|[^\\'])*'
)
|
(?<parenthesis_open>
Expand All @@ -170,20 +168,20 @@ public static function tokenizer($query) {
(?<parenthesis_close>
\)
)
)/x
)/xi
REGEX;
do {
$result = preg_match($token, $query, $matches, PREG_OFFSET_CAPTURE);
if ($result) {
$query = substr($query, strlen($matches[0][0]));
// todo: swap filters, first remove numeric keys
$value = $matches[0][0];
$offset = $matches[0][1];
$query = substr($query, strlen($value) + $offset);
yield array_filter(
array_filter($matches, function($match) {
return $match[0];
}),
function($key) {
return !is_int($key);
}, ARRAY_FILTER_USE_KEY
$matches,
function($val, $key) {
return !is_int($key) && $val[0];
},
ARRAY_FILTER_USE_BOTH
);
}
} while($result);
Expand Down
63 changes: 35 additions & 28 deletions src/store/MySQLQueryParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,79 +18,79 @@ public function __construct($tokenizer) {
public function parse($query)
{
$indent = 0;
$part = '';
$sql = '';
$sql = [];
$position = 0;
$expect = 'name|parenthesis_open|not';

foreach( call_user_func($this->tokenizer, $query) as $token ) {
$type = key($token);
list($token, $offset)=$token[$type];
if ( !preg_match("/^$expect$/",$type) ) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$type.': '
$tokenType = key($token);
list($tokenValue, $offset)=$token[$tokenType];
if ( !preg_match("/^$expect$/",$tokenType) ) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$tokenType.': '
.(substr($query,0, $position)." --> ".substr($query,$position)) );
}
switch($type) {
switch($tokenType) {
case 'number':
case 'string':
$sql .= $part.$token;
$part = '';
$sql[] = $tokenValue;
$expect = 'operator|parenthesis_close';
break;
case 'name':
switch ($token) {
switch ($tokenValue) {
case 'nodes.path':
case 'nodes.parent':
case 'nodes.name':
case 'nodes.mtime':
case 'nodes.ctime':
$part = $token;
$sql[] = $tokenValue;
break;
default:
$part = "JSON_UNQUOTE(JSON_EXTRACT( nodes.data, '$.".$token."'))";
$sql[] = "JSON_UNQUOTE(JSON_EXTRACT( nodes.data, '$.".$tokenValue."'))";
break;
}
$expect = 'compare';
break;
case 'compare':
switch( $token ) {
switch( $tokenValue ) {
case '>':
case '>=':
case '<':
case '<=':
case '=':
case '<>':
case '!=':
$part.=$token;
$sql[] =$tokenValue;
break;
case '?':
$part.= ' IS NOT NULL';
str_replace($part, '->>', '->');
$part = $sql[count($sql)-1];
$part = str_replace('->>', '->', $part);
$sql[count($sql)-1] = $part;
$sql[] = 'IS NOT NULL';
break;
case '~=':
$part.=' like ';
$sql[] = 'like';
break;
case '!~':
$part.=' not like ';
$sql[] = 'not like';
break;
}
$expect = 'number|string';
break;
case 'not':
$sql .= $token;
$sql[] = $tokenValue;
$expect = 'name|parenthesis_open';
break;
case 'operator':
$sql .= ' '.$token.' ';
$sql[] = $tokenValue;
$expect = 'name|parenthesis_open|not';
break;
case 'parenthesis_open':
$sql .= $token;
$sql[] = $tokenValue;
$indent++;
$expect = 'name|parenthesis_open|not';
break;
case 'parenthesis_close':
$sql .= $token;
$sql[] = $tokenValue;
$indent--;
if ( $indent>0 ) {
$expect = 'operator|parenthesis_close';
Expand All @@ -99,16 +99,23 @@ public function parse($query)
}
break;
}
$position += $offset + strlen($token);
$position += $offset + strlen($tokenValue);
}
if ( $indent!=0 ) {
throw new \LogicException('unbalanced parenthesis');
} else if ( trim($part) ) {
$position -= strlen($token);
throw new \LogicException('parse error at '.$position.': '.(substr($query,0, $position)." --> ".substr($query,$position)));
} else {
return $sql;
}
if ($position<strlen($query)) {
throw new \LogicException('Parse error at '.$position.': unrecognized token: '
.(substr($query,0, $position)." --> ".substr($query,$position)) );
}
foreach(['number','string','compare'] as $tokenType) {
if (strpos($expect, $tokenType)!==false) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.': '
.(substr($query,0, $position)." --> ".substr($query,$position)) );

}
}
return implode(' ',$sql);
}

}
3 changes: 3 additions & 0 deletions src/store/MySQLStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ final class MySQLStore implements Store {
public function __construct($db = null, $queryParser = null, $resultHandler = null, $path = '/')
{
$this->db = $db;
if ($this->db) {
$this->db->setAttribute(\PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
}
$this->queryParser = $queryParser;
$this->resultHandler = $resultHandler;
$this->path = \arc\path::collapse($path);
Expand Down
64 changes: 35 additions & 29 deletions src/store/PSQLQueryParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,79 +18,78 @@ public function __construct($tokenizer) {
public function parse($query)
{
$indent = 0;
$part = '';
$sql = '';
$sql = [];
$position = 0;
$expect = 'name|parenthesis_open|not';

foreach( call_user_func($this->tokenizer, $query) as $token ) {
$type = key($token);
list($token, $offset)=$token[$type];
if ( !preg_match("/^$expect$/",$type) ) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$type.': '
$tokenType = key($token);
list($tokenValue, $offset)=$token[$tokenType];
if ( !preg_match("/^$expect$/",$tokenType) ) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.', got '.$tokenType.': '
.(substr($query,0, $position)." --> ".substr($query,$position)) );
}
switch($type) {
switch($tokenType) {
case 'number':
case 'string':
$sql .= $part.$token;
$part = '';
$sql[] = $tokenValue;
$expect = 'operator|parenthesis_close';
break;
case 'name':
switch ($token) {
switch ($tokenValue) {
case 'nodes.path':
case 'nodes.parent':
case 'nodes.name':
case 'nodes.mtime':
case 'nodes.ctime':
$part = $token;
$sql[] = $tokenValue;
break;
default:
$part = "nodes.data #>> '{".str_replace('.',',',$token)."}'";
$sql[] = "nodes.data #>> '{".str_replace('.',',',$tokenValue)."}'";
break;
}
$expect = 'compare';
break;
case 'compare':
switch( $token ) {
switch( $tokenValue ) {
case '>':
case '>=':
case '<':
case '<=':
case '=':
case '<>':
case '!=':
$part.=$token;
$sql[] = $tokenValue;
break;
case '?':
$part.=$token;
str_replace($part, '#>>', '#>');
$part = $sql[count($sql)-1];
$part = str_replace('#>>', '#>', $part);
$sql[count($sql)-1] = $part;
$sql[] = $tokenValue;
break;
case '~=':
$part.=' like ';
$sql[] = 'like';
break;
case '!~':
$part.=' not like ';
$sql[] = 'not like';
break;
}
$expect = 'number|string';
break;
case 'not':
$sql .= $token;
$sql[] = $tokenValue;
$expect = 'name|parenthesis_open';
break;
case 'operator':
$sql .= ' '.$token.' ';
$sql[] = $tokenValue;
$expect = 'name|parenthesis_open|not';
break;
case 'parenthesis_open':
$sql .= $token;
$sql[] = $tokenValue;
$indent++;
$expect = 'name|parenthesis_open|not';
break;
case 'parenthesis_close':
$sql .= $token;
$sql[] = $tokenValue;
$indent--;
if ( $indent>0 ) {
$expect = 'operator|parenthesis_close';
Expand All @@ -99,16 +98,23 @@ public function parse($query)
}
break;
}
$position += $offset + strlen($token);
$position += $offset + strlen($tokenValue);
}
if ( $indent!=0 ) {
throw new \LogicException('unbalanced parenthesis');
} else if ( trim($part) ) {
$position -= strlen($token);
throw new \LogicException('parse error at '.$position.': '.(substr($query,0, $position)." --> ".substr($query,$position)));
} else {
return $sql;
}
if ($position<strlen($query)) {
throw new \LogicException('Parse error at '.$position.': unrecognized token: '
.(substr($query,0, $position)." --> ".substr($query,$position)) );
}
foreach(['number','string','compare'] as $tokenType) {
if (strpos($expect, $tokenType)!==false) {
throw new \LogicException('Parse error at '.$position.': expected '.$expect.': '
.(substr($query,0, $position)." --> ".substr($query,$position)) );

}
}
return implode(' ',$sql);
}

}
2 changes: 1 addition & 1 deletion src/store/ResultHandlers.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static function getDBGeneratorHandler($db)
$result = $q->execute($args);
$data = $q->fetch(\PDO::FETCH_ASSOC);
if (!$data) {
yield $data;
return $data;
}
while ($data) {
$value = (object) $data;
Expand Down
Loading

0 comments on commit dea9c76

Please sign in to comment.