Browse Source
- Driver->prepare() can now take a new Database\Query object as the first parameter - The Query class allows for building a complex query out of a main body, common table expressions, WHERE coniditions, ordering conditions, a limit, and offset - The subscriptionList method is the prototypical example of usage - The experimental articleList method will in time be adapted to use this as well - A generic means of specifying a selection context is forthcoming; this would remove subscriptionList's $folder and $id parameters, for instancemicrosub
J. King
7 years ago
9 changed files with 190 additions and 69 deletions
@ -0,0 +1,110 @@ |
|||
<?php |
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Database; |
|||
use JKingWeb\Arsse\Db\Driver; |
|||
use JKingWeb\Arsse\Db\Statement; |
|||
|
|||
class Query { |
|||
protected $body = ""; |
|||
protected $qCTE = []; // Common table expression query components |
|||
protected $tCTE = []; // Common table expression type bindings |
|||
protected $vCTE = []; // Common table expression binding values |
|||
protected $jCTE = []; // Common Table Expression joins |
|||
protected $qWhere = []; // WHERE clause components |
|||
protected $tWhere = []; // WHERE clause type bindings |
|||
protected $vWhere = []; // WHERE clause binding values |
|||
protected $order = []; // ORDER BY clause components |
|||
protected $limit = 0; |
|||
protected $offset = 0; |
|||
|
|||
|
|||
function __construct(string $body, string $where = "", string $order = "", int $limit = 0, int $offset = 0) { |
|||
if(strlen($body)) $this->body = $body; |
|||
if(strlen($where)) $this->where[] = $where; |
|||
if(strlen($order)) $this->order[] = $order; |
|||
$this->limit = $limit; |
|||
$this->offset = $offset; |
|||
} |
|||
|
|||
function setCTE(string $body, $types = null, $values = null, string $join = ''): bool { |
|||
if(!strlen($body)) return false; |
|||
$this->qCTE[] = $body; |
|||
if(!is_null($types)) { |
|||
$this->tCTE[] = $types; |
|||
$this->vCTE[] = $values; |
|||
} |
|||
if(strlen($join)) $this->jCTE[] = $join; // the CTE may only participate in subqueries rather than a join on the main query |
|||
return true; |
|||
} |
|||
|
|||
function setWhere(string $where, $types = null, $values = null): bool { |
|||
if(!strlen($where)) return false; |
|||
$this->qWhere[] = $where; |
|||
if(!is_null($types)) { |
|||
$this->tWhere[] = $types; |
|||
$this->vWhere[] = $values; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
function setOrder(string $oder, bool $prepend = false): bool { |
|||
if(!strlen($order)) return false; |
|||
if($prepend) { |
|||
array_unshift($this->order, $order); |
|||
} else { |
|||
$this->order[] = $order; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
function prepare(Driver $drv, ...$userTypes): Statement { |
|||
return new QueryStatement($drv->prepare($this->getQuery(), $this->getCTETypes(), $userTypes, $this->getWhereTypes()), $this->getCTEValues(), $this->getWhereValues()); |
|||
} |
|||
|
|||
function getQuery(bool $pretty = false): string { |
|||
$cte = sizeof($this->qCTE); |
|||
$out = ""; |
|||
if($cte) { |
|||
// start with common table expressions |
|||
$out .= "WITH RECURSIVE ".implode(", ", $this->qCTE)." "; |
|||
} |
|||
// add the body |
|||
$out .= $this->body; |
|||
if($cte) { |
|||
// add any joins against CTEs |
|||
$out .= " ".implode(" ", $this->jCTE); |
|||
} |
|||
// add any WHERE terms |
|||
if(sizeof($this->qWhere)) { |
|||
$out .= " WHERE ".implode(" AND ", $this->qWhere); |
|||
} |
|||
// add any ORDER BY terms |
|||
if(sizeof($this->order)) { |
|||
$out .= " ORDER BY ".implode(", ", $this->order); |
|||
} |
|||
// add LIMIT and OFFSET if the former is specified |
|||
if($this->limit > 0) { |
|||
$out .= " LIMIT ".$this->limit; |
|||
if($this->offset > 0) { |
|||
$out .= " OFFSET ".$this->offset; |
|||
} |
|||
} |
|||
return $out; |
|||
} |
|||
|
|||
function getWhereTypes(): array { |
|||
return $this->tWhere; |
|||
} |
|||
|
|||
function getWhereValues(): array { |
|||
return $this->vWhere; |
|||
} |
|||
|
|||
function getCTETypes(): array { |
|||
return $this->tCTE; |
|||
} |
|||
|
|||
function getCTEValues(): array { |
|||
return $this->vCTE; |
|||
} |
|||
} |
@ -1,28 +0,0 @@ |
|||
<?php |
|||
namespace JKingWeb\Arsse; |
|||
const INSTALL = true; |
|||
require_once __DIR__."/../bootstrap.php"; |
|||
|
|||
|
|||
$user = "john.doe@example.com"; |
|||
$pass = "secret"; |
|||
$_SERVER['PHP_AUTH_USER'] = $user; |
|||
$_SERVER['PHP_AUTH_PW'] = $pass; |
|||
$conf = new Conf(); |
|||
$conf->dbSQLite3File = ":memory:"; |
|||
Data::load($conf); |
|||
Data::$db->schemaUpdate(); |
|||
|
|||
Data::$user->add($user, $pass); |
|||
Data::$user->auth(); |
|||
Data::$user->authorizationEnabled(false); |
|||
Data::$user->rightsSet($user, User\Driver::RIGHTS_GLOBAL_ADMIN); |
|||
Data::$user->authorizationEnabled(true); |
|||
Data::$db->folderAdd($user, ['name' => 'ook']); |
|||
/*Data::$db->subscriptionAdd($user, "http://linuxfr.org/news.atom"); |
|||
Data::$db->subscriptionPropertiesSet($user, 1, [ |
|||
'title' => "OOOOOOOOK!", |
|||
]);*/ |
|||
(new REST())->dispatch(new REST\Request( |
|||
"POST", "/index.php/apps/news/api/v1-2/feeds/", json_encode(['url'=> "http://linuxfr.org/news.atom"]) |
|||
)); |
Loading…
Reference in new issue