-
Notifications
You must be signed in to change notification settings - Fork 5
Round-trip vectorsdb collection dimension through migrations #210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,8 @@ | |
|
|
||
| class Collection extends Table | ||
| { | ||
| protected ?int $dimension = null; | ||
|
|
||
| public static function getName(): string | ||
| { | ||
| return Resource::TYPE_COLLECTION; | ||
|
|
@@ -25,7 +27,8 @@ public static function getName(): string | |
| * permissions: ?array<string>, | ||
| * createdAt: string, | ||
| * updatedAt: string, | ||
| * enabled: bool | ||
| * enabled: bool, | ||
| * dimension?: ?int | ||
| * } $array | ||
| */ | ||
| public static function fromArray(array $array): self | ||
|
|
@@ -36,7 +39,7 @@ public static function fromArray(array $array): self | |
| default => Database::fromArray($array['database']) | ||
| }; | ||
|
|
||
| return new self( | ||
| $collection = new self( | ||
| $database, | ||
| name: $array['name'], | ||
| id: $array['id'], | ||
|
|
@@ -46,5 +49,31 @@ public static function fromArray(array $array): self | |
| updatedAt: $array['updatedAt'] ?? '', | ||
| enabled: $array['enabled'] ?? true, | ||
| ); | ||
|
|
||
| $collection->setDimension($array['dimension'] ?? null); | ||
|
|
||
| return $collection; | ||
| } | ||
|
|
||
| public function getDimension(): ?int | ||
| { | ||
| return $this->dimension; | ||
| } | ||
|
|
||
| public function setDimension(?int $dimension): self | ||
| { | ||
| $this->dimension = $dimension; | ||
|
|
||
| return $this; | ||
| } | ||
|
|
||
| /** | ||
| * @return array<string, mixed> | ||
| */ | ||
| public function jsonSerialize(): array | ||
| { | ||
| return array_merge(parent::jsonSerialize(), [ | ||
| 'dimension' => $this->dimension, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Knowledge Base Used: Prompt To Fix With AIThis is a comment left during a code review.
Path: src/Migration/Resources/Database/Collection.php
Line: 76
Comment:
**Null Dimension Changes Archives**
`Collection::jsonSerialize()` now writes `dimension: null` for every collection that does not set a dimension, including non-vectors collections and older archive data. Any strict archive reader or downstream schema that only accepts the previous collection shape can reject otherwise valid non-vectors collection exports because the field is present instead of omitted.
**Knowledge Base Used:**
- [Resource Model Classes](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/utopia-php/migration/-/docs/resources.md)
- [Migration Sources](https://app.greptile.com/appwrite/-/custom-context/knowledge-base/utopia-php/migration/-/docs/sources.md)
How can I resolve this? If you propose a fix, please make it concise.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed: |
||
| ]); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| <?php | ||
|
|
||
| namespace Utopia\Tests\Unit\Resources; | ||
|
|
||
| use PHPUnit\Framework\TestCase; | ||
| use Utopia\Migration\Resource; | ||
| use Utopia\Migration\Resources\Database\Collection; | ||
| use Utopia\Migration\Resources\Database\VectorsDB; | ||
|
|
||
| class CollectionTest extends TestCase | ||
| { | ||
| private const DATABASE = [ | ||
| 'id' => 'vectors', | ||
| 'name' => 'Vectors', | ||
| 'type' => Resource::TYPE_DATABASE_VECTORSDB, | ||
| ]; | ||
|
|
||
| public function testDimensionRoundTrip(): void | ||
| { | ||
| $collection = Collection::fromArray([ | ||
| 'database' => self::DATABASE, | ||
| 'id' => 'embeddings-store', | ||
| 'name' => 'Embeddings Store', | ||
| 'rowSecurity' => true, | ||
| 'permissions' => [], | ||
| 'createdAt' => '2026-01-01T00:00:00.000+00:00', | ||
| 'updatedAt' => '2026-01-01T00:00:00.000+00:00', | ||
| 'enabled' => true, | ||
| 'dimension' => 1536, | ||
| ]); | ||
|
|
||
| $this->assertInstanceOf(VectorsDB::class, $collection->getDatabase()); | ||
| $this->assertSame(1536, $collection->getDimension()); | ||
|
|
||
| $serialized = $collection->jsonSerialize(); | ||
| $this->assertSame(1536, $serialized['dimension']); | ||
|
|
||
| $rehydrated = Collection::fromArray(\json_decode(\json_encode($collection), true)); | ||
| $this->assertSame(1536, $rehydrated->getDimension()); | ||
| } | ||
|
|
||
| public function testDimensionDefaultsToNull(): void | ||
| { | ||
| $collection = Collection::fromArray([ | ||
| 'database' => self::DATABASE, | ||
| 'id' => 'embeddings-store', | ||
| 'name' => 'Embeddings Store', | ||
| 'rowSecurity' => true, | ||
| 'permissions' => [], | ||
| 'createdAt' => '', | ||
| 'updatedAt' => '', | ||
| 'enabled' => true, | ||
| ]); | ||
|
|
||
| $this->assertNull($collection->getDimension()); | ||
| $this->assertNull($collection->jsonSerialize()['dimension']); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a vectorsdb collection has more than one vector attribute, this sync runs for each one and writes the collection-level
dimensionfrom the current attribute size. A later non-embeddingsvector field with a different size can overwrite the restored collection metadata, so new inserts or collection operations validate against the wrong dimension.Knowledge Base Used:
Prompt To Fix With AI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed:
syncVectorDimensionnow only writes when the collection'sdimensionis still the placeholder (0), so it fills in the value for pre-dimension archives but never overwrites an archived dimension — a second vector column import is a no-op.