From dc31b65be8c8e5db7b5182475113f4b5edc32428 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Fri, 25 Aug 2023 12:20:48 -0400 Subject: [PATCH] WIP on data (JSON Path queries) --- src/app/Data.php | 16 ++++++++--- src/app/documents/Configuration.php | 44 +++++++++++++++++++++++++++++ src/app/documents/Document.php | 18 ++++++++++-- src/app/documents/functions.php | 11 ++++++++ src/app/index.php | 11 ++++++-- 5 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/app/Data.php b/src/app/Data.php index 3043c6d..dfcb6f1 100644 --- a/src/app/Data.php +++ b/src/app/Data.php @@ -11,12 +11,20 @@ class Data /** The prayer request table */ const REQ_TABLE = 'prayer_request'; + /** + * Configure the data connection + */ + public static function configure() + { + Configuration::$connectionString = 'pgsql:host=localhost;port=5432;dbname=leafjson;user=leaf;password=leaf'; + //Configuration::$startUp = '\MyPrayerJournal\Data::startUp'; + } + /** * Ensure the table and index exist */ public static function startUp() { - Configuration::$connectionString = "pgsql:host=localhost;port=5432;dbname=leafjson;user=leaf;password=leaf"; Definition::ensureTable(self::REQ_TABLE); Definition::ensureIndex(self::REQ_TABLE, DocumentIndex::Optimized); } @@ -96,10 +104,10 @@ class Data private static function getJournalByAnswered(string $userId, string $op): array { $sql = Query::selectFromTable(self::REQ_TABLE) - . ' WHERE ' . Query::whereDataContains(':criteria') . ' AND ' . Query::whereJsonPathMatches(':path'); + . ' WHERE ' . Query::whereDataContains('$1') . ' AND ' . Query::whereJsonPathMatches('$2'); $params = [ - ':criteria' => Query::jsonbDocParam([ 'userId' => $userId ]), - ':path' => '$.history[*].action (@ ' . $op . ' "' . RequestAction::Answered->name . '")' + Query::jsonbDocParam([ 'userId' => $userId ]), + '$.history[*].action (@ ' . $op . ' "' . RequestAction::Answered->name . '")' ]; return self::mapToJournalRequest( Document::customList($sql, $params, Request::class, Document::mapFromJson(...)), true); diff --git a/src/app/documents/Configuration.php b/src/app/documents/Configuration.php index 953d34f..c90786e 100644 --- a/src/app/documents/Configuration.php +++ b/src/app/documents/Configuration.php @@ -3,6 +3,8 @@ declare(strict_types=1); namespace BitBadger\PgSQL\Documents; +use \PgSql\Connection; + /** * Document table configuration */ @@ -14,6 +16,27 @@ class Configuration /** @var ?\PDO $conn The active connection */ private static ?\PDO $conn = null; + /** @var ?Connection $rawConn An active non-PDO PostgreSQL connection */ + private static ?Connection $rawConn = null; + + /** @var ?string $startUp The name of a function to run on first connection to the database */ + public static ?string $startUp = null; + + /** + * Ensure that the connection string is set, either explicity, by environment variables, or with defaults + */ + private static function ensureConnectionString() + { + if (self::$connectionString == "") { + $host = $_ENV['PGDOC_HOST'] ?? 'localhost'; + $port = $_ENV['PGDOC_PORT'] ?? 5432; + $db = $_ENV['PGDOC_DB'] ?? 'postgres'; + $user = $_ENV['PGDOC_USER'] ?? 'postgres'; + $pass = $_ENV['PGDOC_PASS'] ?? 'postgres'; + self::$connectionString = "pgsql:host=$host;port=$port;dbname=$db;user=$user;pass=$pass"; + } + } + /** * Get the database connection, connecting on first request * @@ -22,10 +45,31 @@ class Configuration public static function getConn(): \PDO { if (is_null(self::$conn)) { + self::ensureConnectionString(); self::$conn = new \PDO(self::$connectionString); + + if (!is_null(self::$startUp)) { + call_user_func(self::$startUp); + } } return self::$conn; } + + /** + * + */ + public static function getRawConn(): Connection + { + if (is_null(self::$rawConn)) { + self::ensureConnectionString(); + self::$rawConn = pg_connect(str_replace(';', ' ', self::$connectionString)); + + if (!is_null(self::$startUp)) { + call_user_func(self::$startUp); + } + } + return self::$rawConn; + } } require('functions.php'); diff --git a/src/app/documents/Document.php b/src/app/documents/Document.php index 68e99ea..55df2cb 100644 --- a/src/app/documents/Document.php +++ b/src/app/documents/Document.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace BitBadger\PgSQL\Documents; use PDOStatement; +use PgSql\Result; /** Document manipulation functions */ class Document @@ -402,8 +403,14 @@ class Document */ private static function createCustomQuery(string $sql, array $params): PDOStatement { + $result = pg_query_params(pgconn(), $sql, $params); + echo "Preparing statement for $sql\n"; + foreach ($params as $name => $value) { + echo "Binding $name to $value\n"; + } $query = pdo()->prepare($sql); foreach ($params as $name => $value) { + echo "Binding $name to $value\n"; $query->bindParam($name, $value); } $query->execute(); @@ -421,9 +428,14 @@ class Document */ public static function customList(string $sql, array $params, string $className, callable $mapFunc): array { - return array_map( - fn ($it) => $mapFunc($it, $className), - self::createCustomQuery($sql, $params)->fetchAll(\PDO::FETCH_ASSOC)); + $data = pg_query_params(pgconn(), $sql, $params); + $result = []; + if (!$data) return $result; + while ($row = pg_fetch_array($data, mode: PGSQL_ASSOC)) { + array_push($result, $mapFunc($row, $className)); + } + pg_free_result($data); + return $result; } /** diff --git a/src/app/documents/functions.php b/src/app/documents/functions.php index a302a0f..5a93afd 100644 --- a/src/app/documents/functions.php +++ b/src/app/documents/functions.php @@ -13,3 +13,14 @@ if (!function_exists('pdo')) { return Configuration::getConn(); } } +if (!function_exists('pgconn')) { + /** + * Return the active PostgreSQL connection + * + * @return \PgSql\Connection The open PostgreSQL connection + */ + function pgconn() + { + return Configuration::getRawConn(); + } +} diff --git a/src/app/index.php b/src/app/index.php index e929bcb..e30b6d7 100644 --- a/src/app/index.php +++ b/src/app/index.php @@ -4,11 +4,14 @@ require __DIR__ . '/vendor/autoload.php'; use MyPrayerJournal\Data; -Data::startUp(); +Data::configure(); +//Data::findFullRequestById('abc', 'def'); +//echo "Returned from req\n"; + +//Data::getAnsweredRequests('abc'); app()->template->config('path', './pages'); app()->template->config('params', [ - // 'app' => function () { return app(); }, 'page_link' => function (string $url, bool $checkActive = false) { echo 'href="'. $url . '" hx-get="' . $url . '"'; if ($checkActive && str_starts_with($_SERVER['REQUEST_URI'], $url)) { @@ -34,8 +37,10 @@ function renderPage(string $template, array $params, string $pageTitle) response()->markup(app()->template->render('layout/full', $params)); } +Data::getAnsweredRequests('abc'); app()->get('/', function () { - renderPage('home', [], 'Welcome'); + phpinfo(); + //renderPage('home', [], 'Welcome'); }); app()->get('/legal/privacy-policy', function () {