Derive mode from DSN function
- Add headers in all files - Minor field name changes
This commit is contained in:
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
use PhpOption\{None, Option, Some};
|
||||
|
||||
/**
|
||||
* Common configuration for the document library
|
||||
@@ -20,9 +28,6 @@ class Configuration
|
||||
*/
|
||||
public static int $idStringLength = 16;
|
||||
|
||||
/** @var string The data source name (DSN) of the connection string */
|
||||
public static string $pdoDSN = '';
|
||||
|
||||
/** @var string|null The username to use to establish a data connection (use env PDO_DOC_USERNAME if possible) */
|
||||
public static ?string $username = null;
|
||||
|
||||
@@ -32,41 +37,71 @@ class Configuration
|
||||
/** @var array|null Options to use for connections (driver-specific) */
|
||||
public static ?array $options = null;
|
||||
|
||||
/** @var Mode|null The mode in which the library is operating (filled after first connection if not configured) */
|
||||
public static ?Mode $mode = null;
|
||||
/** @var Option<Mode> The mode in which the library is operating */
|
||||
public static Option $_mode;
|
||||
|
||||
/** @var Option<string> The data source name (DSN) of the connection string */
|
||||
private static Option $_pdoDSN;
|
||||
|
||||
/** @var PDO|null The PDO instance to use for database commands */
|
||||
private static ?PDO $_pdo = null;
|
||||
|
||||
/**
|
||||
* Use a Data Source Name (DSN)
|
||||
*
|
||||
* @param string $dsn The data source name to use (driver:[parameters])
|
||||
* @throws DocumentException If a DSN does not start with `pgsql:` or `sqlite:`
|
||||
*/
|
||||
public static function useDSN(string $dsn): void
|
||||
{
|
||||
if (empty($dsn)) {
|
||||
self::$_mode = self::$_pdoDSN = None::create();
|
||||
} else {
|
||||
self::$_mode = Some::create(Mode::deriveFromDSN($dsn));
|
||||
self::$_pdoDSN = Some::create($dsn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a new connection to the database
|
||||
*
|
||||
* @return PDO A new connection to the SQLite database with foreign key support enabled
|
||||
* @throws DocumentException If this is called before a connection string is set
|
||||
* @throws Exception If this is called before a connection string is set
|
||||
*/
|
||||
public static function dbConn(): PDO
|
||||
{
|
||||
if (is_null(self::$_pdo)) {
|
||||
if (empty(self::$pdoDSN)) {
|
||||
throw new DocumentException('Please provide a data source name (DSN) before attempting data access');
|
||||
}
|
||||
self::$_pdo = new PDO(self::$pdoDSN, $_ENV['PDO_DOC_USERNAME'] ?? self::$username,
|
||||
$dsn = (self::$_pdoDSN ?? None::create())->getOrThrow(
|
||||
new DocumentException('Please provide a data source name (DSN) before attempting data access'));
|
||||
self::$_pdo = new PDO($dsn, $_ENV['PDO_DOC_USERNAME'] ?? self::$username,
|
||||
$_ENV['PDO_DOC_PASSWORD'] ?? self::$password, self::$options);
|
||||
|
||||
if (is_null(self::$mode)) {
|
||||
$driver = self::$_pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
self::$mode = match ($driver) {
|
||||
'pgsql' => Mode::PgSQL,
|
||||
'sqlite' => Mode::SQLite,
|
||||
default => throw new DocumentException(
|
||||
"Unsupported driver $driver: this library currently supports PostgreSQL and SQLite")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return self::$_pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the mode for the current database connection
|
||||
*
|
||||
* @return Mode The mode for the current database connection
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public static function mode(?string $process = null): Mode
|
||||
{
|
||||
return self::$_mode->getOrThrow(
|
||||
new DocumentException('Database mode not set' . (is_null($process) ? '' : "; cannot $process")));
|
||||
}
|
||||
|
||||
/**
|
||||
* You probably don't mean to be calling this; it is here for testing only
|
||||
*
|
||||
* @param Mode|null $mode The mode to set
|
||||
*/
|
||||
public static function overrideMode(?Mode $mode): void
|
||||
{
|
||||
self::$_mode = Option::fromValue($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the current PDO instance
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
@@ -18,7 +24,7 @@ class Document
|
||||
{
|
||||
$doInsert = fn() => Custom::nonQuery(Query::insert($tableName), Parameters::json(':data', $document));
|
||||
|
||||
if (Configuration::$autoId == AutoId::None) {
|
||||
if (Configuration::$autoId === AutoId::None) {
|
||||
$doInsert();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Criteria for a field WHERE clause
|
||||
*/
|
||||
@@ -48,19 +56,19 @@ class Field
|
||||
* Get the WHERE clause fragment for this parameter
|
||||
*
|
||||
* @return string The WHERE clause fragment for this parameter
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception|DocumentException If the database mode has not been set
|
||||
*/
|
||||
public function toWhere(): string
|
||||
{
|
||||
$fieldName = ($this->qualifier == '' ? '' : "$this->qualifier.") . 'data' . match (true) {
|
||||
$mode = Configuration::mode('make field WHERE clause');
|
||||
$fieldName = (empty($this->qualifier) ? '' : "$this->qualifier.") . 'data' . match (true) {
|
||||
!str_contains($this->fieldName, '.') => "->>'$this->fieldName'",
|
||||
Configuration::$mode == Mode::PgSQL => "#>>'{" . implode(',', explode('.', $this->fieldName)) . "}'",
|
||||
Configuration::$mode == Mode::SQLite => "->>'" . implode("'->>'", explode('.', $this->fieldName)) . "'",
|
||||
default => throw new DocumentException('Database mode not set; cannot make field WHERE clause')
|
||||
$mode === Mode::PgSQL => "#>>'{" . implode(',', explode('.', $this->fieldName)) . "}'",
|
||||
$mode === Mode::SQLite => "->>'" . implode("'->>'", explode('.', $this->fieldName)) . "'"
|
||||
};
|
||||
$fieldPath = match (Configuration::$mode) {
|
||||
$fieldPath = match ($mode) {
|
||||
Mode::PgSQL => match (true) {
|
||||
$this->op == Op::BT => is_numeric($this->value[0]) ? "($fieldName)::numeric" : $fieldName,
|
||||
$this->op === Op::BT => is_numeric($this->value[0]) ? "($fieldName)::numeric" : $fieldName,
|
||||
is_numeric($this->value) => "($fieldName)::numeric",
|
||||
default => $fieldName
|
||||
},
|
||||
@@ -71,7 +79,7 @@ class Field
|
||||
Op::BT => " {$this->paramName}min AND {$this->paramName}max",
|
||||
default => " $this->paramName"
|
||||
};
|
||||
return $fieldPath . ' ' . $this->op->toString() . $criteria;
|
||||
return $fieldPath . ' ' . $this->op->toSQL() . $criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
@@ -18,7 +24,7 @@ enum FieldMatch
|
||||
*
|
||||
* @return string The SQL keyword for this enumeration value
|
||||
*/
|
||||
public function toString(): string
|
||||
public function toSQL(): string
|
||||
{
|
||||
return match ($this) {
|
||||
FieldMatch::All => 'AND',
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
@@ -7,9 +13,7 @@ namespace BitBadger\PDODocument\Mapper;
|
||||
*/
|
||||
class ArrayMapper implements Mapper
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function map(array $result): array
|
||||
{
|
||||
return $result;
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
@@ -7,9 +13,7 @@ namespace BitBadger\PDODocument\Mapper;
|
||||
*/
|
||||
class CountMapper implements Mapper
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function map(array $result): int
|
||||
{
|
||||
return (int) $result[0];
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Mode};
|
||||
use BitBadger\PDODocument\{Configuration, Mode};
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Map an EXISTS result to a boolean value
|
||||
@@ -11,14 +18,13 @@ class ExistsMapper implements Mapper
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public function map(array $result): bool
|
||||
{
|
||||
return match (Configuration::$mode) {
|
||||
return match (Configuration::mode('map existence result')) {
|
||||
Mode::PgSQL => (bool)$result[0],
|
||||
Mode::SQLite => (int)$result[0] > 0,
|
||||
default => throw new DocumentException('Database mode not set; cannot map existence result'),
|
||||
Mode::SQLite => (int)$result[0] > 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Mapper;
|
||||
|
||||
/**
|
||||
* Map a string result from the
|
||||
* Map a string result from the named field
|
||||
*
|
||||
* @implements Mapper<string>
|
||||
*/
|
||||
|
||||
23
src/Mode.php
23
src/Mode.php
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
@@ -12,4 +18,19 @@ enum Mode
|
||||
|
||||
/** Storing documents in a SQLite database */
|
||||
case SQLite;
|
||||
|
||||
/**
|
||||
* Derive the mode from the Data Source Name (DSN)
|
||||
*
|
||||
* @return Mode The database mode based on the DSN
|
||||
* @throws DocumentException If the DSN does not start with `pgsql:` or `sqlite:`
|
||||
*/
|
||||
public static function deriveFromDSN(string $dsn): Mode
|
||||
{
|
||||
return match (true) {
|
||||
str_starts_with($dsn, 'pgsql:') => Mode::PgSQL,
|
||||
str_starts_with($dsn, 'sqlite:') => Mode::SQLite,
|
||||
default => throw new DocumentException('This library currently supports PostgreSQL and SQLite')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
12
src/Op.php
12
src/Op.php
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
@@ -27,11 +33,11 @@ enum Op
|
||||
case NEX;
|
||||
|
||||
/**
|
||||
* Get the string representation of this operator
|
||||
* Get the SQL representation of this operator
|
||||
*
|
||||
* @return string The operator to use in SQL statements
|
||||
*/
|
||||
public function toString(): string
|
||||
public function toSQL(): string
|
||||
{
|
||||
return match ($this) {
|
||||
Op::EQ => "=",
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Functions to create parameters for queries
|
||||
*/
|
||||
@@ -57,7 +65,7 @@ class Parameters
|
||||
public static function nameFields(array $fields): array
|
||||
{
|
||||
for ($idx = 0; $idx < sizeof($fields); $idx++) {
|
||||
if ($fields[$idx]->paramName == '') $fields[$idx]->paramName = ":field$idx";
|
||||
if (empty($fields[$idx]->paramName)) $fields[$idx]->paramName = ":field$idx";
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
@@ -80,20 +88,18 @@ class Parameters
|
||||
* @param string $paramName The name of the parameter for the field names
|
||||
* @param array|string[] $fieldNames The names of the fields for the parameter
|
||||
* @return array An associative array of parameter/value pairs for the field names
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public static function fieldNames(string $paramName, array $fieldNames): array
|
||||
{
|
||||
switch (Configuration::$mode) {
|
||||
case Mode::PgSQL:
|
||||
return [$paramName => "{" . implode(",", $fieldNames) . "}"];
|
||||
case Mode::SQLite:
|
||||
$it = [];
|
||||
$idx = 0;
|
||||
foreach ($fieldNames as $field) $it[$paramName . $idx++] = "$.$field";
|
||||
return $it;
|
||||
default:
|
||||
throw new DocumentException('Database mode not set; cannot generate field name parameters');
|
||||
}
|
||||
$mode = Configuration::mode('generate field name parameters');
|
||||
|
||||
if ($mode === Mode::PgSQL) return [$paramName => "{" . implode(",", $fieldNames) . "}"];
|
||||
|
||||
// else SQLite
|
||||
$it = [];
|
||||
$idx = 0;
|
||||
foreach ($fieldNames as $field) $it[$paramName . $idx++] = "$.$field";
|
||||
return $it;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
use Exception;
|
||||
use Random\RandomException;
|
||||
|
||||
/**
|
||||
@@ -30,8 +37,7 @@ class Query
|
||||
*/
|
||||
public static function whereByFields(array $fields, ?FieldMatch $match = null): string
|
||||
{
|
||||
return implode(' ' . ($match ?? FieldMatch::All)->toString() . ' ',
|
||||
array_map(fn($it) => $it->toWhere(), $fields));
|
||||
return implode(' ' . ($match ?? FieldMatch::All)->toSQL() . ' ', array_map(fn($it) => $it->toWhere(), $fields));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,11 +59,11 @@ class Query
|
||||
*
|
||||
* @param string $paramName The name of the parameter (optional; defaults to `:criteria`)
|
||||
* @return string The WHERE clause fragment for a JSON containment query
|
||||
* @throws DocumentException If the database mode is not PostgreSQL
|
||||
* @throws Exception|DocumentException If the database mode is not PostgreSQL
|
||||
*/
|
||||
public static function whereDataContains(string $paramName = ':criteria'): string
|
||||
{
|
||||
if (Configuration::$mode <> Mode::PgSQL) {
|
||||
if (Configuration::mode() <> Mode::PgSQL) {
|
||||
throw new DocumentException('JSON containment is only supported on PostgreSQL');
|
||||
}
|
||||
return "data @> $paramName";
|
||||
@@ -68,11 +74,11 @@ class Query
|
||||
*
|
||||
* @param string $paramName The name of the parameter (optional; defaults to `:path`)
|
||||
* @return string The WHERE clause fragment for a JSON Path match query
|
||||
* @throws DocumentException If the database mode is not PostgreSQL
|
||||
* @throws Exception|DocumentException If the database mode is not PostgreSQL
|
||||
*/
|
||||
public static function whereJsonPathMatches(string $paramName = ':path'): string
|
||||
{
|
||||
if (Configuration::$mode <> Mode::PgSQL) {
|
||||
if (Configuration::mode() <> Mode::PgSQL) {
|
||||
throw new DocumentException('JSON Path matching is only supported on PostgreSQL');
|
||||
}
|
||||
return "jsonb_path_exists(data, $paramName::jsonpath)";
|
||||
@@ -84,13 +90,13 @@ class Query
|
||||
* @param string $tableName The name of the table into which the document will be inserted
|
||||
* @param AutoId|null $autoId The version of automatic ID query to generate (optional, defaults to None)
|
||||
* @return string The `INSERT` statement to insert a document
|
||||
* @throws DocumentException If the database mode is not set
|
||||
* @throws Exception|DocumentException If the database mode is not set
|
||||
*/
|
||||
public static function insert(string $tableName, ?AutoId $autoId = null): string
|
||||
{
|
||||
try {
|
||||
$id = Configuration::$idField;
|
||||
$values = match (Configuration::$mode) {
|
||||
$id = Configuration::$idField;
|
||||
$values = match (Configuration::mode('generate auto-ID INSERT statement')) {
|
||||
Mode::SQLite => match ($autoId ?? AutoId::None) {
|
||||
AutoId::None => ':data',
|
||||
AutoId::Number => "json_set(:data, '$.$id', "
|
||||
@@ -105,9 +111,7 @@ class Query
|
||||
. "FROM $tableName) || '}')::jsonb",
|
||||
AutoId::UUID => ":data::jsonb || '{\"$id\":\"" . AutoId::generateUUID() . "\"}'",
|
||||
AutoId::RandomString => ":data::jsonb || '{\"$id\":\"" . AutoId::generateRandom() . "\"}'",
|
||||
},
|
||||
default =>
|
||||
throw new DocumentException('Database mode not set; cannot generate auto-ID INSERT statement'),
|
||||
}
|
||||
};
|
||||
return "INSERT INTO $tableName VALUES ($values)";
|
||||
} catch (RandomException $ex) {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, DocumentIndex, Mode};
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Queries to define tables and indexes
|
||||
@@ -14,14 +21,13 @@ class Definition
|
||||
*
|
||||
* @param string $name The name of the table (including schema, if applicable)
|
||||
* @return string The CREATE TABLE statement for the document table
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public static function ensureTable(string $name): string
|
||||
{
|
||||
$dataType = match (Configuration::$mode) {
|
||||
$dataType = match (Configuration::mode('make create table statement')) {
|
||||
Mode::PgSQL => 'JSONB',
|
||||
Mode::SQLite => 'TEXT',
|
||||
default => throw new DocumentException('Database mode not set; cannot make create table statement')
|
||||
Mode::SQLite => 'TEXT'
|
||||
};
|
||||
return "CREATE TABLE IF NOT EXISTS $name (data $dataType NOT NULL)";
|
||||
}
|
||||
@@ -35,7 +41,7 @@ class Definition
|
||||
private static function splitSchemaAndTable(string $tableName): array
|
||||
{
|
||||
$parts = explode('.', $tableName);
|
||||
return sizeof($parts) == 1 ? ["", $tableName] : [$parts[0], $parts[1]];
|
||||
return sizeof($parts) === 1 ? ["", $tableName] : [$parts[0], $parts[1]];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +57,7 @@ class Definition
|
||||
[, $tbl] = self::splitSchemaAndTable($tableName);
|
||||
$jsonFields = implode(', ', array_map(function (string $field) {
|
||||
$parts = explode(' ', $field);
|
||||
$fieldName = sizeof($parts) == 1 ? $field : $parts[0];
|
||||
$fieldName = sizeof($parts) === 1 ? $field : $parts[0];
|
||||
$direction = sizeof($parts) < 2 ? "" : " $parts[1]";
|
||||
return "(data->>'$fieldName')$direction";
|
||||
}, $fields));
|
||||
@@ -75,16 +81,16 @@ class Definition
|
||||
* @param string $tableName The name of the table on which the document index should be created
|
||||
* @param DocumentIndex $indexType The type of index to be created
|
||||
* @return string The SQL statement to create an index on JSON documents in the specified table
|
||||
* @throws DocumentException If the database mode is not PostgreSQL
|
||||
* @throws Exception|DocumentException If the database mode is not PostgreSQL
|
||||
*/
|
||||
public static function ensureDocumentIndexOn(string $tableName, DocumentIndex $indexType): string
|
||||
{
|
||||
if (Configuration::$mode <> Mode::PgSQL) {
|
||||
if (Configuration::mode() <> Mode::PgSQL) {
|
||||
throw new DocumentException('Document indexes are only supported on PostgreSQL');
|
||||
}
|
||||
[, $tbl] = self::splitSchemaAndTable($tableName);
|
||||
$extraOps = match ($indexType) {
|
||||
DocumentIndex::Full => '',
|
||||
DocumentIndex::Full => '',
|
||||
DocumentIndex::Optimized => ' jsonb_path_ops'
|
||||
};
|
||||
return "CREATE INDEX IF NOT EXISTS idx_{$tbl}_document ON $tableName USING GIN (data$extraOps)";
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, FieldMatch, Mode, Query};
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Queries to perform partial updates on documents
|
||||
@@ -15,14 +22,13 @@ class Patch
|
||||
* @param string $tableName The name of the table in which documents should be patched
|
||||
* @param string $whereClause The body of the WHERE clause to use in the UPDATE statement
|
||||
* @return string The UPDATE statement to perform the patch
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public static function update(string $tableName, string $whereClause): string
|
||||
{
|
||||
$setValue = match (Configuration::$mode) {
|
||||
$setValue = match (Configuration::mode('make patch statement')) {
|
||||
Mode::PgSQL => 'data || :data',
|
||||
Mode::SQLite => 'json_patch(data, json(:data))',
|
||||
default => throw new DocumentException('Database mode not set; cannot make patch statement')
|
||||
Mode::SQLite => 'json_patch(data, json(:data))'
|
||||
};
|
||||
return "UPDATE $tableName SET data = $setValue WHERE $whereClause";
|
||||
}
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument\Query;
|
||||
|
||||
use BitBadger\PDODocument\{Configuration, DocumentException, Field, FieldMatch, Mode, Query};
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Queries to remove fields from documents
|
||||
@@ -20,20 +27,16 @@ class RemoveFields
|
||||
* @param array $parameters The parameter list for the query
|
||||
* @param string $whereClause The body of the WHERE clause for the update
|
||||
* @return string The UPDATE statement to remove fields from a JSON document
|
||||
* @throws DocumentException If the database mode has not been set
|
||||
* @throws Exception If the database mode has not been set
|
||||
*/
|
||||
public static function update(string $tableName, array $parameters, string $whereClause): string
|
||||
{
|
||||
switch (Configuration::$mode) {
|
||||
case Mode::PgSQL:
|
||||
return "UPDATE $tableName SET data = data - " . array_keys($parameters)[0]
|
||||
. "::text[] WHERE $whereClause";
|
||||
case Mode::SQLite:
|
||||
$paramNames = implode(', ', array_keys($parameters));
|
||||
return "UPDATE $tableName SET data = json_remove(data, $paramNames) WHERE $whereClause";
|
||||
default:
|
||||
throw new DocumentException('Database mode not set; cannot generate field removal query');
|
||||
}
|
||||
return match (Configuration::mode('generate field removal query')) {
|
||||
Mode::PgSQL => "UPDATE $tableName SET data = data - " . array_keys($parameters)[0]
|
||||
. "::text[] WHERE $whereClause",
|
||||
Mode::SQLite => "UPDATE $tableName SET data = json_remove(data, " . implode(', ', array_keys($parameters))
|
||||
. ") WHERE $whereClause"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
/**
|
||||
* @author Daniel J. Summers <daniel@bitbadger.solutions>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace BitBadger\PDODocument;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user