Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7f856b4
Revert "Fix merge"
ArnabChatterjee20k Jan 19, 2026
c4be3db
Revert "Update lock"
ArnabChatterjee20k Jan 19, 2026
81c2d3b
Revert "Revert"
ArnabChatterjee20k Jan 19, 2026
0d0129f
linting
ArnabChatterjee20k Jan 19, 2026
97e0821
fixed double counting issue
ArnabChatterjee20k Jan 21, 2026
c963043
Merge remote-tracking branch 'origin/main' into multitype-db
ArnabChatterjee20k Jan 21, 2026
f6eadfc
updated index validator
ArnabChatterjee20k Jan 21, 2026
86ee0d5
Merge remote-tracking branch 'origin/main' into multitype-db
ArnabChatterjee20k Feb 9, 2026
b3fcc08
addressed pr comments
ArnabChatterjee20k Feb 10, 2026
fe91feb
updated composer json and lock
ArnabChatterjee20k Feb 13, 2026
334f4a8
Merge remote-tracking branch 'origin/main' into multitype-db
ArnabChatterjee20k Feb 13, 2026
9e4b945
removed redundant attribute addition making the column as the single …
ArnabChatterjee20k Feb 18, 2026
98c44a1
improved createField
ArnabChatterjee20k Feb 18, 2026
8f0d54e
Merge remote-tracking branch 'origin/main' into improve-columns-setup
ArnabChatterjee20k Feb 18, 2026
e4872c1
linting
ArnabChatterjee20k Feb 18, 2026
8431f1f
removed generic attribute and using Attribute as the base
ArnabChatterjee20k Feb 24, 2026
280fe7a
Merge pull request #150 from utopia-php/improve-columns-setup
abnegate Feb 24, 2026
682cdc3
Refactor Appwrite migration to remove unused getDatabaseDSN callable …
ArnabChatterjee20k Feb 24, 2026
237513f
Merge pull request #151 from utopia-php/remove-dsn-callables
abnegate Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Migration/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function resolveResourceCacheKey(Resource $resource): string
case Resource::TYPE_TABLE:
case Resource::TYPE_COLLECTION:
/** @var Table $resource */
$keys[] = $resource->getDatabase()->getType();
$keys[] = $resource->getDatabase()->getSequence();
break;

Expand Down
386 changes: 218 additions & 168 deletions src/Migration/Destinations/Appwrite.php

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions src/Migration/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ abstract class Resource implements \JsonSerializable

public const TYPE_DATABASE = 'database';

public const TYPE_DATABASE_LEGACY = 'legacy';

public const TYPE_DATABASE_TABLESDB = 'tablesdb';

public const TYPE_DATABASE_DOCUMENTSDB = 'documentsdb';
public const TYPE_DATABASE_VECTORDB = 'vectordb';

public const TYPE_ROW = 'row';

public const TYPE_FILE = 'file';
Expand Down Expand Up @@ -76,6 +83,8 @@ abstract class Resource implements \JsonSerializable
self::TYPE_BUCKET,
self::TYPE_TABLE,
self::TYPE_DATABASE,
self::TYPE_DATABASE_VECTORDB,
self::TYPE_DATABASE_DOCUMENTSDB,
self::TYPE_ROW,
self::TYPE_FILE,
self::TYPE_FUNCTION,
Expand All @@ -96,6 +105,39 @@ abstract class Resource implements \JsonSerializable
self::TYPE_COLLECTION,
];

// index terminology is same for all
public const DATABASE_TYPE_RESOURCE_MAP = [
self::TYPE_DATABASE => [
'entity' => self::TYPE_TABLE,
'field' => self::TYPE_COLUMN,
'record' => self::TYPE_ROW,
],
self::TYPE_DATABASE_DOCUMENTSDB => [
'entity' => self::TYPE_COLLECTION,
// HACK: not required in documentsdb but adding it for consistency in the db reader(not gonna impact)
'field' => self::TYPE_ATTRIBUTE,
'record' => self::TYPE_DOCUMENT,
],
self::TYPE_DATABASE_VECTORDB => [
'entity' => self::TYPE_COLLECTION,
'field' => self::TYPE_ATTRIBUTE,
'record' => self::TYPE_DOCUMENT,
]
];

public const ENTITY_TYPE_RESOURCE_MAP = [
self::TYPE_TABLE => [
'field' => self::TYPE_COLUMN,
'record' => self::TYPE_ROW,
'index' => self::TYPE_INDEX
],
self::TYPE_COLLECTION => [
'field' => self::TYPE_ATTRIBUTE,
'record' => self::TYPE_DOCUMENT,
'index' => self::TYPE_INDEX
],
];

protected string $id = '';

protected string $originalId = '';
Expand Down
189 changes: 189 additions & 0 deletions src/Migration/Resources/Database/Attribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
<?php

namespace Utopia\Migration\Resources\Database;

use Utopia\Migration\Resource;
use Utopia\Migration\Transfer;

