From 3cb6c3cd4bf00dd83dcff2a669b2bebee2d14942 Mon Sep 17 00:00:00 2001 From: UniForceMusic <51342446+UniForceMusic@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:07:19 +0100 Subject: [PATCH 1/3] feat: add Firebird support --- src/Engine/FirebirdEngine.php | 25 ++++++++++++ src/Query/Firebird/DeleteQuery.php | 23 +++++++++++ src/Query/Firebird/InsertQuery.php | 21 ++++++++++ src/Query/Firebird/SelectQuery.php | 40 ++++++++++++++++++++ tests/Engine/FirebirdTest.php | 28 ++++++++++++++ tests/Query/Firebird/DeleteTest.php | 22 +++++++++++ tests/Query/Firebird/FirebirdEngineSetup.php | 16 ++++++++ tests/Query/Firebird/InsertTest.php | 24 ++++++++++++ tests/Query/Firebird/SelectTest.php | 35 +++++++++++++++++ 9 files changed, 234 insertions(+) create mode 100644 src/Engine/FirebirdEngine.php create mode 100644 src/Query/Firebird/DeleteQuery.php create mode 100644 src/Query/Firebird/InsertQuery.php create mode 100644 src/Query/Firebird/SelectQuery.php create mode 100644 tests/Engine/FirebirdTest.php create mode 100644 tests/Query/Firebird/DeleteTest.php create mode 100644 tests/Query/Firebird/FirebirdEngineSetup.php create mode 100644 tests/Query/Firebird/InsertTest.php create mode 100644 tests/Query/Firebird/SelectTest.php diff --git a/src/Engine/FirebirdEngine.php b/src/Engine/FirebirdEngine.php new file mode 100644 index 0000000..fa71328 --- /dev/null +++ b/src/Engine/FirebirdEngine.php @@ -0,0 +1,25 @@ +limit)) { + return $query; + } + + return $query->append('ROWS %s', literal($this->limit)); + } +} diff --git a/src/Query/Firebird/InsertQuery.php b/src/Query/Firebird/InsertQuery.php new file mode 100644 index 0000000..6495ebd --- /dev/null +++ b/src/Query/Firebird/InsertQuery.php @@ -0,0 +1,21 @@ +applyReturning($query); + + return $query; + } +} diff --git a/src/Query/Firebird/SelectQuery.php b/src/Query/Firebird/SelectQuery.php new file mode 100644 index 0000000..de1f2e4 --- /dev/null +++ b/src/Query/Firebird/SelectQuery.php @@ -0,0 +1,40 @@ +limit) || !is_int($this->offset)) { + return $query; + } + + $rows = $this->offset + 1; + $to = $rows + $this->limit - 1; + + return $query->append('ROWS %d TO %d', literal($rows), literal($to)); + } + + protected function applyLimit(ExpressionInterface $query): ExpressionInterface + { + if (!is_int($this->limit)) { + return $query; + } + + // When offset is present, ROWS acts differently and should be handled in ->applyOffset() + if (is_int($this->offset)) { + return $query; + } + + return $query->append('ROWS %s', literal($this->limit)); + } +} diff --git a/tests/Engine/FirebirdTest.php b/tests/Engine/FirebirdTest.php new file mode 100644 index 0000000..a7673f6 --- /dev/null +++ b/tests/Engine/FirebirdTest.php @@ -0,0 +1,28 @@ +engine = new FirebirdEngine(); + } + + public function testIdentifier(): void + { + $field = identify('id'); + + $this->assertSql('"id"', $field); + + $field = identify('contains"quotes'); + + $this->assertSql('"contains""quotes"', $field); + } +} diff --git a/tests/Query/Firebird/DeleteTest.php b/tests/Query/Firebird/DeleteTest.php new file mode 100644 index 0000000..4ab6a0d --- /dev/null +++ b/tests/Query/Firebird/DeleteTest.php @@ -0,0 +1,22 @@ +factory + ->delete('users') + ->limit(10); + + $this->assertSql('DELETE FROM "users" ROWS 10', $delete); + $this->assertParams([], $delete); + } +} diff --git a/tests/Query/Firebird/FirebirdEngineSetup.php b/tests/Query/Firebird/FirebirdEngineSetup.php new file mode 100644 index 0000000..2b10a6d --- /dev/null +++ b/tests/Query/Firebird/FirebirdEngineSetup.php @@ -0,0 +1,16 @@ +factory + ->insert('users', [ + 'username' => 'jay', + ]) + ->returning('id'); + + $this->assertSql('INSERT INTO "users" ("username") VALUES (?) RETURNING "id"', $insert); + $this->assertParams(['jay'], $insert); + } +} diff --git a/tests/Query/Firebird/SelectTest.php b/tests/Query/Firebird/SelectTest.php new file mode 100644 index 0000000..ac65e2a --- /dev/null +++ b/tests/Query/Firebird/SelectTest.php @@ -0,0 +1,35 @@ +factory + ->select() + ->from('users') + ->limit(10); + + $this->assertSql('SELECT * FROM "users" ROWS 10', $select); + $this->assertParams([], $select); + } + + public function testLimitWithOffset(): void + { + $select = $this->factory + ->select() + ->from('users') + ->offset(5) + ->limit(10); + + $this->assertSql('SELECT * FROM "users" ROWS 6 TO 15', $select); + $this->assertParams([], $select); + } +} From e38162a55444740f92c91dd94044aa7c7d617ca2 Mon Sep 17 00:00:00 2001 From: UniForceMusic <51342446+UniForceMusic@users.noreply.github.com> Date: Wed, 3 Dec 2025 15:14:19 +0100 Subject: [PATCH 2/3] feat: add returning to delete query --- src/Query/Firebird/DeleteQuery.php | 11 +++++++++++ tests/Query/Firebird/DeleteTest.php | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Query/Firebird/DeleteQuery.php b/src/Query/Firebird/DeleteQuery.php index fe23f78..78d7b1f 100644 --- a/src/Query/Firebird/DeleteQuery.php +++ b/src/Query/Firebird/DeleteQuery.php @@ -7,11 +7,22 @@ use Latitude\QueryBuilder\ExpressionInterface; use Latitude\QueryBuilder\Query; +use Latitude\QueryBuilder\Query\Capability\HasReturning; use function is_int; use function Latitude\QueryBuilder\literal; class DeleteQuery extends Query\DeleteQuery { + use HasReturning; + + public function asExpression(): ExpressionInterface + { + $query = parent::asExpression(); + $query = $this->applyReturning($query); + + return $query; + } + protected function applyLimit(ExpressionInterface $query): ExpressionInterface { if (!is_int($this->limit)) { diff --git a/tests/Query/Firebird/DeleteTest.php b/tests/Query/Firebird/DeleteTest.php index 4ab6a0d..8f4dc84 100644 --- a/tests/Query/Firebird/DeleteTest.php +++ b/tests/Query/Firebird/DeleteTest.php @@ -19,4 +19,15 @@ public function testLimit(): void $this->assertSql('DELETE FROM "users" ROWS 10', $delete); $this->assertParams([], $delete); } + + public function testLimitWithReturning(): void + { + $delete = $this->factory + ->delete('users') + ->limit(10) + ->returning('id'); + + $this->assertSql('DELETE FROM "users" ROWS 10 RETURNING "id"', $delete); + $this->assertParams([], $delete); + } } From 2a9d5d5d7aef17529bf626d7e90120c646cbe723 Mon Sep 17 00:00:00 2001 From: UniForceMusic <51342446+UniForceMusic@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:38:12 +0100 Subject: [PATCH 3/3] feat: add docs for Firebird engine --- docs/engines.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/engines.md b/docs/engines.md index 0c86a4f..be5986e 100644 --- a/docs/engines.md +++ b/docs/engines.md @@ -45,3 +45,8 @@ converts boolean values into small integers because SQLite does not have a separate boolean storage class. Instead, boolean values are stored as integers: `0` (false) and `1` (true). +## Firebird Engine + +The Firebird Engine is `Latitude\QueryBuilder\Engine\FirebirdEngine`. This engine +adheres to the SQL-92, with the only custom implementation being limit and offset. +The returning clause is also added to `INSERT` and `DELETE` queries.