From f6cab541afee9a1a0ce6d8ad0375f48687c8e65b Mon Sep 17 00:00:00 2001 From: n0nag0n Date: Fri, 26 Apr 2024 22:48:17 -0600 Subject: [PATCH] added ability to have text based primary keys --- src/ActiveRecord.php | 11 +++-- tests/ActiveRecordPdoIntegrationTest.php | 53 ++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php index 3b2a06f..4f99319 100644 --- a/src/ActiveRecord.php +++ b/src/ActiveRecord.php @@ -451,12 +451,17 @@ public function insert(): ActiveRecord ]); $this->values = new Expressions(['operator' => 'VALUES', 'target' => new WrapExpressions(['target' => $value])]); + $intentionallyAssignedPrimaryKey = $this->dirty[$this->primaryKey] ?? null; + $this->execute($this->buildSql(['insert', 'values']), $this->params); - $this->{$this->primaryKey} = $this->databaseConnection->lastInsertId(); + + $this->{$this->primaryKey} = $intentionallyAssignedPrimaryKey ?: $this->databaseConnection->lastInsertId(); $this->processEvent([ 'afterInsert', 'afterSave' ], [ $this ]); - return $this->dirty()->resetQueryData(); + $this->isHydrated = true; + + return $this->dirty(); } /** * function to build update SQL, and update current record in database, just write the dirty data into database. @@ -486,7 +491,7 @@ public function update(): ActiveRecord */ public function save(): ActiveRecord { - if ($this->{$this->primaryKey}) { + if ($this->{$this->primaryKey} !== null && $this->isHydrated() === true) { $record = $this->update(); } else { $record = $this->insert(); diff --git a/tests/ActiveRecordPdoIntegrationTest.php b/tests/ActiveRecordPdoIntegrationTest.php index a124ce1..398a2bc 100644 --- a/tests/ActiveRecordPdoIntegrationTest.php +++ b/tests/ActiveRecordPdoIntegrationTest.php @@ -46,6 +46,7 @@ public function tearDown(): void { $this->ActiveRecord->execute("DROP TABLE IF EXISTS contact;"); $this->ActiveRecord->execute("DROP TABLE IF EXISTS user;"); + $this->ActiveRecord->execute("DROP TABLE IF EXISTS my_text_table;"); } public function testInsert() @@ -550,4 +551,56 @@ public function testRelationWithProtectedKeyword() $this->expectExceptionMessage('group is a protected keyword and cannot be used as a relation name'); $contact->group->id; } + + public function testTextBasedPrimaryKey() { + $this->ActiveRecord->execute("CREATE TABLE IF NOT EXISTS my_text_table ( + my_pk TEXT NOT NULL PRIMARY KEY, + data INTEGER, name TEXT + )"); + + $myTextTable = new class (new PDO('sqlite:test.db'), 'my_text_table', [ 'primaryKey' => 'my_pk' ]) extends ActiveRecord { + }; + + $my_pk = time(); + $myTextTable->my_pk = $my_pk; + $myTextTable->data = 12345; + + $this->assertTrue($myTextTable->isDirty()); + $myTextTable->save(); + + $this->assertTrue($myTextTable->isHydrated()); + + $myTextTable->reset(); + + $myTextTable->find($my_pk); + + $this->assertEquals($my_pk, $myTextTable->my_pk); + $this->assertEquals(12345, $myTextTable->data); + $this->assertTrue($myTextTable->isHydrated()); + } + + public function testTextBasedPrimaryKeyDuplicateKey() { + $this->ActiveRecord->execute("CREATE TABLE IF NOT EXISTS my_text_table ( + my_pk TEXT NOT NULL PRIMARY KEY, + data INTEGER, name TEXT + )"); + + $myTextTable = new class (new PDO('sqlite:test.db'), 'my_text_table', [ 'primaryKey' => 'my_pk' ]) extends ActiveRecord { + }; + + $my_pk = time(); + $myTextTable->my_pk = $my_pk; + $myTextTable->data = 12345; + $myTextTable->save(); + + $myTextTable2 = new class (new PDO('sqlite:test.db'), 'my_text_table', [ 'primaryKey' => 'my_pk' ]) extends ActiveRecord { + }; + + $myTextTable2->my_pk = $my_pk; + $myTextTable2->data = 12345; + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('UNIQUE constraint failed: my_text_table.my_pk'); + $myTextTable2->save(); + } }