From 38aa353984d4378ade367a4bee9d14a577c436a1 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Wed, 3 Jun 2026 07:02:16 +0200 Subject: [PATCH] feat(pdo): add fetch-object statement wrapper Related to #11 --- CHANGELOG.md | 1 + README.md | 1 + src/pdo/statement.phel | 9 ++++++++- tests/pdo_test.phel | 12 ++++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6415e..f6043e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `pdo/insert` - build an `INSERT` from a map (`(pdo/insert conn :table {:col v ...})`), execute it as a prepared statement, and return the new `last-insert-id`. Identifiers must match `[A-Za-z_][A-Za-z0-9_]*` ([#4]). - `pdo/bind-param` - wrap `PDOStatement::bindParam`; binds a parameter applied at execution time ([#8]). - `pdo/close-cursor` - wrap `PDOStatement::closeCursor`; frees the cursor so the statement can be re-executed ([#9]). +- `pdo/fetch-object` - wrap `PDOStatement::fetchObject`; returns the next row as an object (`stdClass` or a named class), or `nil` when exhausted ([#11]). ## [0.1.0] - 2026-05-13 diff --git a/README.md b/README.md index 4dc0fda..0d9c9e4 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Returned by `pdo/query` and `pdo/prepare`. | `fetch` | `(fetch stmt)` | Next row as a map, or `nil` if exhausted. | | `fetch-all` | `(fetch-all stmt)` | Remaining rows as a vector of maps. | | `fetch-column` | `(fetch-column stmt & [column])` | Single column from the next row. | +| `fetch-object` | `(fetch-object stmt & [class-name ctor-args])` | Next row as an object (`stdClass` by default, or an instance of `class-name`), or `nil` if exhausted. | | `bind-value` | `(bind-value stmt column value & [type])` | Bind a value to a placeholder. Returns the statement. | | `bind-param` | `(bind-param stmt column value & [type])` | Bind a parameter, applied at execution time. Returns the statement. | | `column-count` | `(column-count stmt)` | Number of columns in the result set. | diff --git a/src/pdo/statement.phel b/src/pdo/statement.phel index 6565542..29603a7 100644 --- a/src/pdo/statement.phel +++ b/src/pdo/statement.phel @@ -21,6 +21,14 @@ [stmt] (map row->map (php/-> (stmt :stmt) (fetchAll \PDO/FETCH_ASSOC)))) +(defn fetch-object + "Fetches the next row as an object (stdClass by default, or an instance of class-name), or nil if no more rows" + [stmt & [class-name ctor-args]] + (when-let [obj (php/-> (stmt :stmt) + (fetchObject (or class-name "stdClass") + (phel->php (or ctor-args []))))] + obj)) + (defn execute "Executes a prepared statement" [stmt & [params]] @@ -71,7 +79,6 @@ ;; PDOStatement::bindColumn — Bind a column to a PHP variable ;; PDOStatement::errorCode — Fetch the SQLSTATE associated with the last operation on the statement handle ;; PDOStatement::errorInfo — Fetch extended error information associated with the last operation on the statement handle -;; PDOStatement::fetchObject — Fetches the next row and returns it as an object ;; PDOStatement::getAttribute — Retrieve a statement attribute ;; PDOStatement::getColumnMeta — Returns metadata for a column in a result set ;; PDOStatement::getIterator — Gets result set iterator diff --git a/tests/pdo_test.phel b/tests/pdo_test.phel index 83be24c..8a02528 100644 --- a/tests/pdo_test.phel +++ b/tests/pdo_test.phel @@ -111,6 +111,18 @@ (let [stmt (pdo/query *conn* "select * from t1")] (is (= [{:id 1 :name "phel"} {:id 2 :name "php"}] (pdo/fetch-all stmt))))) +(deftest fetch-object-returns-stdclass-row + (seed-t1 *conn*) + (let [stmt (pdo/query *conn* "select * from t1 where id = 1") + obj (pdo/fetch-object stmt)] + (is (= "stdClass" (php/get_class obj))) + (is (= "phel" (php/-> obj name))))) + +(deftest fetch-object-returns-nil-when-no-rows + (seed-t1 *conn*) + (let [stmt (pdo/query *conn* "select * from t1 where id = 999")] + (is (nil? (pdo/fetch-object stmt))))) + (deftest column-count-on-select (seed-t1 *conn*) (let [stmt (pdo/query *conn* "select * from t1")]