- Database library: createCollection() accepts metadata parameter
for arbitrary key-value pairs on the _metadata document
- Appwrite: passes externalId (user-facing collection ID) when
creating collections via createCollection(metadata: ['externalId' => $collectionId])
- Metadata decorator: reads $collection->getAttribute('externalId')
directly from the collection metadata — zero queries, zero caches,
zero overhead
- getDatabasesDB: removed dbForProject dependency and all mapping logic
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The findOne by $sequence query fails validation because $sequence is an
internal id-type attribute. Instead, load ALL collections for the
database once on first relationship encounter and cache statically per
database per Swoole worker. No per-attribute queries needed.
Also fixes UUID sequence extraction — the previous explode('_') split
UUIDs incorrectly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The UserEvents hook copied event state at resource-resolution time
(before the init hook set the user), causing webhooks to receive null
user IDs. Now stores the source queueForEvents as a reference and
copies at fire-time when the user Document has been populated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The findOne query per relationship attribute ran on every getDatabasesDB
call. Static cache keyed by database+internal name caches results across
requests within the same Swoole worker process.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Related collection lookup used internal name as document ID, but
Appwrite collections have user-facing IDs. Extract sequence from
internal name and use findOne by $sequence instead.
- Increase all schema polling timeouts from 240s to 360s for CI
dedicated mode parallel load.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- getDatabasesDB now registers mappings for related collections from
relationship attributes, not just the primary collection. This fixes
testOneToOneRelationship where nested documents showed internal names.
- Update utopia-php/migration to handle Index objects in createCollection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Endpoints pass the collection document they already have to
getDatabasesDB. The factory registers the single collection mapping
on the Metadata decorator — no bulk find queries, no static cache,
no dbForProject dependency.
The decorator is now purely stateless with zero database overhead.
Collection ID resolution uses only the pre-registered mapping from
the endpoint's request parameters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The decorator no longer queries dbForProject directly. Instead,
getDatabasesDB pre-populates the mapping via setCollectionId() and
uses a static cache (Metadata::getCachedMap) so the query runs at most
ONCE per database per Swoole worker process. The decorator is now
stateless — no database dependencies, just a pre-set map.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove processDocument() and all its calls — the decorator approach is
the intended design. The Metadata decorator lazily loads the collection
ID mapping from dbForProject on first use, wrapped in silent() to
prevent lifecycle hooks. Maps both relative (collection_N) and full
(database_M_collection_N) keys to user-facing IDs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Metadata decorator required a collection ID mapping query that added
overhead and caused Redis OOM in CI. Instead, stamp $databaseId and
$collectionId/$tableId directly in endpoint actions where user-facing
IDs are available from request parameters — matching the 1.9.x approach.
- Remove Metadata decorator from getDatabasesDB hooks
- Restore processDocument() on Documents/Action base class
- Add processDocument() calls in Get, Create, XList, Update, Upsert
- Simplify Metadata.php to stateless map-only decorator (no queries)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the collection ID mapping query from the Metadata decorator to
getDatabasesDB where it runs once during resource init. The mapping
includes both relative keys (collection_N) and full keys
(database_M_collection_N) for dedicated mode compatibility.
The Metadata decorator is now purely stateless — no database queries,
no dbForProject dependency. It only uses the pre-set map from
setCollectionId().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move collection ID mapping query from getDatabasesDB init to lazy
loading inside the Metadata decorator. The query is wrapped in
silent() and skipValidation() to prevent triggering lifecycle hooks
(Usage, Events) that were contributing to Redis OOM in CI.
The mapping is loaded once on first need, not during resource init,
reducing overhead for requests that don't access document endpoints.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The collection ID mapping query needs dbForProject which was missing
from the getDatabasesDB resource's dependency injection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the collection mapping query from inside the Metadata decorator to
the getDatabasesDB resource factory. This avoids decorator-level
database queries that can fail in various contexts and cause cascading
issues.
The mapping is loaded once when getDatabasesDB creates the database
instance, and the results are passed to the Metadata decorator via
setCollectionId(). The decorator itself is now stateless with respect
to database queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Metadata decorator now skips _metadata collection documents to prevent
injected $databaseId/$collectionId attributes from leaking into SQL
UPDATE statements via getAttributes()
- Add Tenancy hook to dbForProject in shared mode (was missing, causing
401 on session verification)
- Update Collection/Table response models to use $databaseId with $
prefix matching the decorator
- Update utopia-php/database with MongoDB tenant null filter fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Since setDocumentType('users', User::class) is registered on all
database instances, getDocument('users', ...) already returns User
instances. The new User($doc->getArrayCopy()) pattern was redundant
and could lose internal state managed by the database layer.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
The user resource and realtime handlers return Document objects from
getDocument(), but isPrivileged()/isApp() are now instance methods on
the User class. Wrapping results with new User() ensures the correct
type is returned for all code paths.
https://claude.ai/code/session_01JLPDurUgyj7qViA8JqQFTH
The team resource query was changed from $internalId to $sequence,
breaking console session authentication (401 on project creation).
Also removed duplicate utopia-php/servers entry in composer.json
and updated composer.lock hash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document::getTenant() casts numeric tenants to (int), but
adapter->getTenant() held a string from getSequence(). The strict
!== comparison in Database::getCollection() then failed, returning
"Collection not found" for all shared-table MariaDB projects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The $tenant attribute type in the database library is being changed from
VAR_INTEGER to VAR_ID, which handles both SQL (integer) and MongoDB
(UUID7 string) adapters natively. This removes the now-unnecessary
conditional casting pattern throughout the codebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Introduced a new API endpoint to update user impersonator capability.
- Enhanced user model to include impersonator attributes.
- Updated database schema to support impersonation.
- Implemented impersonation logic in the request handling to allow users with impersonator capability to act as other users.
- Added relevant API documentation for impersonation headers.
This feature allows users with the appropriate permissions to impersonate other users, enhancing flexibility in user management.
- Moved the `setSupportForAttributes` method call from the adapter initialization to the database resource creation in `getDatabasesDB`.
- Updated the logic to ensure attribute support is set correctly based on the database type.
- Updated embedding agent timeout to be configurable via environment variable.
- Removed commented code in XList for clarity.
- Refactored database cleaning logic into separate methods for better readability and maintainability.
* Added new exception `MIGRATION_DATABASE_TYPE_UNSUPPORTED` with proper error metadata and HTTP 400 response.
* Replaced generic CSV database type errors with the new migration-specific exception for clearer error handling.
* Added support for `DOCUMENTSDB` in migration transfer resource service mapping.
* Fixed Appwrite report initialization by correctly injecting `getDatabasesDB`.
* Updated database adapter initialization to conditionally disable attribute support for `DOCUMENTSDB`.
* Moved `setSupportForAttributes` logic from pool initialization to database resource creation.
* Removed duplicate `getDatabasesDB` resource definition and redundant database event listener setup.
* Cleaned up unused variables and minor code inconsistencies.
* Fixed docblock formatting in `TransactionState`.
* Adjusted metrics handling in VectorDB embeddings text creation (removed unnecessary trigger/reset flow).