class Attribute extends Resource
{
public const TYPE_STRING = 'string';
public const TYPE_INTEGER = 'integer';
public const TYPE_FLOAT = 'double';
public const TYPE_BOOLEAN = 'boolean';
public const TYPE_DATETIME = 'datetime';
public const TYPE_EMAIL = 'email';
public const TYPE_ENUM = 'enum';
public const TYPE_IP = 'ip';
public const TYPE_URL = 'url';
public const TYPE_RELATIONSHIP = 'relationship';

public const TYPE_POINT = 'point';
public const TYPE_LINE = 'linestring';
public const TYPE_POLYGON = 'polygon';

public const TYPE_OBJECT = 'object';
public const TYPE_VECTOR = 'vector';

/**
* @param string $key
* @param Table $table
* @param string $fieldType The actual field type (e.g., 'string', 'integer', 'email')
* @param int $size
* @param bool $required
* @param mixed|null $default
* @param bool $array
* @param bool $signed
* @param string $format
* @param array<string, mixed> $formatOptions
* @param array<string> $filters
* @param array<string, mixed> $options
* @param string $createdAt
* @param string $updatedAt
*/
public function __construct(
protected readonly string $key,
protected readonly Table $table,
protected readonly string $fieldType = '',
protected readonly int $size = 0,
protected readonly bool $required = false,
protected readonly mixed $default = null,
protected readonly bool $array = false,
protected readonly bool $signed = false,
protected readonly string $format = '',
protected readonly array $formatOptions = [],
protected readonly array $filters = [],
protected array $options = [],
protected string $createdAt = '',
protected string $updatedAt = '',
) {
}

/**
* @return array<string, mixed>
*/
public function jsonSerialize(): array
{
return [
'key' => $this->key,
'table' => $this->table,
'type' => $this->getType(),
'size' => $this->size,
'required' => $this->required,
'default' => $this->default,
'array' => $this->array,
'signed' => $this->signed,
'format' => $this->format,
'formatOptions' => $this->formatOptions,
'filters' => $this->filters,
'options' => $this->options,
'createdAt' => $this->createdAt,
'updatedAt' => $this->updatedAt,
];
}

public static function getName(): string
{
return Resource::TYPE_ATTRIBUTE;
}

public function getType(): string
{
return $this->fieldType;
}

/**
* Convert a Column resource to an Attribute resource.
*
* @param Column $column
* @return self
*/
public static function fromColumn(Column $column): self
{
return new self(
$column->getKey(),
$column->getTable(),
$column->getType(),
$column->getSize(),
$column->isRequired(),
$column->getDefault(),
$column->isArray(),
$column->isSigned(),
$column->getFormat(),
$column->getFormatOptions(),
$column->getFilters(),
$column->getOptions(),
$column->getCreatedAt(),
$column->getUpdatedAt()
);
}

public function getGroup(): string
{
return Transfer::GROUP_DATABASES;
}

public function getKey(): string
{
return $this->key;
}

public function getTable(): Table
{
return $this->table;
}

public function getSize(): int
{
return $this->size;
}

public function isRequired(): bool
{
return $this->required;
}

public function getDefault(): mixed
{
return $this->default;
}

public function isArray(): bool
{
return $this->array;
}

public function isSigned(): bool
{
return $this->signed;
}

public function getFormat(): string
{
return $this->format;
}

/**
* @return array<string, mixed>
*/
public function getFormatOptions(): array
{
return $this->formatOptions;
}

/**
* @return array<string>
*/
public function getFilters(): array
{
return $this->filters;
}

/**
* @return array<string, mixed>
*/
public function &getOptions(): array
{
return $this->options;
}
}
50 changes: 50 additions & 0 deletions src/Migration/Resources/Database/Collection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Utopia\Migration\Resources\Database;

use Utopia\Migration\Resource;

class Collection extends Table
{
public static function getName(): string
{
return Resource::TYPE_COLLECTION;
}

/**
* @param array{
* database: array{
* id: string,
* name: string,
* type: string
* },
* name: string,
* id: string,
* documentSecurity?: bool,
* rowSecurity?: bool,
* permissions: ?array<string>,
* createdAt: string,
* updatedAt: string,
* enabled: bool
* } $array
*/
public static function fromArray(array $array): self
{
$database = match ($array['database']['type']) {
Resource::TYPE_DATABASE_DOCUMENTSDB => DocumentsDB::fromArray($array['database']),
Resource::TYPE_DATABASE_VECTORDB => VectorDB::fromArray($array['database']),
default => Database::fromArray($array['database'])
};

return new self(
$database,
name: $array['name'],
id: $array['id'],
rowSecurity: $array['rowSecurity'] ?? $array['documentSecurity'],
permissions: $array['permissions'] ?? [],
createdAt: $array['createdAt'] ?? '',
updatedAt: $array['updatedAt'] ?? '',
enabled: $array['enabled'] ?? true,
);
}
}
15 changes: 15 additions & 0 deletions src/Migration/Resources/Database/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ abstract class Column extends Resource
public const TYPE_LINE = 'linestring';
public const TYPE_POLYGON = 'polygon';

public const TYPE_OBJECT = 'object';
public const TYPE_VECTOR = 'vector';

/**
* @param string $key
* @param Table $table
Expand Down Expand Up @@ -157,4 +160,16 @@ public function &getOptions(): array
{
return $this->options;
}

/**
* Convert this Column resource to an Attribute resource.
* This provides a deterministic way to derive attributes from columns,
* eliminating the need to maintain duplicate per-type Attribute implementations.
*
* @return Attribute
*/
public function getAttribute(): Attribute
{
return Attribute::fromColumn($this);
}
}
Loading