diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000..9349b002
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,26 @@
+DESTINATION_APPWRITE_TEST_PROJECT=testProject
+DESTINATION_APPWRITE_TEST_ENDPOINT=http://localhost/v1
+DESTINATION_APPWRITE_TEST_KEY=xxxxxxxxxxxxxxxxxx
+
+SOURCE_APPWRITE_TEST_PROJECT=testProject
+SOURCE_APPWRITE_TEST_ENDPOINT=http://localhost/v1
+SOURCE_APPWRITE_TEST_KEY=xxxxxxxxxxxxxxxxxx
+
+FIREBASE_TEST_PROJECT=testProject
+FIREBASE_TEST_ACCOUNT='{type: "service_account", ...}'
+
+SUPABASE_TEST_ENDPOINT=https://xxxxxxxxxxxx.supabase.co
+SUPABASE_TEST_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+SUPABASE_TEST_HOST=db.xxxxxxxxxxxxxxxx.supabase.co
+SUPABASE_TEST_DATABASE=postgres
+SUPABASE_TEST_USERNAME=postgres
+SUPABASE_TEST_PASSWORD=xxxxxxxxxxxxxxxxxxxxx
+
+NHOST_TEST_SUBDOMAIN=xxxxxxxxxxx
+NHOST_TEST_REGION=eu-central-1
+NHOST_TEST_SECRET=xxxxxxxxxxxxxxxxx
+NHOST_TEST_DATABASE=xxxxxxxxxxxxxxx
+NHOST_TEST_USERNAME=postgres
+NHOST_TEST_PASSWORD=xxxxxxxxxxxxxxx
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..9c0bf128
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+composer.lock
+/vendor/
+/.idea/
+*.cache
+.env
+test-service-account.json
+.DS_Store
+localBackup/
+.vscode/
+.env.prod
\ No newline at end of file
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..adc8fece
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,76 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to make participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, sex characteristics, gender identity, expression,
+level of experience, education, socio-economic status, nationality, personal
+appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or
+ advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at team@appwrite.io. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..173bd98e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,33 @@
+FROM postgres:alpine3.18 as supabase-db
+COPY ./tests/Transfer/resources/supabase/backup.tar /docker-entrypoint-initdb.d/backup.tar
+COPY ./tests/Transfer/resources/restore.sh /docker-entrypoint-initdb.d/restore.sh
+
+FROM postgres:alpine3.18 as nhost-db
+COPY ./tests/Transfer/resources/nhost/backup.tar /docker-entrypoint-initdb.d/backup.tar
+COPY ./tests/Transfer/resources/restore.sh /docker-entrypoint-initdb.d/restore.sh
+
+# Use my fork of mockoon while waiting for range headers to be merged
+FROM node:14-alpine3.14 as mock-api
+WORKDIR /app
+RUN git clone https://github.com/PineappleIOnic/mockoon.git .
+RUN npm run bootstrap
+RUN npm run build:libs
+RUN npm run build:cli
+RUN mv ./packages/cli/dist/run /usr/local/bin/mockoon
+
+FROM composer:2.0 as composer
+
+WORKDIR /usr/local/src/
+
+COPY composer.lock /usr/local/src/
+COPY composer.json /usr/local/src/
+
+RUN composer install --ignore-platform-reqs
+
+FROM php:8.0-fpm-alpine3.14 as tests
+RUN set -ex && apk --no-cache add postgresql-dev
+RUN docker-php-ext-install pdo pdo_pgsql
+COPY ./src /usr/local/src
+COPY ./tests /usr/local/src/tests
+COPY --from=composer /usr/local/src/vendor /usr/local/src/vendor
+CMD php ./vendor/bin/phpunit
\ No newline at end of file
diff --git a/README.md b/README.md
index d35d021e..b8ed83b3 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,74 @@
-# transfer
\ No newline at end of file
+# Utopia Transfer
+
+[](https://travis-ci.com/utopia-php/transfer)
+
+[](https://appwrite.io/discord)
+
+Utopia Transfer is a simple and lite library to transfer and transform resources inbetween services. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io).
+
+Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project it is dependency free and can be used as standalone with any other PHP project or framework.
+
+## Getting Started
+
+Install using composer:
+```bash
+composer require utopia-php/transfer
+```
+
+Init in your application:
+```php
+run(
+ [
+ Transfer::GROUP_AUTH
+ ], function ($status) {
+ echo $status['message'] . PHP_EOL;
+ }
+);
+```
+
+## Supported Resources Chart
+
+Sources:
+| | Auth | Databases | Storage | Functions | Settings |
+|----------|-------|-----------|-------|-----------|-----------|
+| Appwrite | ✅ | ✅ | ✅ | ✅ | |
+| Supabase | ✅ | ✅ | ✅ | | |
+| NHost | ✅ | ✅ | ✅ | | |
+| Firebase | ✅ | ✅ | ✅ | | |
+
+Destinations:
+| | Auth | Databases | Storage | Functions | Settings |
+|----------|-------|-----------|-------|-----------|-----------|
+| Appwrite | ✅ | ✅ | ✅ | ✅ | |
+| Local | ✅ | ✅ | ✅ | ✅ | ✅ |
+
+> **Warning**
+> The Local destination should be used for testing purposes only. It is not recommended to use this destination in production or as a backup. The local destination is there to confirm that a source is working correctly and to test the transfer process with needing a target destination instance. This may change in the future however as the library matures.
+
+
+
+## System Requirements
+
+Utopia Transfer requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible.
+
+## Copyright and license
+
+The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php)
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..72a150f1
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "utopia-php/transfer",
+ "description": "A simple library to transfer resources between services.",
+ "type": "library",
+ "keywords": ["php", "framework", "upf", "utopia", "transfer"],
+ "license": "MIT",
+ "minimum-stability": "stable",
+ "authors": [{
+ "name": "Eldad Fux",
+ "email": "eldad@appwrite.io"
+ },
+ {
+ "name": "Bradley Schofield",
+ "email": "bradley@appwrite.io"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Transfer\\": "src/Transfer"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {"Utopia\\Tests\\": "tests/Transfer"}
+ },
+ "require": {
+ "php": ">=8.0",
+ "utopia-php/cli": "^0.13.0",
+ "appwrite/appwrite": "^8.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3",
+ "vlucas/phpdotenv": "^5.5",
+ "laravel/pint": "^1.10"
+ }
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..1dbd99ac
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,47 @@
+version: '3'
+
+services:
+ supabase-db:
+ build:
+ context: .
+ target: supabase-db
+ ports:
+ - "5432:5432"
+ networks:
+ - tests
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+
+ nhost-db:
+ build:
+ context: .
+ target: nhost-db
+ networks:
+ - tests
+ ports:
+ - "5433:5432"
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: postgres
+
+ tests:
+ build:
+ context: .
+ target: tests
+ networks:
+ - tests
+ volumes:
+ - ./:/app
+ working_dir: /app
+ depends_on:
+ - supabase-db
+ - nhost-db
+ environment:
+ - NHOST_DB_URL=postgres://postgres:postgres@nhost-db:5432/postgres
+ - SUPABASE_DB_URL=postgres://postgres:postgres@supabase-db:5432/postgres
+
+networks:
+ tests:
\ No newline at end of file
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 00000000..89c508c5
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,15 @@
+
+
+
+ ./src
+ ./tests
+
+
+
+ *
+
+
+
+ *
+
+
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 00000000..b4ec372f
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,16 @@
+
+
+
+ ./tests/Transfer/E2E
+
+
+
\ No newline at end of file
diff --git a/playground.php b/playground.php
new file mode 100644
index 00000000..1576e617
--- /dev/null
+++ b/playground.php
@@ -0,0 +1,149 @@
+load();
+
+cleanupAppwrite();
+
+/**
+ * Initialise All Source Adapters
+ */
+// $sourceAppwrite = new Appwrite(
+// $_ENV['SOURCE_APPWRITE_TEST_PROJECT'],
+// $_ENV['SOURCE_APPWRITE_TEST_ENDPOINT'],
+// $_ENV['SOURCE_APPWRITE_TEST_KEY']
+// );
+
+$firebase = json_decode($_ENV['FIREBASE_TEST_ACCOUNT'], true);
+
+$sourceFirebase = new Firebase(
+ $firebase,
+ $firebase['project_id'] ?? '',
+);
+
+// $sourceNHost = new NHost(
+// $_ENV['NHOST_TEST_SUBDOMAIN'] ?? '',
+// $_ENV['NHOST_TEST_REGION'] ?? '',
+// $_ENV['NHOST_TEST_SECRET'] ?? '',
+// $_ENV['NHOST_TEST_DATABASE'] ?? '',
+// $_ENV['NHOST_TEST_USERNAME'] ?? '',
+// $_ENV['NHOST_TEST_PASSWORD'] ?? '',
+// );
+
+$sourceSupabase = new Supabase(
+ $_ENV['SUPABASE_TEST_ENDPOINT'] ?? '',
+ $_ENV['SUPABASE_TEST_KEY'] ?? '',
+ $_ENV['SUPABASE_TEST_HOST'] ?? '',
+ $_ENV['SUPABASE_TEST_DATABASE'] ?? '',
+ $_ENV['SUPABASE_TEST_USERNAME'] ?? '',
+ $_ENV['SUPABASE_TEST_PASSWORD'] ?? '',
+);
+
+/**
+ * Initialise All Destination Adapters
+ */
+// $destinationAppwrite = new AppwriteDestination(
+// $_ENV['DESTINATION_APPWRITE_TEST_PROJECT'],
+// $_ENV['DESTINATION_APPWRITE_TEST_ENDPOINT'],
+// $_ENV['DESTINATION_APPWRITE_TEST_KEY']
+// );
+
+$destinationLocal = new Local(__DIR__ . '/localBackup/');
+
+/**
+ * Initialise Transfer Class
+ */
+$transfer = new Transfer(
+ $sourceFirebase,
+ $destinationLocal
+);
+
+/**
+ * Run Transfer
+ */
+$transfer->run(
+ Supabase::getSupportedResources(),
+ function (array $resources) {
+ }
+);
+
+function cleanupAppwrite()
+{
+ $client = new \Appwrite\Client();
+
+ $client
+ ->setEndpoint($_ENV['DESTINATION_APPWRITE_TEST_ENDPOINT'])
+ ->setProject($_ENV['DESTINATION_APPWRITE_TEST_PROJECT'])
+ ->setKey($_ENV['DESTINATION_APPWRITE_TEST_KEY']);
+
+ $databaseService = new \Appwrite\Services\Databases($client);
+ $listDatabases = $databaseService->list();
+ foreach ($listDatabases['databases'] as $database) {
+ $databaseId = $database['$id'];
+ $listCollections = $databaseService->listCollections($databaseId);
+ foreach ($listCollections['collections'] as $collection) {
+ $collectionId = $collection['$id'];
+ $listDocuments = $databaseService->listDocuments($databaseId, $collectionId);
+ foreach ($listDocuments['documents'] as $document) {
+ $documentId = $document['$id'];
+ $databaseService->deleteDocument($databaseId, $collectionId, $documentId);
+ }
+ }
+
+ $databaseService->delete($databaseId);
+ }
+
+ $usersService = new \Appwrite\Services\Users($client);
+ $listUsers = $usersService->list();
+ if ($listUsers['total'] > count($listUsers['users'])) {
+ while ($listUsers['total'] > count($listUsers['users'])) {
+ $listUsers['users'] = array_merge($listUsers['users'], $usersService->list(
+ [Query::cursorAfter(
+ $listUsers['users'][count($listUsers['users']) - 1]['$id']
+ )]
+ )['users']);
+ }
+ }
+
+ foreach ($listUsers['users'] as $user) {
+ $userId = $user['$id'];
+ $usersService->delete($userId);
+ }
+
+ $teamsService = new \Appwrite\Services\Teams($client);
+ $listTeams = $teamsService->list();
+ foreach ($listTeams['teams'] as $team) {
+ $teamId = $team['$id'];
+ $teamsService->delete($teamId);
+ }
+
+ $storageService = new \Appwrite\Services\Storage($client);
+ $listBuckets = $storageService->listBuckets();
+ foreach ($listBuckets['buckets'] as $bucket) {
+ $bucketId = $bucket['$id'];
+ $listFiles = $storageService->listFiles($bucketId);
+ foreach ($listFiles['files'] as $file) {
+ $fileId = $file['$id'];
+ $storageService->deleteFile($bucketId, $fileId);
+ }
+ }
+}
+
+var_dump($transfer->getStatusCounters());
diff --git a/src/Transfer/Cache.php b/src/Transfer/Cache.php
new file mode 100644
index 00000000..f9de6895
--- /dev/null
+++ b/src/Transfer/Cache.php
@@ -0,0 +1,124 @@
+cache = [];
+ }
+
+ /**
+ * Add Resource
+ *
+ * Places the resource in the cache, in the cache backend this also gets assigned a unique ID.
+ *
+ * @param Resource $resource
+ * @return void
+ */
+ public function add($resource)
+ {
+ if (!$resource->getInternalId()) {
+ $resourceId = uniqid();
+ if (isset($this->cache[$resource->getName()][$resourceId])) {
+ $resourceId = uniqid();
+ }
+ $resource->setInternalId(uniqid());
+ }
+ $this->cache[$resource->getName()][$resource->getInternalId()] = $resource;
+ }
+
+ public function addAll(array $resources)
+ {
+ foreach ($resources as $resource) {
+ $this->add($resource);
+ }
+ }
+
+ /**
+ * Update Resource
+ *
+ * Updates the resource in the cache, if the resource does not exist in the cache an exception is thrown.
+ * Use Add to add a new resource to the cache.
+ *
+ * @param Resource $resource
+ * @return void
+ */
+ public function update($resource)
+ {
+ if (!in_array($resource, $this->cache[$resource->getName()])) {
+ throw new \Exception('Resource does not exist in cache');
+ }
+
+ $this->cache[$resource->getName()][$resource->getInternalId()] = $resource;
+ }
+
+ public function updateAll($resources)
+ {
+ foreach ($resources as $resource) {
+ $this->update($resource);
+ }
+ }
+
+ /**
+ * Remove Resource
+ *
+ * Removes the resource from the cache, if the resource does not exist in the cache an exception is thrown.
+ *
+ * @param Resource $resource
+ * @return void
+ */
+ public function remove($resource)
+ {
+ if (!in_array($resource, $this->cache[$resource->getName()])) {
+ throw new \Exception('Resource does not exist in cache');
+ }
+
+ unset($this->cache[$resource->getName()][$resource->getInternalId()]);
+ }
+
+ /**
+ * Get Resources
+ *
+ * @param string|resource $resourceType
+ * @return resource[]
+ */
+ public function get($resource)
+ {
+ if (is_string($resource)) {
+ return $this->cache[$resource] ?? [];
+ } else {
+ return $this->cache[$resource->getName()] ?? [];
+ }
+ }
+
+ /**
+ * Get All Resources
+ *
+ * @return array
+ */
+ public function getAll()
+ {
+ return $this->cache;
+ }
+
+ /**
+ * Wipe Cache
+ *
+ * Removes all resources from the cache.
+ *
+ * @return void
+ */
+ public function wipe()
+ {
+ $this->cache = [];
+ }
+}
diff --git a/src/Transfer/Destination.php b/src/Transfer/Destination.php
new file mode 100644
index 00000000..dc0bc156
--- /dev/null
+++ b/src/Transfer/Destination.php
@@ -0,0 +1,46 @@
+source;
+ }
+
+ /**
+ * Set Soruce
+ */
+ public function setSource(Source $source): self
+ {
+ $this->source = $source;
+
+ return $this;
+ }
+
+ /**
+ * Transfer Resources to Destination from Source callback
+ */
+ public function run(array $resources, callable $callback): void
+ {
+ $this->source->run($resources, function (array $resources) use ($callback) {
+ $this->import($resources, $callback);
+ });
+ }
+
+ /**
+ * Import Resources
+ *
+ * @param callable $callback (array $resources)
+ */
+ abstract protected function import(array $resources, callable $callback): void;
+}
diff --git a/src/Transfer/Destinations/Appwrite.php b/src/Transfer/Destinations/Appwrite.php
new file mode 100644
index 00000000..ccbdcef2
--- /dev/null
+++ b/src/Transfer/Destinations/Appwrite.php
@@ -0,0 +1,707 @@
+project = $project;
+ $this->endpoint = $endpoint;
+ $this->key = $key;
+
+ $this->client = (new Client())
+ ->setEndpoint($endpoint)
+ ->setProject($project)
+ ->setKey($key);
+ }
+
+ /**
+ * Get Name
+ */
+ public static function getName(): string
+ {
+ return 'Appwrite';
+ }
+
+ /**
+ * Get Supported Resources
+ */
+ static function getSupportedResources(): array
+ {
+ return [
+ // Auth
+ Resource::TYPE_USER,
+ Resource::TYPE_TEAM,
+ Resource::TYPE_MEMBERSHIP,
+
+ // Database
+ Resource::TYPE_DATABASE,
+ Resource::TYPE_COLLECTION,
+ Resource::TYPE_ATTRIBUTE,
+ Resource::TYPE_INDEX,
+ Resource::TYPE_DOCUMENT,
+
+ // Storage
+ Resource::TYPE_BUCKET,
+ Resource::TYPE_FILE,
+
+ // Functions
+ Resource::TYPE_FUNCTION,
+ Resource::TYPE_DEPLOYMENT,
+ Resource::TYPE_ENVVAR,
+
+ // Settings
+ ];
+ }
+
+ public function report(array $resources = []): array
+ {
+ if (empty($resources)) {
+ $resources = $this->getSupportedResources();
+ }
+
+ $databases = new Databases($this->client);
+ $functions = new Functions($this->client);
+ $storage = new Storage($this->client);
+ $teams = new Teams($this->client);
+ $users = new Users($this->client);
+
+ $currentPermission = '';
+ // Most of these API calls are purposely wrong. Appwrite will throw a 403 before a 400.
+ // We want to make sure the API key has full read and write access to the project.
+
+ try {
+ // Auth
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $currentPermission = 'users.read';
+ $users->list();
+
+ $currentPermission = 'users.write';
+ $users->create('', '', '');
+ }
+
+ if (in_array(Resource::TYPE_TEAM, $resources)) {
+ $currentPermission = 'teams.read';
+ $teams->list();
+
+ $currentPermission = 'teams.write';
+ $teams->create('', '');
+ }
+
+ if (in_array(Resource::TYPE_MEMBERSHIP, $resources)) {
+ $currentPermission = 'memberships.read';
+ $teams->listMemberships('');
+
+ $currentPermission = 'memberships.write';
+ $teams->createMembership('', [], '');
+ }
+
+ // Database
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $currentPermission = 'database.read';
+ $databases->list();
+
+ $currentPermission = 'database.write';
+ $databases->create('', '');
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $currentPermission = 'collections.read';
+ $databases->listCollections('');
+
+ $currentPermission = 'collections.write';
+ $databases->createCollection('', '', '');
+ }
+
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $currentPermission = 'attributes.read';
+ $databases->listAttributes('', '');
+
+ $currentPermission = 'attributes.write';
+ $databases->createStringAttribute('', '', '', 0, false);
+ }
+
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $currentPermission = 'indexes.read';
+ $databases->listIndexes('', '');
+
+ $currentPermission = 'indexes.write';
+ $databases->createIndex('', '', '', '', []);
+ }
+
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $currentPermission = 'documents.read';
+ $databases->listDocuments('', '');
+
+ $currentPermission = 'documents.write';
+ $databases->createDocument('', '', '', []);
+ }
+
+ // Storage
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $currentPermission = 'storage.read';
+ $storage->listBuckets();
+
+ $currentPermission = 'storage.write';
+ $storage->createBucket('', '');
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $currentPermission = 'files.read';
+ $storage->listFiles('');
+
+ $currentPermission = 'files.write';
+ $storage->createFile('', '', new InputFile());
+ }
+
+ // Functions
+ if (in_array(Resource::TYPE_FUNCTION, $resources)) {
+ $currentPermission = 'functions.read';
+ $functions->list();
+
+ $currentPermission = 'functions.write';
+ $functions->create('', '', '');
+ }
+
+ return [];
+ } catch (\Exception $exception) {
+ if ($exception->getCode() === 403) {
+ throw new \Exception('Missing permission: '.$currentPermission);
+ } else {
+ throw $exception;
+ }
+ }
+ }
+
+ protected function import(array $resources, callable $callback): void
+ {
+ foreach ($resources as $resource) {
+ /** @var Resource $resource */
+ switch ($resource->getGroup()) {
+ case Transfer::GROUP_DATABASES:
+ $responseResource = $this->importDatabaseResource($resource);
+ break;
+ case Transfer::GROUP_STORAGE:
+ $responseResource = $this->importFileResource($resource);
+ break;
+ case Transfer::GROUP_AUTH:
+ $responseResource = $this->importAuthResource($resource);
+ break;
+ case Transfer::GROUP_FUNCTIONS:
+ $responseResource = $this->importFunctionResource($resource);
+ break;
+ }
+
+ $this->cache->update($responseResource);
+ }
+
+ $callback($resources);
+ }
+
+ public function importDatabaseResource(Resource $resource): Resource
+ {
+ $databaseService = new Databases($this->client);
+
+ $response = null;
+ $resource->setStatus(Resource::STATUS_PROCESSING);
+
+ try {
+ switch ($resource->getName()) {
+ case Resource::TYPE_DATABASE:
+ /** @var Database $resource */
+ $response = $databaseService->create($resource->getId(), $resource->getDBName());
+ break;
+ case Resource::TYPE_COLLECTION:
+ /** @var Collection $resource */
+ $response = $newCollection = $databaseService->createCollection(
+ $resource->getDatabase()->getId(),
+ $resource->getId(),
+ $resource->getCollectionName(),
+ $resource->getPermissions(),
+ $resource->getDocumentSecurity()
+ );
+ $resource->setId($newCollection['$id']);
+ break;
+ case Resource::TYPE_INDEX:
+ /** @var Index $resource */
+ $response = $databaseService->createIndex(
+ $resource->getCollection()->getDatabase()->getId(),
+ $resource->getCollection()->getId(),
+ $resource->getKey(),
+ $resource->getType(),
+ $resource->getAttributes(),
+ $resource->getOrders()
+ );
+ break;
+ case Resource::TYPE_ATTRIBUTE:
+ /** @var Attribute $resource */
+ $this->createAttribute($resource);
+ break;
+ case Resource::TYPE_DOCUMENT:
+ /** @var Document $resource */
+ $databaseService->createDocument(
+ $resource->getDatabase()->getId(),
+ $resource->getCollection()->getId(),
+ $resource->getId(),
+ $resource->getData(),
+ $resource->getPermissions()
+ );
+ break;
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+ } catch (\Exception $e) {
+ $resource->setStatus(Resource::STATUS_ERROR, $e->getMessage());
+ } finally {
+ return $resource;
+ }
+ }
+
+ public function createAttribute(Attribute $attribute): void
+ {
+ $databaseService = new Databases($this->client);
+
+ switch ($attribute->getTypeName()) {
+ case Attribute::TYPE_STRING:
+ /** @var Text $attribute */
+ $databaseService->createStringAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getSize(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_INTEGER:
+ /** @var Integer $attribute */
+ $databaseService->createIntegerAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getMin(), $attribute->getMax() ?? null, $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_FLOAT:
+ /** @var Decimal $attribute */
+ $databaseService->createFloatAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), null, null, $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_BOOLEAN:
+ /** @var Boolean $attribute */
+ $databaseService->createBooleanAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_DATETIME:
+ /** @var DateTime $attribute */
+ $databaseService->createDatetimeAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_EMAIL:
+ /** @var Email $attribute */
+ $databaseService->createEmailAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_IP:
+ /** @var IP $attribute */
+ $databaseService->createIpAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_URL:
+ /** @var URLAttribute $attribute */
+ $databaseService->createUrlAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_ENUM:
+ /** @var Enum $attribute */
+ $databaseService->createEnumAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey(), $attribute->getElements(), $attribute->getRequired(), $attribute->getDefault(), $attribute->getArray());
+ break;
+ case Attribute::TYPE_RELATIONSHIP:
+ /** @var Relationship $attribute */
+ $databaseService->createRelationshipAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getRelatedCollection(), $attribute->getRelationType(), $attribute->getTwoWay(), $attribute->getKey(), $attribute->getTwoWayKey(), $attribute->getOnDelete());
+ break;
+ default:
+ throw new \Exception('Invalid attribute type');
+ }
+
+ // Wait for attribute to be created
+ $this->awaitAttributeCreation($attribute, 5);
+ }
+
+ /**
+ * Await Attribute Creation
+ */
+ public function awaitAttributeCreation(Attribute $attribute, int $timeout): bool
+ {
+ $databaseService = new Databases($this->client);
+
+ $start = \time();
+
+ while (\time() - $start < $timeout) {
+ $response = $databaseService->getAttribute($attribute->getCollection()->getDatabase()->getId(), $attribute->getCollection()->getId(), $attribute->getKey());
+
+ if ($response['status'] === 'available') {
+ return true;
+ }
+
+ \usleep(500000);
+ }
+
+ throw new \Exception('Attribute creation timeout');
+ }
+
+ public function importFileResource(Resource $resource): Resource
+ {
+ $storageService = new Storage($this->client);
+
+ $response = null;
+
+ try {
+ switch ($resource->getName()) {
+ case Resource::TYPE_FILE:
+ /** @var File $resource */
+ return $this->importFile($resource);
+ break;
+ case Resource::TYPE_BUCKET:
+ /** @var Bucket $resource */
+ $response = $storageService->createBucket(
+ $resource->getId(),
+ $resource->getBucketName(),
+ $resource->getPermissions(),
+ $resource->getFileSecurity(),
+ true, // Set to true for now, we'll come back later.
+ $resource->getMaxFileSize(),
+ $resource->getAllowedFileExtensions(),
+ $resource->getCompression(),
+ $resource->getEncryption(),
+ $resource->getAntiVirus()
+ );
+ $resource->setId($response['$id']);
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+ } catch (\Exception $e) {
+ $resource->setStatus(Resource::STATUS_ERROR, $e->getMessage());
+ } finally {
+ return $resource;
+ }
+ }
+
+ /**
+ * Import File Data
+ *
+ * @param File $file
+ *
+ * @returns File
+ */
+ public function importFile(File $file): File
+ {
+ $bucketId = $file->getBucket()->getId();
+
+ $response = null;
+
+ if ($file->getSize() <= Transfer::STORAGE_MAX_CHUNK_SIZE) {
+ $response = $this->client->call(
+ 'POST',
+ "/v1/storage/buckets/{$bucketId}/files",
+ [
+ 'content-type' => 'multipart/form-data',
+ ],
+ [
+ 'bucketId' => $bucketId,
+ 'fileId' => $file->getId(),
+ 'file' => new \CurlFile('data://'.$file->getMimeType().';base64,'.base64_encode($file->getData()), $file->getMimeType(), $file->getFileName()),
+ 'permissions' => $file->getPermissions(),
+ ]
+ );
+
+ $file->setStatus(Resource::STATUS_SUCCESS);
+
+ return $file;
+ }
+
+ $response = $this->client->call(
+ 'POST',
+ "/v1/storage/buckets/{$bucketId}/files",
+ [
+ 'content-type' => 'multipart/form-data',
+ 'content-range' => 'bytes '.($file->getStart()).'-'.($file->getEnd() == ($file->getSize() - 1) ? $file->getSize() : $file->getEnd()).'/'.$file->getSize(),
+ ],
+ [
+ 'bucketId' => $bucketId,
+ 'fileId' => $file->getId(),
+ 'file' => new \CurlFile('data://'.$file->getMimeType().';base64,'.base64_encode($file->getData()), $file->getMimeType(), $file->getFileName()),
+ 'permissions' => $file->getPermissions(),
+ ]
+ );
+
+ if ($file->getEnd() == ($file->getSize() - 1)) {
+ // Signatures for Encrypted files are invalid, so we skip the check
+ if ($file->getBucket()->getEncryption() == false || $file->getSize() > (20 * 1024 * 1024)) {
+ if ($response['signature'] !== $file->getSignature()) {
+ $file->setStatus(Resource::STATUS_WARNING, 'File signature mismatch, Possibly corrupted.');
+ }
+ }
+ }
+
+ return $file;
+ }
+
+ public function importAuthResource(Resource $resource): Resource
+ {
+ $userService = new Users($this->client);
+ $teamService = new Teams($this->client);
+
+ try {
+ switch ($resource->getName()) {
+ case Resource::TYPE_USER:
+ /** @var User $resource */
+ if (in_array(User::TYPE_EMAIL, $resource->getTypes())) {
+ $this->importPasswordUser($resource);
+ } else {
+ $userService->create($resource->getId(), $resource->getEmail(), $resource->getPhone(), null, $resource->getName());
+ }
+
+ if ($resource->getUsername()) {
+ $userService->updateName($resource->getId(), $resource->getUsername());
+ }
+
+ if ($resource->getPhone()) {
+ $userService->updatePhone($resource->getId(), $resource->getPhone());
+ }
+
+ if ($resource->getEmailVerified()) {
+ $userService->updateEmailVerification($resource->getId(), $resource->getEmailVerified());
+ }
+
+ if ($resource->getPhoneVerified()) {
+ $userService->updatePhoneVerification($resource->getId(), $resource->getPhoneVerified());
+ }
+
+ if ($resource->getDisabled()) {
+ $userService->updateStatus($resource->getId(), !$resource->getDisabled());
+ }
+
+ break;
+ case Resource::TYPE_TEAM:
+ /** @var Team $resource */
+ $teamService->create($resource->getId(), $resource->getName());
+ $teamService->updatePrefs($resource->getId(), $resource->getPrefs());
+ break;
+ case Resource::TYPE_MEMBERSHIP:
+ /** @var Membership $resource */
+ //TODO: Discuss in meeting.
+ // $teamService->createMembership($resource->getTeam()->getId(), $resource->getRoles(), )
+ // break;
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+ } catch (\Exception $e) {
+ $resource->setStatus(Resource::STATUS_ERROR, $e->getMessage());
+ } finally {
+ return $resource;
+ }
+ }
+
+ public function importPasswordUser(User $user): array|null
+ {
+ $auth = new Users($this->client);
+ $hash = $user->getPasswordHash();
+ $result = null;
+
+ if (empty($hash->getHash())) {
+ throw new \Exception('User password hash is empty');
+ }
+
+ switch ($hash->getAlgorithm()) {
+ case Hash::ALGORITHM_SCRYPT_MODIFIED:
+ $result = $auth->createScryptModifiedUser(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ $hash->getSalt(),
+ $hash->getSeparator(),
+ $hash->getSigningKey(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_BCRYPT:
+ $result = $auth->createBcryptUser(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_ARGON2:
+ $result = $auth->createArgon2User(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_SHA256:
+ $result = $auth->createShaUser(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ 'sha256',
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_PHPASS:
+ $result = $auth->createPHPassUser(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_SCRYPT:
+ $result = $auth->createScryptUser(
+ $user->getId(),
+ $user->getEmail(),
+ $hash->getHash(),
+ $hash->getSalt(),
+ $hash->getPasswordCpu(),
+ $hash->getPasswordMemory(),
+ $hash->getPasswordParallel(),
+ $hash->getPasswordLength(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ case Hash::ALGORITHM_PLAINTEXT:
+ $result = $auth->create(
+ $user->getId(),
+ $user->getEmail(),
+ $user->getPhone(),
+ $hash->getHash(),
+ empty($user->getUsername()) ? null : $user->getUsername()
+ );
+ break;
+ }
+
+ return $result;
+ }
+
+ public function importFunctionResource(Resource $resource): Resource
+ {
+ $functions = new Functions($this->client);
+
+ try {
+ switch ($resource->getName()) {
+ case Resource::TYPE_FUNCTION:
+ /** @var Func $resource */
+ $functions->create(
+ $resource->getId(),
+ $resource->getFunctionName(),
+ $resource->getRuntime(),
+ $resource->getExecute(),
+ $resource->getEvents(),
+ $resource->getSchedule(),
+ $resource->getTimeout(),
+ $resource->getEnabled()
+ );
+ break;
+ case Resource::TYPE_ENVVAR:
+ /** @var EnvVar $resource */
+ $functions->createVariable(
+ $resource->getFunc()->getId(),
+ $resource->getKey(),
+ $resource->getValue()
+ );
+ break;
+ case Resource::TYPE_DEPLOYMENT:
+ return $this->importDeployment($resource);
+ break;
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+
+ return $resource;
+ } catch (\Exception $e) {
+ $resource->setStatus(Resource::STATUS_ERROR, $e->getMessage());
+ } finally {
+ return $resource;
+ }
+ }
+
+ private function importDeployment(Deployment $deployment): Resource
+ {
+ $functionId = $deployment->getFunction()->getId();
+
+ $response = null;
+
+ if ($deployment->getSize() <= Transfer::STORAGE_MAX_CHUNK_SIZE) {
+ $response = $this->client->call(
+ 'POST',
+ "/v1/functions/{$functionId}/deployments",
+ [
+ 'content-type' => 'multipart/form-data',
+ ],
+ [
+ 'functionId' => $functionId,
+ 'code' => new \CurlFile('data://application/gzip;base64,'.base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'),
+ 'activate' => $deployment->getActivated() ? 'true' : 'false',
+ 'entrypoint' => $deployment->getEntrypoint(),
+ ]
+ );
+
+ $deployment->setStatus(Resource::STATUS_SUCCESS);
+
+ return $deployment;
+ }
+
+ $response = $this->client->call(
+ 'POST',
+ "/v1/functions/{$functionId}/deployments",
+ [
+ 'content-type' => 'multipart/form-data',
+ 'content-range' => 'bytes '.($deployment->getStart()).'-'.($deployment->getEnd() == ($deployment->getSize() - 1) ? $deployment->getSize() : $deployment->getEnd()).'/'.$deployment->getSize(),
+ 'x-appwrite-id' => $deployment->getId(),
+ ],
+ [
+ 'functionId' => $functionId,
+ 'code' => new \CurlFile('data://application/gzip;base64,'.base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'),
+ 'activate' => $deployment->getActivated(),
+ 'entrypoint' => $deployment->getEntrypoint(),
+ ]
+ );
+
+ if ($deployment->getStart() === 0) {
+ $deployment->setId($response['$id']);
+ }
+
+ if ($deployment->getEnd() == ($deployment->getSize() - 1)) {
+ $deployment->setStatus(Resource::STATUS_SUCCESS);
+ } else {
+ $deployment->setStatus(Resource::STATUS_PENDING);
+ }
+
+ return $deployment;
+ }
+}
diff --git a/src/Transfer/Destinations/Local.php b/src/Transfer/Destinations/Local.php
new file mode 100644
index 00000000..73268ad4
--- /dev/null
+++ b/src/Transfer/Destinations/Local.php
@@ -0,0 +1,144 @@
+path = $path;
+
+ if (!\file_exists($this->path)) {
+ mkdir($this->path, 0777, true);
+ mkdir($this->path . '/files', 0777, true);
+ mkdir($this->path . '/deployments', 0777, true);
+ }
+ }
+
+ /**
+ * Get Name
+ */
+ public static function getName(): string
+ {
+ return 'Local';
+ }
+
+ /**
+ * Get Supported Resources
+ */
+ static function getSupportedResources(): array
+ {
+ return [
+ Resource::TYPE_ATTRIBUTE,
+ Resource::TYPE_BUCKET,
+ Resource::TYPE_COLLECTION,
+ Resource::TYPE_DATABASE,
+ Resource::TYPE_DEPLOYMENT,
+ Resource::TYPE_DOCUMENT,
+ Resource::TYPE_ENVVAR,
+ Resource::TYPE_FILE,
+ Resource::TYPE_FUNCTION,
+ Resource::TYPE_HASH,
+ Resource::TYPE_INDEX,
+ Resource::TYPE_TEAM,
+ Resource::TYPE_MEMBERSHIP,
+ Resource::TYPE_USER
+ ];
+ }
+
+ /**
+ * Report checks if all resources are accessible and ready for writing.
+ */
+ public function report(array $resources = []): array
+ {
+ $report = [];
+
+ if (empty($resources)) {
+ $resources = $this->getSupportedResources();
+ }
+
+ // Check we can write to the file
+ if (!\is_writable($this->path . '/backup.json')) {
+ $report[Transfer::GROUP_DATABASES][] = 'Unable to write to file: ' . $this->path;
+ throw new \Exception('Unable to write to file: ' . $this->path);
+ }
+
+ return $report;
+ }
+
+ /**
+ * Write all data to file
+ */
+ private function sync(): void
+ {
+ $jsonEncodedData = \json_encode($this->data, JSON_PRETTY_PRINT);
+
+ if ($jsonEncodedData === false) {
+ throw new \Exception('Unable to encode data to JSON, Are you accidentally encoding binary data?');
+ }
+
+ \file_put_contents($this->path . '/backup.json', \json_encode($this->data, JSON_PRETTY_PRINT));
+ }
+
+ protected function import(array $resources, callable $callback): void
+ {
+ foreach ($resources as $resource) {
+ /** @var Resource $resource */
+ switch ($resource->getName()) {
+ case 'Deployment':
+ /** @var Deployment $resource */
+ if ($resource->getStart() === 0) {
+ $this->data[$resource->getGroup()][$resource->getName()][$resource->getInternalId()] = $resource->asArray();
+ }
+
+ file_put_contents($this->path . 'deployments/' . $resource->getId() . '.tar.gz', $resource->getData(), FILE_APPEND);
+ break;
+ case 'File':
+ /** @var File $resource */
+
+ // Handle folders
+ if (str_contains($resource->getFileName(), '/')) {
+ $folders = explode('/', $resource->getFileName());
+ $folderPath = $this->path . '/files';
+
+ foreach ($folders as $folder) {
+ $folderPath .= '/' . $folder;
+
+ if (!\file_exists($folderPath) && str_contains($folder, '.') === false) {
+ mkdir($folderPath, 0777, true);
+ }
+ }
+ }
+
+ if ($resource->getStart() === 0 && \file_exists($this->path . '/files/' . $resource->getFileName())) {
+ unlink($this->path . '/files/' . $resource->getFileName());
+ }
+
+ file_put_contents($this->path . '/files/' . $resource->getFileName(), $resource->getData(), FILE_APPEND);
+ break;
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+ $this->cache->update($resource);
+ $this->sync();
+ }
+
+ $callback($resources);
+ }
+}
diff --git a/src/Transfer/Resource.php b/src/Transfer/Resource.php
new file mode 100644
index 00000000..a35c0a2a
--- /dev/null
+++ b/src/Transfer/Resource.php
@@ -0,0 +1,181 @@
+id;
+ }
+
+ /**
+ * Set ID
+ */
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get Internal ID
+ */
+ public function getInternalId(): string
+ {
+ return $this->internalId;
+ }
+
+ /**
+ * Set Internal ID
+ */
+ public function setInternalId(string $internalId): self
+ {
+ $this->internalId = $internalId;
+
+ return $this;
+ }
+
+ /**
+ * Get Status
+ */
+ public function getStatus(): string
+ {
+ return $this->status;
+ }
+
+ /**
+ * Set Status
+ */
+ public function setStatus(string $status, string $message = ''): self
+ {
+ $this->status = $status;
+ $this->message = $message;
+
+ return $this;
+ }
+
+ /**
+ * Get message
+ */
+ public function getMessage(): string
+ {
+ return $this->message;
+ }
+
+ /**
+ * Set message
+ */
+ public function setMessage(string $message): self
+ {
+ $this->message = $message;
+
+ return $this;
+ }
+
+ /**
+ * As Array
+ */
+ abstract public function asArray(): array;
+}
diff --git a/src/Transfer/Resources/Auth/Hash.php b/src/Transfer/Resources/Auth/Hash.php
new file mode 100644
index 00000000..d903b91c
--- /dev/null
+++ b/src/Transfer/Resources/Auth/Hash.php
@@ -0,0 +1,249 @@
+hash = $hash;
+ $this->salt = $salt;
+ $this->algorithm = $algorithm;
+ $this->separator = $separator;
+ $this->signingKey = $signingKey;
+ $this->passwordCpu = $passwordCpu;
+ $this->passwordMemory = $passwordMemory;
+ $this->passwordParallel = $passwordParallel;
+ $this->passwordLength = $passwordLength;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_HASH;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_AUTH;
+ }
+
+ /**
+ * Get Hash
+ */
+ public function getHash(): string
+ {
+ return $this->hash;
+ }
+
+ /**
+ * Set Hash
+ */
+ public function setHash(string $hash): self
+ {
+ $this->hash = $hash;
+
+ return $this;
+ }
+
+ /**
+ * Get Salt
+ */
+ public function getSalt(): string
+ {
+ return $this->salt;
+ }
+
+ /**
+ * Set Salt
+ */
+ public function setSalt(string $salt): self
+ {
+ $this->salt = $salt;
+
+ return $this;
+ }
+
+ /**
+ * Get Algorithm
+ */
+ public function getAlgorithm(): string
+ {
+ return $this->algorithm;
+ }
+
+ /**
+ * Set Algorithm
+ */
+ public function setAlgorithm(string $algorithm): self
+ {
+ $this->algorithm = $algorithm;
+
+ return $this;
+ }
+
+ /**
+ * Get Separator
+ */
+ public function getSeparator(): string
+ {
+ return $this->separator;
+ }
+
+ /**
+ * Set Separator
+ */
+ public function setSeparator(string $separator): self
+ {
+ $this->separator = $separator;
+
+ return $this;
+ }
+
+ /**
+ * Get Signing Key
+ */
+ public function getSigningKey(): string
+ {
+ return $this->signingKey;
+ }
+
+ /**
+ * Set Signing Key
+ */
+ public function setSigningKey(string $signingKey): self
+ {
+ $this->signingKey = $signingKey;
+
+ return $this;
+ }
+
+ /**
+ * Get Password CPU
+ */
+ public function getPasswordCpu(): int
+ {
+ return $this->passwordCpu;
+ }
+
+ /**
+ * Set Password CPU
+ */
+ public function setPasswordCpu(int $passwordCpu): self
+ {
+ $this->passwordCpu = $passwordCpu;
+
+ return $this;
+ }
+
+ /**
+ * Get Password Memory
+ */
+ public function getPasswordMemory(): int
+ {
+ return $this->passwordMemory;
+ }
+
+ /**
+ * Set Password Memory
+ */
+ public function setPasswordMemory(int $passwordMemory): self
+ {
+ $this->passwordMemory = $passwordMemory;
+
+ return $this;
+ }
+
+ /**
+ * Get Password Parallel
+ */
+ public function getPasswordParallel(): int
+ {
+ return $this->passwordParallel;
+ }
+
+ /**
+ * Set Password Parallel
+ */
+ public function setPasswordParallel(int $passwordParallel): self
+ {
+ $this->passwordParallel = $passwordParallel;
+
+ return $this;
+ }
+
+ /**
+ * Get Password Length
+ */
+ public function getPasswordLength(): int
+ {
+ return $this->passwordLength;
+ }
+
+ /**
+ * Set Password Length
+ */
+ public function setPasswordLength(int $passwordLength): self
+ {
+ $this->passwordLength = $passwordLength;
+
+ return $this;
+ }
+
+ /**
+ * As Array
+ */
+ public function asArray(): array
+ {
+ return [
+ 'hash' => $this->hash,
+ 'salt' => $this->salt,
+ 'algorithm' => $this->algorithm,
+ 'separator' => $this->separator,
+ 'signingKey' => $this->signingKey,
+ 'passwordCpu' => $this->passwordCpu,
+ 'passwordMemory' => $this->passwordMemory,
+ 'passwordParallel' => $this->passwordParallel,
+ 'passwordLength' => $this->passwordLength,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Auth/Membership.php b/src/Transfer/Resources/Auth/Membership.php
new file mode 100644
index 00000000..971141ff
--- /dev/null
+++ b/src/Transfer/Resources/Auth/Membership.php
@@ -0,0 +1,95 @@
+team = $team;
+ $this->userId = $userId;
+ $this->roles = $roles;
+ $this->active = $active;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_MEMBERSHIP;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_AUTH;
+ }
+
+ public function getTeam(): Team
+ {
+ return $this->team;
+ }
+
+ public function setTeam(Team $team): self
+ {
+ $this->team = $team;
+
+ return $this;
+ }
+
+ public function getUserId(): string
+ {
+ return $this->userId;
+ }
+
+ public function setUserId(string $userId): self
+ {
+ $this->userId = $userId;
+
+ return $this;
+ }
+
+ public function getRoles(): array
+ {
+ return $this->roles;
+ }
+
+ public function setRoles(array $roles): self
+ {
+ $this->roles = $roles;
+
+ return $this;
+ }
+
+ public function getActive(): bool
+ {
+ return $this->active;
+ }
+
+ public function setActive(bool $active): self
+ {
+ $this->active = $active;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'userId' => $this->userId,
+ 'roles' => $this->roles,
+ 'active' => $this->active,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Auth/Team.php b/src/Transfer/Resources/Auth/Team.php
new file mode 100644
index 00000000..78afcb64
--- /dev/null
+++ b/src/Transfer/Resources/Auth/Team.php
@@ -0,0 +1,96 @@
+id = $id;
+ $this->name = $name;
+ $this->preferences = $preferences;
+ $this->members = $members;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_TEAM;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_AUTH;
+ }
+
+ public function getTeamName(): string
+ {
+ return $this->name;
+ }
+
+ public function setTeamName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getPreferences(): array
+ {
+ return $this->preferences;
+ }
+
+ public function setPreferences(array $preferences): self
+ {
+ $this->preferences = $preferences;
+
+ return $this;
+ }
+
+ public function getMembers(): array
+ {
+ return $this->members;
+ }
+
+ /**
+ * @param User[] $members
+ */
+ public function setMembers(array $members): self
+ {
+ $this->members = $members;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'name' => $this->name,
+ 'preferences' => $this->preferences,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Auth/User.php b/src/Transfer/Resources/Auth/User.php
new file mode 100644
index 00000000..782af79e
--- /dev/null
+++ b/src/Transfer/Resources/Auth/User.php
@@ -0,0 +1,296 @@
+id = $id;
+ $this->email = $email;
+ $this->username = $username;
+ $this->passwordHash = $passwordHash;
+ $this->phone = $phone;
+ $this->types = $types;
+ $this->oauthProvider = $oauthProvider;
+ $this->emailVerified = $emailVerified;
+ $this->phoneVerified = $phoneVerified;
+ $this->disabled = $disabled;
+ $this->preferences = $preferences;
+ }
+
+ /**
+ * Get Name
+ */
+ public static function getName(): string
+ {
+ return Resource::TYPE_USER;
+ }
+
+ /**
+ * Get ID
+ */
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ /**
+ * Set ID
+ */
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get Email
+ */
+ public function getEmail(): string
+ {
+ return $this->email;
+ }
+
+ /**
+ * Set Email
+ */
+ public function setEmail(string $email): self
+ {
+ $this->email = $email;
+
+ return $this;
+ }
+
+ /**
+ * Get Username
+ */
+ public function getUsername(): string
+ {
+ return $this->username;
+ }
+
+ /**
+ * Set Username
+ */
+ public function setUsername(string $username): self
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Get Password Hash
+ */
+ public function getPasswordHash(): Hash
+ {
+ return $this->passwordHash;
+ }
+
+ /**
+ * Set Password Hash
+ */
+ public function setPasswordHash(Hash $passwordHash): self
+ {
+ $this->passwordHash = $passwordHash;
+
+ return $this;
+ }
+
+ /**
+ * Get Phone
+ */
+ public function getPhone(): string
+ {
+ return $this->phone;
+ }
+
+ /**
+ * Set Phone
+ */
+ public function setPhone(string $phone): self
+ {
+ $this->phone = $phone;
+
+ return $this;
+ }
+
+ /**
+ * Get Type
+ */
+ public function getTypes(): array
+ {
+ return $this->types;
+ }
+
+ /**
+ * Set Types
+ */
+ public function setTypes(string $types): self
+ {
+ $this->types = $types;
+
+ return $this;
+ }
+
+ /**
+ * Get OAuth Provider
+ */
+ public function getOAuthProvider(): string
+ {
+ return $this->oauthProvider;
+ }
+
+ /**
+ * Set OAuth Provider
+ */
+ public function setOAuthProvider(string $oauthProvider): self
+ {
+ $this->oauthProvider = $oauthProvider;
+
+ return $this;
+ }
+
+ /**
+ * Get Email Verified
+ */
+ public function getEmailVerified(): bool
+ {
+ return $this->emailVerified;
+ }
+
+ /**
+ * Set Email Verified
+ */
+ public function setEmailVerified(bool $verified): self
+ {
+ $this->emailVerified = $verified;
+
+ return $this;
+ }
+
+ /**
+ * Get Email Verified
+ */
+ public function getPhoneVerified(): bool
+ {
+ return $this->phoneVerified;
+ }
+
+ /**
+ * Set Phone Verified
+ */
+ public function setPhoneVerified(bool $verified): self
+ {
+ $this->phoneVerified = $verified;
+
+ return $this;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_AUTH;
+ }
+
+ /**
+ * Get Disabled
+ */
+ public function getDisabled(): bool
+ {
+ return $this->disabled;
+ }
+
+ /**
+ * Set Disabled
+ */
+ public function setDisabled(bool $disabled): self
+ {
+ $this->disabled = $disabled;
+
+ return $this;
+ }
+
+ /**
+ * Get Preferences
+ */
+ public function getPreferences(): array
+ {
+ return $this->preferences;
+ }
+
+ /**
+ * Set Preferences
+ */
+ public function setPreferences(array $preferences): self
+ {
+ $this->preferences = $preferences;
+
+ return $this;
+ }
+
+ /**
+ * As Array
+ */
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'email' => $this->email,
+ 'username' => $this->username,
+ 'passwordHash' => $this->passwordHash ? $this->passwordHash->asArray() : null,
+ 'phone' => $this->phone,
+ 'types' => $this->types,
+ 'oauthProvider' => $this->oauthProvider,
+ 'emailVerified' => $this->emailVerified,
+ 'phoneVerified' => $this->phoneVerified,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attribute.php b/src/Transfer/Resources/Database/Attribute.php
new file mode 100644
index 00000000..9a3b0d8d
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attribute.php
@@ -0,0 +1,118 @@
+key = $key;
+ $this->required = $required;
+ $this->array = $array;
+ $this->collection = $collection;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_ATTRIBUTE;
+ }
+
+ abstract public function getTypeName(): string;
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_DATABASES;
+ }
+
+ public function getKey(): string
+ {
+ return $this->key;
+ }
+
+ public function setKey(string $key): self
+ {
+ $this->key = $key;
+
+ return $this;
+ }
+
+ public function getCollection(): Collection
+ {
+ return $this->collection;
+ }
+
+ public function setCollection(Collection $collection)
+ {
+ $this->collection = $collection;
+
+ return $this;
+ }
+
+ public function getRequired(): bool
+ {
+ return $this->required;
+ }
+
+ public function setRequired(bool $required): self
+ {
+ $this->required = $required;
+
+ return $this;
+ }
+
+ public function getArray(): bool
+ {
+ return $this->array;
+ }
+
+ public function setArray(bool $array): self
+ {
+ $this->array = $array;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'key' => $this->key,
+ 'required' => $this->required,
+ 'array' => $this->array,
+ 'type' => $this->getName(),
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Boolean.php b/src/Transfer/Resources/Database/Attributes/Boolean.php
new file mode 100644
index 00000000..b72f5310
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Boolean.php
@@ -0,0 +1,48 @@
+default = $default;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_BOOLEAN;
+ }
+
+ public function getDefault(): ?bool
+ {
+ return $this->default;
+ }
+
+ public function setDefault(bool $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function asArray(): array
+ {
+ return array_merge(parent::asArray(), [
+ 'default' => $this->default,
+ ]);
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/DateTime.php b/src/Transfer/Resources/Database/Attributes/DateTime.php
new file mode 100644
index 00000000..a8b4d5af
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/DateTime.php
@@ -0,0 +1,35 @@
+default = $default;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_DATETIME;
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Decimal.php b/src/Transfer/Resources/Database/Attributes/Decimal.php
new file mode 100644
index 00000000..92226461
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Decimal.php
@@ -0,0 +1,78 @@
+default = $default;
+ $this->min = $min;
+ $this->max = $max;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_FLOAT;
+ }
+
+ public function getMin(): float|null
+ {
+ return $this->min;
+ }
+
+ public function getMax(): float|null
+ {
+ return $this->max;
+ }
+
+ public function setMin(float $min): self
+ {
+ $this->min = $min;
+
+ return $this;
+ }
+
+ public function setMax(float $max): self
+ {
+ $this->max = $max;
+
+ return $this;
+ }
+
+ public function getDefault(): ?float
+ {
+ return $this->default;
+ }
+
+ public function setDefault(float $default): self
+ {
+ $this->default = $default;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return array_merge(parent::asArray(), [
+ 'min' => $this->getMin(),
+ 'max' => $this->getMax(),
+ 'default' => $this->getDefault(),
+ ]);
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Email.php b/src/Transfer/Resources/Database/Attributes/Email.php
new file mode 100644
index 00000000..64b2df3c
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Email.php
@@ -0,0 +1,35 @@
+default = $default;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_EMAIL;
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Enum.php b/src/Transfer/Resources/Database/Attributes/Enum.php
new file mode 100644
index 00000000..6880c54e
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Enum.php
@@ -0,0 +1,58 @@
+default = $default;
+ $this->elements = $elements;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_ENUM;
+ }
+
+ public function getElements(): array
+ {
+ return $this->elements;
+ }
+
+ public function setElements(array $elements): self
+ {
+ $this->elements = $elements;
+
+ return $this;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function asArray(): array
+ {
+ return array_merge(parent::asArray(), [
+ 'elements' => $this->elements,
+ ]);
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/IP.php b/src/Transfer/Resources/Database/Attributes/IP.php
new file mode 100644
index 00000000..a2049185
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/IP.php
@@ -0,0 +1,35 @@
+default = $default;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_IP;
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Integer.php b/src/Transfer/Resources/Database/Attributes/Integer.php
new file mode 100644
index 00000000..f84e2f59
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Integer.php
@@ -0,0 +1,78 @@
+default = $default;
+ $this->min = $min;
+ $this->max = $max;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_INTEGER;
+ }
+
+ public function getMin(): int|null
+ {
+ return $this->min;
+ }
+
+ public function getMax(): int|null
+ {
+ return $this->max;
+ }
+
+ public function setMin(int|null $min): self
+ {
+ $this->min = $min;
+
+ return $this;
+ }
+
+ public function setMax(int|null $max): self
+ {
+ $this->max = $max;
+
+ return $this;
+ }
+
+ public function getDefault(): ?int
+ {
+ return $this->default;
+ }
+
+ public function setDefault(int $default): self
+ {
+ $this->default = $default;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return array_merge(parent::asArray(), [
+ 'min' => $this->getMin(),
+ 'max' => $this->getMax(),
+ 'default' => $this->getDefault(),
+ ]);
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Relationship.php b/src/Transfer/Resources/Database/Attributes/Relationship.php
new file mode 100644
index 00000000..59190c06
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Relationship.php
@@ -0,0 +1,97 @@
+relatedCollection = $relatedCollection;
+ $this->relationType = $relationType;
+ $this->twoWay = $twoWay;
+ $this->twoWayKey = $twoWayKey;
+ $this->onDelete = $onDelete;
+ $this->side = $side;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_RELATIONSHIP;
+ }
+
+ public function getRelatedCollection(): string
+ {
+ return $this->relatedCollection;
+ }
+
+ public function setRelatedCollection(string $relatedCollection): void
+ {
+ $this->relatedCollection = $relatedCollection;
+ }
+
+ public function getRelationType(): string
+ {
+ return $this->relationType;
+ }
+
+ public function setRelationType(string $relationType): void
+ {
+ $this->relationType = $relationType;
+ }
+
+ public function getTwoWay(): bool
+ {
+ return $this->twoWay;
+ }
+
+ public function setTwoWay(bool $twoWay): void
+ {
+ $this->twoWay = $twoWay;
+ }
+
+ public function getTwoWayKey(): string
+ {
+ return $this->twoWayKey;
+ }
+
+ public function setTwoWayKey(string $twoWayKey): void
+ {
+ $this->twoWayKey = $twoWayKey;
+ }
+
+ public function getOnDelete(): string
+ {
+ return $this->onDelete;
+ }
+
+ public function setOnDelete(string $onDelete): void
+ {
+ $this->onDelete = $onDelete;
+ }
+
+ public function getSide(): string
+ {
+ return $this->side;
+ }
+
+ public function setSide(string $side): void
+ {
+ $this->side = $side;
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/Text.php b/src/Transfer/Resources/Database/Attributes/Text.php
new file mode 100644
index 00000000..1b97d409
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/Text.php
@@ -0,0 +1,57 @@
+default = $default;
+ $this->size = $size;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_STRING;
+ }
+
+ public function getSize(): int
+ {
+ return $this->size;
+ }
+
+ public function setSize(int $size): self
+ {
+ $this->size = $size;
+
+ return $this;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function asArray(): array
+ {
+ return array_merge(parent::asArray(), [
+ 'size' => $this->size,
+ ]);
+ }
+}
diff --git a/src/Transfer/Resources/Database/Attributes/URL.php b/src/Transfer/Resources/Database/Attributes/URL.php
new file mode 100644
index 00000000..9e6ec417
--- /dev/null
+++ b/src/Transfer/Resources/Database/Attributes/URL.php
@@ -0,0 +1,35 @@
+default = $default;
+ }
+
+ public function getDefault(): ?string
+ {
+ return $this->default;
+ }
+
+ public function setDefault(string $default): void
+ {
+ $this->default = $default;
+ }
+
+ public function getTypeName(): string
+ {
+ return Attribute::TYPE_URL;;
+ }
+}
diff --git a/src/Transfer/Resources/Database/Collection.php b/src/Transfer/Resources/Database/Collection.php
new file mode 100644
index 00000000..2e09a74b
--- /dev/null
+++ b/src/Transfer/Resources/Database/Collection.php
@@ -0,0 +1,118 @@
+
+ */
+ private array $columns = [];
+
+ /**
+ * @var list
+ */
+ private array $indexes = [];
+
+ private Database $database;
+
+ protected array $permissions = [];
+
+ protected bool $documentSecurity = false;
+
+ protected string $name;
+
+ protected string $id;
+
+ public function __construct(Database $database, string $name, string $id, bool $documentSecurity = false, array $permissions = [])
+ {
+ $this->database = $database;
+ $this->name = $name;
+ $this->id = $id;
+ $this->documentSecurity = $documentSecurity;
+ $this->permissions = $permissions;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_COLLECTION;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_DATABASES;
+ }
+
+ public function getDatabase(): Database
+ {
+ return $this->database;
+ }
+
+ public function setDatabase(Database $database): self
+ {
+ $this->database = $database;
+
+ return $this;
+ }
+
+ public function getCollectionName(): string
+ {
+ return $this->name;
+ }
+
+ public function setCollectionName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getDocumentSecurity(): bool
+ {
+ return $this->documentSecurity;
+ }
+
+ public function setDocumentSecurity(bool $documentSecurity): self
+ {
+ $this->documentSecurity = $documentSecurity;
+
+ return $this;
+ }
+
+ public function getPermissions(): array
+ {
+ return $this->permissions;
+ }
+
+ public function setPermissions(array $permissions): self
+ {
+ $this->permissions = $permissions;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'name' => $this->name,
+ 'id' => $this->id,
+ 'permissions' => $this->permissions,
+ 'documentSecurity' => $this->documentSecurity,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Database/Database.php b/src/Transfer/Resources/Database/Database.php
new file mode 100644
index 00000000..33bc69fc
--- /dev/null
+++ b/src/Transfer/Resources/Database/Database.php
@@ -0,0 +1,88 @@
+
+ */
+ private array $collections = [];
+
+ protected string $name;
+
+ protected string $id;
+
+ public function __construct(string $name = '', string $id = '')
+ {
+ $this->name = $name;
+ $this->id = $id;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_DATABASE;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_DATABASES;
+ }
+
+ public function getDBName(): string
+ {
+ return $this->name;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ /**
+ * @return list
+ */
+ public function getCollections(): array
+ {
+ return $this->collections;
+ }
+
+ /**
+ * @param list $collections
+ */
+ public function setCollections(array $collections): self
+ {
+ $this->collections = $collections;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'name' => $this->name,
+ 'id' => $this->id,
+ 'collections' => array_map(function ($collection) {
+ return $collection->asArray();
+ }, $this->collections),
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Database/Document.php b/src/Transfer/Resources/Database/Document.php
new file mode 100644
index 00000000..676eb2bb
--- /dev/null
+++ b/src/Transfer/Resources/Database/Document.php
@@ -0,0 +1,119 @@
+id = $id;
+ $this->database = $database;
+ $this->collection = $collection;
+ $this->data = $data;
+ $this->permissions = $permissions;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_DOCUMENT;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_DATABASES;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getDatabase(): Database
+ {
+ return $this->database;
+ }
+
+ public function setDatabase(Database $database): self
+ {
+ $this->database = $database;
+
+ return $this;
+ }
+
+ public function getCollection(): Collection
+ {
+ return $this->collection;
+ }
+
+ public function setCollection(Collection $collection): self
+ {
+ $this->collection = $collection;
+
+ return $this;
+ }
+
+ public function getData(): array
+ {
+ return $this->data;
+ }
+
+ /**
+ * Set Data
+ *
+ * @param array $data
+ */
+ public function setData(array $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ public function getPermissions(): array
+ {
+ return $this->permissions;
+ }
+
+ /**
+ * Set Permissions
+ *
+ * @param array $permissions
+ */
+ public function setPermissions(array $permissions): self
+ {
+ $this->permissions = $permissions;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'database' => $this->database,
+ 'collection' => $this->collection,
+ 'attributes' => $this->data,
+ 'permissions' => $this->permissions,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Database/Index.php b/src/Transfer/Resources/Database/Index.php
new file mode 100644
index 00000000..0faf2058
--- /dev/null
+++ b/src/Transfer/Resources/Database/Index.php
@@ -0,0 +1,121 @@
+ $attributes
+ */
+ public function __construct(string $id, string $key, Collection $collection, string $type = '', array $attributes = [], array $orders = [])
+ {
+ $this->id = $id;
+ $this->key = $key;
+ $this->type = $type;
+ $this->attributes = $attributes;
+ $this->orders = $orders;
+ $this->collection = $collection;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_INDEX;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_DATABASES;
+ }
+
+ public function getKey(): string
+ {
+ return $this->key;
+ }
+
+ public function setKey(string $key): self
+ {
+ $this->key = $key;
+
+ return $this;
+ }
+
+ public function getCollection(): Collection
+ {
+ return $this->collection;
+ }
+
+ public function setCollection(Collection $collection): self
+ {
+ $this->collection = $collection;
+
+ return $this;
+ }
+
+ public function getType(): string
+ {
+ return $this->type;
+ }
+
+ public function setType(string $type): self
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ public function getAttributes(): array
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * @param list $attributes
+ */
+ public function setAttributes(array $attributes): self
+ {
+ $this->attributes = $attributes;
+
+ return $this;
+ }
+
+ public function getOrders(): array
+ {
+ return $this->orders;
+ }
+
+ public function setOrders(array $orders): self
+ {
+ $this->orders = $orders;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'key' => $this->key,
+ 'type' => $this->type,
+ 'attributes' => $this->attributes,
+ 'orders' => $this->orders,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Functions/Deployment.php b/src/Transfer/Resources/Functions/Deployment.php
new file mode 100644
index 00000000..2f6fe407
--- /dev/null
+++ b/src/Transfer/Resources/Functions/Deployment.php
@@ -0,0 +1,156 @@
+id = $id;
+ $this->func = $func;
+ $this->size = $size;
+ $this->entrypoint = $entrypoint;
+ $this->start = $start;
+ $this->end = $end;
+ $this->data = $data;
+ $this->activated = $activated;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_DEPLOYMENT;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_FUNCTIONS;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getFunction(): Func
+ {
+ return $this->func;
+ }
+
+ public function setFunction(Func $func): self
+ {
+ $this->func = $func;
+
+ return $this;
+ }
+
+ public function setSize(int $size): self
+ {
+ $this->size = $size;
+
+ return $this;
+ }
+
+ public function getSize(): int
+ {
+ return $this->size;
+ }
+
+ public function setEntrypoint(string $entrypoint): self
+ {
+ $this->entrypoint = $entrypoint;
+
+ return $this;
+ }
+
+ public function getEntrypoint(): string
+ {
+ return $this->entrypoint;
+ }
+
+ public function setStart(int $start): self
+ {
+ $this->start = $start;
+
+ return $this;
+ }
+
+ public function getStart(): int
+ {
+ return $this->start;
+ }
+
+ public function setEnd(int $end): self
+ {
+ $this->end = $end;
+
+ return $this;
+ }
+
+ public function getEnd(): int
+ {
+ return $this->end;
+ }
+
+ public function setData(string $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ public function getData(): string
+ {
+ return $this->data;
+ }
+
+ public function setActivated(bool $activated): self
+ {
+ $this->activated = $activated;
+
+ return $this;
+ }
+
+ public function getActivated(): bool
+ {
+ return $this->activated;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'func' => $this->func->asArray(),
+ 'size' => $this->size,
+ 'entrypoint' => $this->entrypoint,
+ 'start' => $this->start,
+ 'end' => $this->end,
+ 'activated' => $this->activated,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Functions/EnvVar.php b/src/Transfer/Resources/Functions/EnvVar.php
new file mode 100644
index 00000000..d11f3b09
--- /dev/null
+++ b/src/Transfer/Resources/Functions/EnvVar.php
@@ -0,0 +1,77 @@
+func = $func;
+ $this->key = $key;
+ $this->value = $value;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_ENVVAR;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_FUNCTIONS;
+ }
+
+ public function getFunc(): Func
+ {
+ return $this->func;
+ }
+
+ public function setFunc(Func $func): self
+ {
+ $this->func = $func;
+
+ return $this;
+ }
+
+ public function getKey(): string
+ {
+ return $this->key;
+ }
+
+ public function setKey(string $key): self
+ {
+ $this->key = $key;
+
+ return $this;
+ }
+
+ public function getValue(): string
+ {
+ return $this->value;
+ }
+
+ public function setValue(string $value): self
+ {
+ $this->value = $value;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'func' => $this->func->getId(),
+ 'key' => $this->key,
+ 'value' => $this->value,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Functions/Func.php b/src/Transfer/Resources/Functions/Func.php
new file mode 100644
index 00000000..ef65d3dc
--- /dev/null
+++ b/src/Transfer/Resources/Functions/Func.php
@@ -0,0 +1,150 @@
+name = $name;
+ $this->id = $id;
+ $this->execute = $execute;
+ $this->enabled = $enabled;
+ $this->runtime = $runtime;
+ $this->events = $events;
+ $this->schedule = $schedule;
+ $this->timeout = $timeout;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_FUNCTION;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_FUNCTIONS;
+ }
+
+ public function getFunctionName(): string
+ {
+ return $this->name;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getExecute(): array
+ {
+ return $this->execute;
+ }
+
+ public function setExecute(array $execute): self
+ {
+ $this->execute = $execute;
+
+ return $this;
+ }
+
+ public function getEnabled(): bool
+ {
+ return $this->enabled;
+ }
+
+ public function setEnabled(bool $enabled): self
+ {
+ $this->enabled = $enabled;
+
+ return $this;
+ }
+
+ public function getRuntime(): string
+ {
+ return $this->runtime;
+ }
+
+ public function setRuntime(string $runtime): self
+ {
+ $this->runtime = $runtime;
+
+ return $this;
+ }
+
+ public function getEvents(): array
+ {
+ return $this->events;
+ }
+
+ public function setEvents(array $events): self
+ {
+ $this->events = $events;
+
+ return $this;
+ }
+
+ public function getSchedule(): string
+ {
+ return $this->schedule;
+ }
+
+ public function setSchedule(string $schedule): self
+ {
+ $this->schedule = $schedule;
+
+ return $this;
+ }
+
+ public function getTimeout(): int
+ {
+ return $this->timeout;
+ }
+
+ public function setTimeout(int $timeout): self
+ {
+ $this->timeout = $timeout;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'name' => $this->name,
+ 'id' => $this->id,
+ 'execute' => $this->execute,
+ 'enabled' => $this->enabled,
+ 'runtime' => $this->runtime,
+ 'events' => $this->events,
+ 'schedule' => $this->schedule,
+ 'timeout' => $this->timeout,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Storage/Bucket.php b/src/Transfer/Resources/Storage/Bucket.php
new file mode 100644
index 00000000..6dfc0030
--- /dev/null
+++ b/src/Transfer/Resources/Storage/Bucket.php
@@ -0,0 +1,189 @@
+id = $id;
+ $this->permissions = $permissions;
+ $this->fileSecurity = $fileSecurity;
+ $this->name = $name;
+ $this->enabled = $enabled;
+ $this->maxFileSize = $maxFileSize;
+ $this->allowedFileExtensions = $allowedFileExtensions;
+ $this->compression = $compression;
+ $this->encryption = $encryption;
+ $this->antiVirus = $antiVirus;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_BUCKET;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_STORAGE;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getPermissions(): array
+ {
+ return $this->permissions;
+ }
+
+ public function setPermissions(array $permissions): self
+ {
+ $this->permissions = $permissions;
+
+ return $this;
+ }
+
+ public function getFileSecurity(): bool
+ {
+ return $this->fileSecurity;
+ }
+
+ public function setFileSecurity(bool $fileSecurity): self
+ {
+ $this->fileSecurity = $fileSecurity;
+
+ return $this;
+ }
+
+ public function getBucketName(): string
+ {
+ return $this->name;
+ }
+
+ public function setBucketName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getEnabled(): bool
+ {
+ return $this->enabled;
+ }
+
+ public function setEnabled(bool $enabled): self
+ {
+ $this->enabled = $enabled;
+
+ return $this;
+ }
+
+ public function getMaxFileSize(): int
+ {
+ return $this->maxFileSize;
+ }
+
+ public function setMaxFileSize(int $maxFileSize): self
+ {
+ $this->maxFileSize = $maxFileSize;
+
+ return $this;
+ }
+
+ public function getAllowedFileExtensions(): array
+ {
+ return $this->allowedFileExtensions;
+ }
+
+ public function setAllowedFileExtensions(array $allowedFileExtensions): self
+ {
+ $this->allowedFileExtensions = $allowedFileExtensions;
+
+ return $this;
+ }
+
+ public function getCompression(): string
+ {
+ return $this->compression;
+ }
+
+ public function setCompression(string $compression): self
+ {
+ $this->compression = $compression;
+
+ return $this;
+ }
+
+ public function getEncryption(): bool
+ {
+ return $this->encryption;
+ }
+
+ public function setEncryption(bool $encryption): self
+ {
+ $this->encryption = $encryption;
+
+ return $this;
+ }
+
+ public function getAntiVirus(): bool
+ {
+ return $this->antiVirus;
+ }
+
+ public function setAntiVirus(bool $antiVirus): self
+ {
+ $this->antiVirus = $antiVirus;
+
+ return $this;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'permissions' => $this->permissions,
+ 'fileSecurity' => $this->fileSecurity,
+ 'name' => $this->name,
+ 'enabled' => $this->enabled,
+ 'maxFileSize' => $this->maxFileSize,
+ 'allowedFileExtensions' => $this->allowedFileExtensions,
+ 'compression' => $this->compression,
+ 'encryption' => $this->encryption,
+ 'antiVirus' => $this->antiVirus,
+ ];
+ }
+}
diff --git a/src/Transfer/Resources/Storage/File.php b/src/Transfer/Resources/Storage/File.php
new file mode 100644
index 00000000..4c09743e
--- /dev/null
+++ b/src/Transfer/Resources/Storage/File.php
@@ -0,0 +1,191 @@
+id = $id;
+ $this->bucket = $bucket;
+ $this->name = $name;
+ $this->signature = $signature;
+ $this->mimeType = $mimeType;
+ $this->permissions = $permissions;
+ $this->size = $size;
+ $this->data = $data;
+ $this->start = $start;
+ $this->end = $end;
+ }
+
+ public static function getName(): string
+ {
+ return Resource::TYPE_FILE;
+ }
+
+ public function getGroup(): string
+ {
+ return Transfer::GROUP_STORAGE;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function setId(string $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
+
+ public function getBucket(): Bucket
+ {
+ return $this->bucket;
+ }
+
+ public function setBucket(Bucket $bucket): self
+ {
+ $this->bucket = $bucket;
+
+ return $this;
+ }
+
+ public function getFileName(): string
+ {
+ return $this->name;
+ }
+
+ public function setName(string $name): self
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ public function getSize(): int
+ {
+ return $this->size;
+ }
+
+ public function getSignature(): string
+ {
+ return $this->signature;
+ }
+
+ public function setSignature(string $signature): self
+ {
+ $this->signature = $signature;
+
+ return $this;
+ }
+
+ public function getMimeType(): string
+ {
+ return $this->mimeType;
+ }
+
+ public function setMimeType(string $mimeType): self
+ {
+ $this->mimeType = $mimeType;
+
+ return $this;
+ }
+
+ public function getPermissions(): array
+ {
+ return $this->permissions;
+ }
+
+ public function setPermissions(array $permissions): self
+ {
+ $this->permissions = $permissions;
+
+ return $this;
+ }
+
+ public function getData(): string
+ {
+ return $this->data;
+ }
+
+ public function setData(string $data): self
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ public function getStart(): int
+ {
+ return $this->start;
+ }
+
+ public function setStart(int $start): self
+ {
+ $this->start = $start;
+
+ return $this;
+ }
+
+ public function getEnd(): int
+ {
+ return $this->end;
+ }
+
+ public function setEnd(int $end): self
+ {
+ $this->end = $end;
+
+ return $this;
+ }
+
+ public function getSizeInBytes(): int
+ {
+ return strlen($this->data);
+ }
+
+ public function getChunkSize(): int
+ {
+ return $this->end - $this->start;
+ }
+
+ public function asArray(): array
+ {
+ return [
+ 'id' => $this->id,
+ 'bucket' => $this->bucket->getId(),
+ 'name' => $this->name,
+ 'signature' => $this->signature,
+ 'mimeType' => $this->mimeType,
+ 'permissions' => $this->permissions,
+ 'size' => $this->size,
+ 'start' => $this->start,
+ 'end' => $this->end,
+ ];
+ }
+}
diff --git a/src/Transfer/Source.php b/src/Transfer/Source.php
new file mode 100644
index 00000000..e35a536e
--- /dev/null
+++ b/src/Transfer/Source.php
@@ -0,0 +1,117 @@
+transferCallback)($resources);
+ }
+
+ /**
+ * Transfer Resources into destination
+ */
+ public function run(array $resources, callable $callback): void
+ {
+ $this->transferCallback = function (array $returnedResources) use ($callback, $resources) {
+ $prunedResurces = [];
+ foreach ($returnedResources as $resource) {
+ /** @var Resource $resource */
+ if (!in_array($resource->getName(), $resources)) {
+ $resource->setStatus(Resource::STATUS_SKIPPED);
+ } else {
+ $prunedResurces[] = $resource;
+ }
+ }
+
+ $this->cache->addAll($returnedResources);
+ $callback($prunedResurces);
+ };
+
+ $this->exportResources($resources, 100);
+ }
+
+ /**
+ * Export Resources
+ *
+ * @param string[] $resources
+ * @return void
+ */
+ public function exportResources(array $resources, int $batchSize)
+ {
+ // Convert Resources back into their relevant groups
+
+ $groups = [];
+ foreach ($resources as $resource) {
+ if (in_array($resource, Transfer::GROUP_AUTH_RESOURCES)) {
+ $groups[Transfer::GROUP_AUTH][] = $resource;
+ } elseif (in_array($resource, Transfer::GROUP_DATABASES_RESOURCES)) {
+ $groups[Transfer::GROUP_DATABASES][] = $resource;
+ } elseif (in_array($resource, Transfer::GROUP_STORAGE_RESOURCES)) {
+ $groups[Transfer::GROUP_STORAGE][] = $resource;
+ } elseif (in_array($resource, Transfer::GROUP_FUNCTIONS_RESOURCES)) {
+ $groups[Transfer::GROUP_FUNCTIONS][] = $resource;
+ }
+ }
+
+ if (empty($groups)) {
+ return;
+ }
+
+ // Send each group to the relevant export function
+ foreach ($groups as $group => $resources) {
+ switch ($group) {
+ case Transfer::GROUP_AUTH:
+ $this->exportGroupAuth($batchSize, $resources);
+ break;
+ case Transfer::GROUP_DATABASES:
+ $this->exportGroupDatabases($batchSize, $resources);
+ break;
+ case Transfer::GROUP_STORAGE:
+ $this->exportGroupStorage($batchSize, $resources);
+ break;
+ case Transfer::GROUP_FUNCTIONS:
+ $this->exportGroupFunctions($batchSize, $resources);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Export Auth Group
+ *
+ * @param array $resources Resources to export
+ * @return void
+ */
+ abstract protected function exportGroupAuth(int $batchSize, array $resources);
+
+ /**
+ * Export Databases Group
+ *
+ * @param int $batchSize Max 100
+ * @param array $resources Resources to export
+ * @return void
+ */
+ abstract protected function exportGroupDatabases(int $batchSize, array $resources);
+
+ /**
+ * Export Storage Group
+ *
+ * @param int $batchSize Max 5
+ * @param array $resources Resources to export
+ * @return void
+ */
+ abstract protected function exportGroupStorage(int $batchSize, array $resources);
+
+ /**
+ * Export Functions Group
+ *
+ * @param int $batchSize Max 100
+ * @param array $resources Resources to export
+ * @return void
+ */
+ abstract protected function exportGroupFunctions(int $batchSize, array $resources);
+}
diff --git a/src/Transfer/Sources/Appwrite.php b/src/Transfer/Sources/Appwrite.php
new file mode 100644
index 00000000..14babb67
--- /dev/null
+++ b/src/Transfer/Sources/Appwrite.php
@@ -0,0 +1,1019 @@
+client = (new Client())
+ ->setEndpoint($endpoint)
+ ->setProject($project)
+ ->setKey($key);
+
+ $this->endpoint = $endpoint;
+ $this->project = $project;
+ $this->key = $key;
+ $this->headers['X-Appwrite-Project'] = $this->project;
+ $this->headers['X-Appwrite-Key'] = $this->key;
+ }
+
+ /**
+ * Get Name
+ */
+ public static function getName(): string
+ {
+ return 'Appwrite';
+ }
+
+ /**
+ * Get Supported Resources
+ */
+ static function getSupportedResources(): array
+ {
+ return [
+ // Auth
+ Resource::TYPE_USER,
+ Resource::TYPE_TEAM,
+ Resource::TYPE_MEMBERSHIP,
+
+ // Database
+ Resource::TYPE_DATABASE,
+ Resource::TYPE_COLLECTION,
+ Resource::TYPE_ATTRIBUTE,
+ Resource::TYPE_INDEX,
+ Resource::TYPE_DOCUMENT,
+
+ // Storage
+ Resource::TYPE_BUCKET,
+ Resource::TYPE_FILE,
+
+ // Functions
+ Resource::TYPE_FUNCTION,
+ Resource::TYPE_DEPLOYMENT,
+ Resource::TYPE_ENVVAR,
+
+ // Settings
+ ];
+ }
+
+ public function report(array $resources = []): array
+ {
+ $report = [];
+ $currentPermission = '';
+
+ if (empty($resources)) {
+ $resources = $this->getSupportedResources();
+ }
+
+ $usersClient = new Users($this->client);
+ $teamsClient = new Teams($this->client);
+ $databaseClient = new Databases($this->client);
+ $storageClient = new Storage($this->client);
+ $functionsClient = new Functions($this->client);
+
+ // Auth
+ try {
+ $currentPermission = 'users.read';
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $report[Resource::TYPE_USER] = $usersClient->list()['total'];
+ }
+
+ $currentPermission = 'teams.read';
+ if (in_array(Resource::TYPE_TEAM, $resources)) {
+ $report[Resource::TYPE_TEAM] = $teamsClient->list()['total'];
+ }
+
+ if (in_array(Resource::TYPE_MEMBERSHIP, $resources)) {
+ $report[Resource::TYPE_MEMBERSHIP] = 0;
+ $teams = $teamsClient->list()['teams'];
+ foreach ($teams as $team) {
+ $report[Resource::TYPE_MEMBERSHIP] += $teamsClient->listMemberships($team['$id'])['total'];
+ }
+ }
+
+ // Databases
+ $currentPermission = 'databases.read';
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $report[Resource::TYPE_DATABASE] = $databaseClient->list()['total'];
+ }
+
+ $currentPermission = 'collections.read';
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $report[Resource::TYPE_COLLECTION] = 0;
+ $databases = $databaseClient->list()['databases'];
+ foreach ($databases as $database) {
+ $report[Resource::TYPE_COLLECTION] += $databaseClient->listCollections($database['$id'])['total'];
+ }
+ }
+
+ $currentPermission = 'documents.read';
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $report[Resource::TYPE_DOCUMENT] = 0;
+ $databases = $databaseClient->list()['databases'];
+ foreach ($databases as $database) {
+ $collections = $databaseClient->listCollections($database['$id'])['collections'];
+ foreach ($collections as $collection) {
+ $report[Resource::TYPE_DOCUMENT] += $databaseClient->listDocuments($database['$id'], $collection['$id'])['total'];
+ }
+ }
+ }
+
+ $currentPermission = 'attributes.read';
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $report[Resource::TYPE_ATTRIBUTE] = 0;
+ $databases = $databaseClient->list()['databases'];
+ foreach ($databases as $database) {
+ $collections = $databaseClient->listCollections($database['$id'])['collections'];
+ foreach ($collections as $collection) {
+ $report[Resource::TYPE_ATTRIBUTE] += $databaseClient->listAttributes($database['$id'], $collection['$id'])['total'];
+ }
+ }
+ }
+
+ $currentPermission = 'indexes.read';
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $report[Resource::TYPE_INDEX] = 0;
+ $databases = $databaseClient->list()['databases'];
+ foreach ($databases as $database) {
+ $collections = $databaseClient->listCollections($database['$id'])['collections'];
+ foreach ($collections as $collection) {
+ $report[Resource::TYPE_INDEX] += $databaseClient->listIndexes($database['$id'], $collection['$id'])['total'];
+ }
+ }
+ }
+
+ // Storage
+ $currentPermission = 'buckets.read';
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $report[Resource::TYPE_BUCKET] = $storageClient->listBuckets()['total'];
+ }
+
+ $currentPermission = 'files.read';
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $report[Resource::TYPE_FILE] = 0;
+ $buckets = $storageClient->listBuckets()['buckets'];
+ foreach ($buckets as $bucket) {
+ $report[Resource::TYPE_FILE] += $storageClient->listFiles($bucket['$id'])['total'];
+ }
+ }
+
+ // Functions
+ $currentPermission = 'functions.read';
+ if (in_array(Resource::TYPE_FUNCTION, $resources)) {
+ $report[Resource::TYPE_FUNCTION] = $functionsClient->list()['total'];
+ }
+
+ if (in_array(Resource::TYPE_DEPLOYMENT, $resources)) {
+ $report[Resource::TYPE_DEPLOYMENT] = 0;
+ $functions = $functionsClient->list()['functions'];
+ foreach ($functions as $function) {
+ $report[Resource::TYPE_DEPLOYMENT] += $functionsClient->listDeployments($function['$id'])['total'];
+ }
+ }
+
+ if (in_array(Resource::TYPE_ENVVAR, $resources)) {
+ $report[Resource::TYPE_ENVVAR] = 0;
+ $functions = $functionsClient->list()['functions'];
+ foreach ($functions as $function) {
+ $report[Resource::TYPE_ENVVAR] += $functionsClient->listVariables($function['$id'])['total'];
+ }
+ }
+
+ return $report;
+ } catch (\Exception $e) {
+ if ($e->getCode() === 403) {
+ throw new \Exception("Missing Permission: {$currentPermission}.");
+ } else {
+ throw new \Exception($e->getMessage());
+ }
+ }
+ }
+
+ /**
+ * Export Auth Resources
+ *
+ * @param int $batchSize Max 100
+ * @return void
+ */
+ protected function exportGroupAuth(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $this->exportUsers($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_TEAM, $resources)) {
+ $this->exportTeams($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_MEMBERSHIP, $resources)) {
+ $this->exportMemberships($batchSize);
+ }
+ }
+
+ private function exportUsers(int $batchSize)
+ {
+ $usersClient = new Users($this->client);
+ $lastDocument = null;
+
+ // Export Users
+ while (true) {
+ $users = [];
+
+ $queries = [Query::limit($batchSize)];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $usersClient->list($queries);
+
+ if ($response['total'] == 0) {
+ break;
+ }
+
+ foreach ($response['users'] as $user) {
+ $users[] = new User(
+ $user['$id'],
+ $user['email'],
+ $user['name'],
+ $user['password'] ? new Hash($user['password'], $user['hash']) : null,
+ $user['phone'],
+ $this->calculateTypes($user),
+ '',
+ $user['emailVerification'],
+ $user['phoneVerification'],
+ !$user['status'],
+ $user['prefs']
+ );
+
+ $lastDocument = $user['$id'];
+ }
+
+ $this->callback($users);
+
+ if (count($users) < $batchSize) {
+ break;
+ }
+ }
+ }
+
+ private function exportTeams(int $batchSize)
+ {
+ $teamsClient = new Teams($this->client);
+ $lastDocument = null;
+
+ // Export Teams
+ while (true) {
+ $teams = [];
+
+ $queries = [Query::limit($batchSize)];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $teamsClient->list($queries);
+
+ if ($response['total'] == 0) {
+ break;
+ }
+
+ foreach ($response['teams'] as $team) {
+ $teams[] = new Team(
+ $team['$id'],
+ $team['name'],
+ $team['prefs'],
+ );
+
+ $lastDocument = $team['$id'];
+ }
+
+ $this->callback($teams);
+
+ if (count($teams) < $batchSize) {
+ break;
+ }
+ }
+ }
+
+ private function exportMemberships(int $batchSize)
+ {
+ $teamsClient = new Teams($this->client);
+
+ $lastDocument = null;
+
+ // Export Memberships
+ $cacheTeams = $this->cache->get(Team::getName());
+
+ foreach ($cacheTeams as $team) {
+ /** @var Team $team */
+ while (true) {
+ $memberships = [];
+
+ $queries = [Query::limit($batchSize)];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $teamsClient->listMemberships($team->getId(), $queries);
+
+ if ($response['total'] == 0) {
+ break;
+ }
+
+ foreach ($response['memberships'] as $membership) {
+ $memberships[] = new Membership(
+ $team,
+ $membership['userId'],
+ $membership['roles'],
+ $membership['confirm']
+ );
+
+ $lastDocument = $membership['$id'];
+ }
+
+ $this->callback($memberships);
+
+ if (count($memberships) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ protected function exportGroupDatabases(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $this->exportDatabases($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $this->exportCollections($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $this->exportAttributes($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $this->exportIndexes($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $this->exportDocuments($batchSize);
+ }
+ }
+
+ private function exportDocuments(int $batchSize)
+ {
+ $databaseClient = new Databases($this->client);
+ $collections = $this->cache->get(Collection::getName());
+
+ foreach ($collections as $collection) {
+ /** @var Collection $collection */
+ $lastDocument = null;
+
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+
+ $documents = [];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $databaseClient->listDocuments(
+ $collection->getDatabase()->getId(),
+ $collection->getId(),
+ $queries
+ );
+
+ foreach ($response['documents'] as $document) {
+ $id = $document['$id'];
+ $permissions = $document['$permissions'];
+ unset($document['$id']);
+ unset($document['$permissions']);
+ unset($document['$collectionId']);
+ unset($document['$updatedAt']);
+ unset($document['$createdAt']);
+ unset($document['$databaseId']);
+
+ $documents[] = new Document(
+ $id,
+ $collection->getDatabase(),
+ $collection,
+ $document,
+ $permissions
+ );
+ $lastDocument = $id;
+ }
+
+ $this->callback($documents);
+
+ if (count($response['documents']) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function convertAttribute(array $value, Collection $collection): Attribute
+ {
+ switch ($value['type']) {
+ case 'string':
+ if (!isset($value['format'])) {
+ return new Text(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default'],
+ $value['size'] ?? 0
+ );
+ }
+
+ switch ($value['format']) {
+ case 'email':
+ return new Email(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ case 'enum':
+ return new Enum(
+ $value['key'],
+ $collection,
+ $value['elements'],
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ case 'url':
+ return new URL(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ case 'ip':
+ return new IP(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ case 'datetime':
+ return new DateTime(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ default:
+ return new Text(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default'],
+ $value['size'] ?? 0
+ );
+ }
+ case 'boolean':
+ return new Boolean(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default']
+ );
+ case 'integer':
+ return new Integer(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default'],
+ $value['min'] ?? 0,
+ $value['max'] ?? 0
+ );
+ case 'double':
+ return new Decimal(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['default'],
+ $value['min'] ?? 0,
+ $value['max'] ?? 0
+ );
+ case 'relationship':
+ return new Relationship(
+ $value['key'],
+ $collection,
+ $value['required'],
+ $value['array'],
+ $value['relatedCollection'],
+ $value['relationType'],
+ $value['twoWay'],
+ $value['twoWayKey'],
+ $value['onDelete'],
+ $value['side']
+ );
+ }
+
+ throw new \Exception('Unknown attribute type: '.$value['type']);
+ }
+
+ private function exportDatabases(int $batchSize)
+ {
+ $databaseClient = new Databases($this->client);
+
+ $lastDocument = null;
+
+ // Transfer Databases
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+ $databases = [];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $databaseClient->list($queries);
+
+ foreach ($response['databases'] as $database) {
+ $newDatabase = new Database(
+ $database['name'],
+ $database['$id']
+ );
+
+ $databases[] = $newDatabase;
+ }
+
+ $this->callback($databases);
+
+ if (count($databases) < $batchSize) {
+ break;
+ }
+ }
+ }
+
+ private function exportCollections(int $batchSize)
+ {
+ $databaseClient = new Databases($this->client);
+
+ // Transfer Collections
+ $lastDocument = null;
+
+ $databases = $this->cache->get(Database::getName());
+ foreach ($databases as $database) {
+ /** @var Database $database */
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+ $collections = [];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $databaseClient->listCollections(
+ $database->getId(),
+ $queries
+ );
+
+ foreach ($response['collections'] as $collection) {
+ $newCollection = new Collection(
+ $database,
+ $collection['name'],
+ $collection['$id'],
+ $collection['documentSecurity'],
+ $collection['$permissions']
+ );
+
+ $collections[] = $newCollection;
+ }
+
+ $this->callback($collections);
+
+ if (count($collections) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function exportAttributes(int $batchSize)
+ {
+ $databaseClient = new Databases($this->client);
+
+ // Transfer Attributes
+ $lastDocument = null;
+ $collections = $this->cache->get(Collection::getName());
+ /** @var Collection[] $collections */
+ foreach ($collections as $collection) {
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+ $attributes = [];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $databaseClient->listAttributes(
+ $collection->getDatabase()->getId(),
+ $collection->getId(),
+ $queries
+ );
+
+ foreach ($response['attributes'] as $attribute) {
+ $attributes[] = $this->convertAttribute($attribute, $collection);
+ }
+
+ $this->callback($attributes);
+
+ if (count($attributes) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function exportIndexes(int $batchSize)
+ {
+ $databaseClient = new Databases($this->client);
+
+ $collections = $this->cache->get(Resource::TYPE_COLLECTION);
+
+ // Transfer Indexes
+ $lastDocument = null;
+ foreach ($collections as $collection) {
+ /** @var Collection $collection */
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+ $indexes = [];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $databaseClient->listIndexes(
+ $collection->getDatabase()->getId(),
+ $collection->getId(),
+ $queries
+ );
+
+ foreach ($response['indexes'] as $index) {
+ $indexes[] = new Index(
+ 'unique()',
+ $index['key'],
+ $collection,
+ $index['type'],
+ $index['attributes'],
+ $index['orders']
+ );
+ }
+
+ $this->callback($indexes);
+
+ if (count($indexes) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function calculateTypes(array $user): array
+ {
+ if (empty($user['email']) && empty($user['phone'])) {
+ return [User::TYPE_ANONYMOUS];
+ }
+
+ $types = [];
+
+ if (!empty($user['email'])) {
+ $types[] = User::TYPE_EMAIL;
+ }
+
+ if (!empty($user['phone'])) {
+ $types[] = User::TYPE_PHONE;
+ }
+
+ return $types;
+ }
+
+ protected function exportGroupStorage(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $this->exportBuckets($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $this->exportFiles($batchSize);
+ }
+ }
+
+ private function exportBuckets(int $batchSize)
+ {
+ //TODO: Impl batching
+ $storageClient = new Storage($this->client);
+
+ $buckets = $storageClient->listBuckets();
+
+ $convertedBuckets = [];
+
+ foreach ($buckets['buckets'] as $bucket) {
+ $convertedBuckets[] = new Bucket(
+ $bucket['$id'],
+ $bucket['$permissions'],
+ $bucket['fileSecurity'],
+ $bucket['name'],
+ $bucket['enabled'],
+ $bucket['maximumFileSize'],
+ $bucket['allowedFileExtensions'],
+ $bucket['compression'],
+ $bucket['encryption'],
+ $bucket['antivirus'],
+ );
+ }
+
+ if (empty($convertedBuckets)) {
+ return;
+ }
+
+ $this->callback($convertedBuckets);
+ }
+
+ private function exportFiles(int $batchSize)
+ {
+ $storageClient = new Storage($this->client);
+
+ $buckets = $this->cache->get(Bucket::getName());
+ foreach ($buckets as $bucket) {
+ /** @var Bucket $bucket */
+ $lastDocument = null;
+
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $storageClient->listFiles(
+ $bucket->getId(),
+ $queries
+ );
+
+ foreach ($response['files'] as $file) {
+ $this->exportFileData(new File(
+ $file['$id'],
+ $bucket,
+ $file['name'],
+ $file['signature'],
+ $file['mimeType'],
+ $file['$permissions'],
+ $file['sizeOriginal'],
+ ));
+
+ $lastDocument = $file['$id'];
+ }
+
+ if (count($response['files']) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function exportFileData(File $file)
+ {
+ // Set the chunk size (5MB)
+ $start = 0;
+ $end = Transfer::STORAGE_MAX_CHUNK_SIZE - 1;
+
+ // Get the file size
+ $fileSize = $file->getSize();
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+
+ // Loop until the entire file is downloaded
+ while ($start < $fileSize) {
+ $chunkData = $this->call(
+ 'GET',
+ "/storage/buckets/{$file->getBucket()->getId()}/files/{$file->getId()}/download",
+ ['range' => "bytes=$start-$end"]
+ );
+
+ // Send the chunk to the callback function
+ $file->setData($chunkData)
+ ->setStart($start)
+ ->setEnd($end);
+
+ $this->callback([$file]);
+
+ // Update the range
+ $start += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ $end += Transfer::STORAGE_MAX_CHUNK_SIZE;
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+ }
+ }
+
+ protected function exportGroupFunctions(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_FUNCTION, $resources)) {
+ $this->exportFunctions($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_DEPLOYMENT, $resources)) {
+ $this->exportDeployments($batchSize);
+ }
+ }
+
+ private function exportFunctions(int $batchSize)
+ {
+ //TODO: Implement batching
+ $functionsClient = new Functions($this->client);
+
+ $functions = $functionsClient->list();
+
+ if ($functions['total'] === 0) {
+ return;
+ }
+
+ $convertedResources = [];
+
+ foreach ($functions['functions'] as $function) {
+ $convertedFunc = new Func(
+ $function['name'],
+ $function['$id'],
+ $function['runtime'],
+ $function['execute'],
+ $function['enabled'],
+ $function['events'],
+ $function['schedule'],
+ $function['timeout']
+ );
+
+ $convertedResources[] = $convertedFunc;
+
+ foreach ($function['vars'] as $var) {
+ $convertedResources[] = new EnvVar(
+ $convertedFunc,
+ $var['key'],
+ $var['value'],
+ );
+ }
+ }
+
+ $this->callback($convertedResources);
+ }
+
+ private function exportDeployments(int $batchSize)
+ {
+ $functionsClient = new Functions($this->client);
+
+ $functions = $this->cache->get(Func::getName());
+
+ foreach ($functions as $func) {
+ /** @var Func $func */
+ $lastDocument = null;
+ while (true) {
+ $queries = [Query::limit($batchSize)];
+
+ if ($lastDocument) {
+ $queries[] = Query::cursorAfter($lastDocument);
+ }
+
+ $response = $functionsClient->listDeployments(
+ $func->getId(),
+ $queries
+ );
+
+ foreach ($response['deployments'] as $deployment) {
+ $this->exportDeploymentData($func, $deployment);
+
+ $lastDocument = $deployment['$id'];
+ }
+
+ if (count($response['deployments']) < $batchSize) {
+ break;
+ }
+ }
+ }
+ }
+
+ private function exportDeploymentData(Func $func, array $deployment)
+ {
+ // Set the chunk size (5MB)
+ $start = 0;
+ $end = Transfer::STORAGE_MAX_CHUNK_SIZE - 1;
+
+ // Get the file size
+ $fileSize = $deployment['size'];
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+
+ $deployment = new Deployment(
+ $deployment['$id'],
+ $func,
+ $fileSize,
+ $deployment['entrypoint'],
+ $start,
+ $end,
+ '',
+ $deployment['activate']
+ );
+
+ $deployment->setInternalId($deployment->getId());
+
+ // Loop until the entire file is downloaded
+ while ($start < $fileSize) {
+ $chunkData = $this->call(
+ 'GET',
+ "/functions/{$func->getId()}/deployments/{$deployment->getInternalId()}/download",
+ ['range' => "bytes=$start-$end"]
+ );
+
+ // Send the chunk to the callback function
+ $deployment->setData($chunkData);
+ $deployment->setStart($start);
+ $deployment->setEnd($end);
+ $this->callback([$deployment]);
+
+ // Update the range
+ $start += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ $end += Transfer::STORAGE_MAX_CHUNK_SIZE;
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+ }
+ }
+}
diff --git a/src/Transfer/Sources/Firebase.php b/src/Transfer/Sources/Firebase.php
new file mode 100644
index 00000000..c5a3f501
--- /dev/null
+++ b/src/Transfer/Sources/Firebase.php
@@ -0,0 +1,523 @@
+serviceAccount = $serviceAccount;
+ $this->projectID = $serviceAccount['project_id'];
+ }
+
+ public static function getName(): string
+ {
+ return 'Firebase';
+ }
+
+ private function base64UrlEncode($data)
+ {
+ return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
+ }
+
+ private function calculateJWT(): string
+ {
+ $jwtClaim = [
+ 'iss' => $this->serviceAccount['client_email'],
+ 'scope' => 'https://www.googleapis.com/auth/firebase https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/datastore',
+ 'exp' => time() + 3600,
+ 'iat' => time(),
+ 'aud' => 'https://oauth2.googleapis.com/token',
+ ];
+
+ $jwtHeader = [
+ 'alg' => 'RS256',
+ 'typ' => 'JWT',
+ ];
+
+ $jwtPayload = $this->base64UrlEncode(json_encode($jwtHeader)).'.'.$this->base64UrlEncode(json_encode($jwtClaim));
+
+ $jwtSignature = '';
+ openssl_sign($jwtPayload, $jwtSignature, $this->serviceAccount['private_key'], 'sha256');
+ $jwtSignature = $this->base64UrlEncode($jwtSignature);
+
+ return $jwtPayload.'.'.$jwtSignature;
+ }
+
+ /**
+ * Computes the JWT then fetches an auth token from the Google OAuth2 API which is valid for an hour
+ */
+ private function authenticate()
+ {
+ if (time() < $this->tokenExpires) {
+ return;
+ }
+
+ try {
+ $response = parent::call('POST', 'https://oauth2.googleapis.com/token', [
+ 'Content-Type' => 'application/x-www-form-urlencoded',
+ ], [
+ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
+ 'assertion' => $this->calculateJWT(),
+ ]);
+
+ $this->currentToken = $response['access_token'];
+ $this->tokenExpires = time() + $response['expires_in'];
+ $this->headers['Authorization'] = 'Bearer '.$this->currentToken;
+ } catch (\Exception $e) {
+ throw new \Exception('Failed to authenticate with Firebase: '.$e->getMessage());
+ }
+ }
+
+ protected function call(string $method, string $path = '', array $headers = [], array $params = []): array|string
+ {
+ $this->authenticate();
+
+ return parent::call($method, $path, $headers, $params);
+ }
+
+ /**
+ * Get Supported Resources
+ */
+ static function getSupportedResources(): array
+ {
+ return [
+ // Auth
+ Resource::TYPE_USER,
+
+ // Database
+ Resource::TYPE_DATABASE,
+ Resource::TYPE_COLLECTION,
+ Resource::TYPE_ATTRIBUTE,
+ Resource::TYPE_DOCUMENT,
+
+ // Storage
+ Resource::TYPE_BUCKET,
+ Resource::TYPE_FILE,
+ ];
+ }
+
+ public function report(array $resources = []): array
+ {
+ throw new \Exception('Not implemented');
+ }
+
+ protected function exportGroupAuth(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $this->exportUsers($batchSize);
+ }
+ }
+
+ private function exportUsers(int $batchSize)
+ {
+ // Fetch our Hash Config
+ $hashConfig = ($this->call('GET', 'https://identitytoolkit.googleapis.com/admin/v2/projects/'.$this->projectID.'/config'))['signIn']['hashConfig'];
+
+ $nextPageToken = null;
+
+ // Transfer Users
+ while (true) {
+ $users = [];
+
+ $request = [
+ 'targetProjectId' => $this->projectID,
+ 'maxResults' => $batchSize,
+ ];
+
+ if ($nextPageToken) {
+ $request['nextPageToken'] = $nextPageToken;
+ }
+
+ $response = $this->call('POST', 'https://identitytoolkit.googleapis.com/identitytoolkit/v3/relyingparty/downloadAccount', [
+ 'Content-Type' => 'application/json',
+ ], $request);
+
+ $result = $response['users'];
+ $nextPageToken = $response['nextPageToken'] ?? null;
+
+ foreach ($result as $user) {
+ $users[] = new User(
+ $user['localId'] ?? '',
+ $user['email'] ?? '',
+ $user['displayName'] ?? $user['email'] ?? '',
+ new Hash($user['passwordHash'] ?? '', $user['salt'] ?? '', Hash::ALGORITHM_SCRYPT_MODIFIED, $hashConfig['saltSeparator'], $hashConfig['signerKey']),
+ $user['phoneNumber'] ?? '',
+ $this->calculateUserType($user['providerUserInfo'] ?? []),
+ '',
+ $user['emailVerified'],
+ false, // Can't get phone number status on firebase :/
+ $user['disabled']
+ );
+ }
+
+ $this->callback($users);
+
+ if (count($result) < $batchSize) {
+ break;
+ }
+ }
+ }
+
+ private function calculateUserType(array $providerData): array
+ {
+ if (count($providerData) === 0) {
+ return [User::TYPE_ANONYMOUS];
+ }
+
+ $types = [];
+
+ foreach ($providerData as $provider) {
+ switch ($provider['providerId']) {
+ case 'password':
+ $types[] = User::TYPE_EMAIL;
+ break;
+ case 'phone':
+ $types[] = User::TYPE_PHONE;
+ break;
+ default:
+ $types[] = User::TYPE_OAUTH;
+ break;
+ }
+ }
+
+ return $types;
+ }
+
+ protected function exportGroupDatabases(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $database = new Database('default', '(default)');
+ $this->callback([$database]);
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $this->exportDB($batchSize, in_array(Resource::TYPE_DOCUMENT, $resources), $database);
+ }
+ }
+
+ private function exportDB(int $batchSize, bool $pushDocuments, Database $database)
+ {
+ $baseURL = "https://firestore.googleapis.com/v1/projects/{$this->projectID}/databases/(default)/documents";
+
+ $nextPageToken = null;
+ $allCollections = [];
+ while (true) {
+ $collections = [];
+
+ $result = $this->call('POST', $baseURL.':listCollectionIds', [
+ 'Content-Type' => 'application/json',
+ ], [
+ 'pageSize' => $batchSize,
+ 'pageToken' => $nextPageToken,
+ ]);
+
+ // Transfer Collections
+ foreach ($result['collectionIds'] as $collection) {
+ $collections[] = new Collection($database, $collection, $collection);
+ }
+
+ if (count($collections) !== 0) {
+ $allCollections = array_merge($allCollections, $collections);
+ $this->callback($collections);
+ } else {
+ return;
+ }
+
+ // Transfer Documents and Calculate Schema
+ foreach ($collections as $collection) {
+ $this->exportCollection($collection, $batchSize, $pushDocuments);
+ }
+
+ if (count($result['collectionIds']) < $batchSize) {
+ break;
+ }
+
+ $nextPageToken = $result['nextPageToken'] ?? null;
+ }
+ }
+
+ private function convertAttribute(Collection $collection, string $key, array $field): Attribute
+ {
+ switch (true) {
+ case array_key_exists('booleanValue', $field):
+ return new Boolean($key, $collection, false, false, null);
+ case array_key_exists('bytesValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000);
+ case array_key_exists('doubleValue', $field):
+ return new Decimal($key, $collection, false, false, null);
+ case array_key_exists('integerValue', $field):
+ return new Integer($key, $collection, false, false, null);
+ case array_key_exists('mapValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000);
+ case array_key_exists('nullValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000);
+ case array_key_exists('referenceValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000); //TODO: This should be a reference attribute
+ case array_key_exists('stringValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000);
+ case array_key_exists('timestampValue', $field):
+ return new DateTime($key, $collection, false, false, null);
+ case array_key_exists('geoPointValue', $field):
+ return new Text($key, $collection, false, false, null, 1000000);
+ case array_key_exists('arrayValue', $field):
+ return $this->calculateArrayType($collection, $key, $field['arrayValue']);
+ default:
+ throw new \Exception('Unknown field type');
+ }
+ }
+
+ private function calculateArrayType(Collection $collection, string $key, array $data): Attribute
+ {
+ $isSameType = true;
+ $previousType = null;
+
+ foreach ($data['values'] as $field) {
+ if (!$previousType) {
+ $previousType = $this->convertAttribute($collection, $key, $field);
+ } elseif ($previousType->getName() != ($this->convertAttribute($collection, $key, $field))->getName()) {
+ $isSameType = false;
+ break;
+ }
+ }
+
+ if ($isSameType) {
+ $previousType->setArray(true);
+
+ return $previousType;
+ } else {
+ return new Text($key, $collection, false, true, null, 1000000);
+ }
+ }
+
+ private function exportCollection(Collection $collection, int $batchSize, bool $transferDocuments)
+ {
+ $resourceURL = 'https://firestore.googleapis.com/v1/projects/'.$this->projectID.'/databases/'.$collection->getDatabase()->getId().'/documents/'.$collection->getId();
+
+ $nextPageToken = null;
+
+ $knownSchema = [];
+
+ // Transfer Documents and Calculate Schemas
+ while (true) {
+ $documents = [];
+
+ $result = $this->call('GET', $resourceURL, [
+ 'Content-Type' => 'application/json',
+ ], [
+ 'pageSize' => $batchSize,
+ 'pageToken' => $nextPageToken,
+ ]);
+
+ if (empty($result)) {
+ break;
+ }
+
+ // Calculate Schema and handle subcollections
+ $documentSchema = [];
+ foreach ($result['documents'] as $document) {
+ if (!isset($document['fields'])) {
+ continue; //TODO: Transfer Empty Documents
+ }
+
+ foreach ($document['fields'] as $key => $field) {
+ if (!isset($documentSchema[$key])) {
+ $documentSchema[$key] = $this->convertAttribute($collection, $key, $field);
+ }
+ }
+
+ $documents[] = $this->convertDocument($collection, $document);
+ }
+
+ // Transfer Documents
+ if ($transferDocuments) {
+ $this->callback($documents);
+ }
+
+ if (count($result['documents']) < $batchSize) {
+ break;
+ }
+
+ $nextPageToken = $result['nextPageToken'] ?? null;
+ }
+ }
+
+ private function calculateValue(array $field)
+ {
+ if (array_key_exists('booleanValue', $field)) {
+ return $field['booleanValue'];
+ } elseif (array_key_exists('bytesValue', $field)) {
+ return $field['bytesValue'];
+ } elseif (array_key_exists('doubleValue', $field)) {
+ return $field['doubleValue'];
+ } elseif (array_key_exists('integerValue', $field)) {
+ return $field['integerValue'];
+ } elseif (array_key_exists('mapValue', $field)) {
+ return $field['mapValue'];
+ } elseif (array_key_exists('nullValue', $field)) {
+ return $field['nullValue'];
+ } elseif (array_key_exists('referenceValue', $field)) {
+ return $field['referenceValue']; //TODO: This should be a reference attribute
+ } elseif (array_key_exists('stringValue', $field)) {
+ return $field['stringValue'];
+ } elseif (array_key_exists('timestampValue', $field)) {
+ return $field['timestampValue'];
+ } elseif (array_key_exists('geoPointValue', $field)) {
+ return $field['geoPointValue'];
+ } elseif (array_key_exists('arrayValue', $field)) {
+ //TODO:
+ } else {
+ throw new \Exception('Unknown field type');
+ }
+ }
+
+ private function convertDocument(Collection $collection, array $document): Document
+ {
+ $data = [];
+ foreach ($document['fields'] as $key => $field) {
+ $data[$key] = $this->calculateValue($field);
+ }
+
+ return new Document($document['name'], $collection->getDatabase(), $collection, $data, []);
+ }
+
+ protected function exportGroupStorage(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $this->exportBuckets($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $this->exportFiles($batchSize);
+ }
+ }
+
+ private function exportBuckets(int $batchsize)
+ {
+ $endpoint = 'https://storage.googleapis.com/storage/v1/b';
+
+ $nextPageToken = null;
+
+ while (true) {
+ $result = $this->call('GET', $endpoint, [], [
+ 'project' => $this->projectID,
+ 'maxResults' => $batchsize,
+ 'pageToken' => $nextPageToken,
+ 'alt' => 'json',
+ ]);
+
+ if (empty($result)) {
+ break;
+ }
+
+ foreach ($result['items'] as $bucket) {
+ $this->callback([new Bucket($bucket['id'], [], false, $bucket['name'])]);
+ }
+
+ if (!isset($result['nextPageToken'])) {
+ break;
+ }
+
+ $nextPageToken = $result['nextPageToken'] ?? null;
+ }
+ }
+
+ private function exportFiles(int $batchsize)
+ {
+ $buckets = $this->cache->get(Bucket::getName());
+
+ foreach ($buckets as $bucket) {
+ /** @var Bucket $bucket */
+ $endpoint = 'https://storage.googleapis.com/storage/v1/b/'.$bucket->getId().'/o';
+
+ $nextPageToken = null;
+
+ while (true) {
+ $result = $this->call('GET', $endpoint, [
+ 'Content-Type' => 'application/json',
+ ], [
+ 'pageSize' => $batchsize,
+ 'pageToken' => $nextPageToken,
+ ]);
+
+ if (empty($result)) {
+ break;
+ }
+
+ if (!isset($result['items'])) {
+ break;
+ }
+
+ foreach ($result['items'] as $item) {
+ $this->exportFile(new File($item['name'], $bucket, $item['name']));
+ }
+
+ if (count($result['items']) < $batchsize) {
+ break;
+ }
+
+ $nextPageToken = $result['nextPageToken'] ?? null;
+ }
+ }
+ }
+
+ private function exportFile(File $file)
+ {
+ $endpoint = 'https://storage.googleapis.com/storage/v1/b/'.$file->getBucket()->getId().'/o/'.$file->getId().'?alt=media';
+ $start = 0;
+ $end = Transfer::STORAGE_MAX_CHUNK_SIZE - 1;
+
+ while (true) {
+ $result = $this->call('GET', $endpoint, [
+ 'Range' => 'bytes='.$start.'-'.$end,
+ ]);
+
+ if (empty($result)) {
+ break;
+ }
+
+ $file->setData($result)
+ ->setStart($start)
+ ->setEnd($end);
+
+ $this->callback([$file]);
+
+ if (strlen($result) < Transfer::STORAGE_MAX_CHUNK_SIZE) {
+ break;
+ }
+
+ $start += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ $end += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ }
+ }
+
+ protected function exportGroupFunctions(int $batchSize, array $resources)
+ {
+ throw new \Exception('Not implemented');
+ }
+}
diff --git a/src/Transfer/Sources/NHost.php b/src/Transfer/Sources/NHost.php
new file mode 100644
index 00000000..e3f9b5e2
--- /dev/null
+++ b/src/Transfer/Sources/NHost.php
@@ -0,0 +1,681 @@
+subdomain = $subdomain;
+ $this->region = $region;
+ $this->adminSecret = $adminSecret;
+ $this->databaseName = $databaseName;
+ $this->username = $username;
+ $this->password = $password;
+ $this->port = $port;
+ }
+
+ public function getDatabase(): PDO
+ {
+ if (!$this->pdo) {
+ try {
+ $this->pdo = new \PDO('pgsql:host=' . $this->subdomain . '.db.' . $this->region . '.nhost.run' . ';port=' . $this->port . ';dbname=' . $this->databaseName, $this->username, $this->password);
+ } catch (\PDOException $e) {
+ throw new \Exception('Failed to connect to database: ' . $e->getMessage());
+ }
+ }
+
+ return $this->pdo;
+ }
+
+ public static function getName(): string
+ {
+ return 'NHost';
+ }
+
+ /**
+ * Get Supported Resources
+ */
+ static function getSupportedResources(): array
+ {
+ return [
+ // Auth
+ Resource::TYPE_USER,
+
+ // Database
+ Resource::TYPE_DATABASE,
+ Resource::TYPE_COLLECTION,
+ Resource::TYPE_ATTRIBUTE,
+ Resource::TYPE_INDEX,
+ Resource::TYPE_DOCUMENT,
+
+ // Storage
+ Resource::TYPE_BUCKET,
+ Resource::TYPE_FILE,
+ ];
+ }
+
+ public function report(array $resources = []): array
+ {
+ $report = [];
+
+ if (empty($resources)) {
+ $resources = $this->getSupportedResources();
+ }
+
+ try {
+ $db = $this->getDatabase();
+ } catch (\PDOException $e) {
+ throw new \Exception('Failed to connect to database. PDO Code: ' . $e->getCode() . ' Error: ' . $e->getMessage());
+ }
+
+ if (!empty($db->errorCode())) {
+ throw new \Exception('Failed to connect to database. PDO Code: ' . $db->errorCode() . (empty($db->errorInfo()[2]) ? '' : ' Error: ' . $db->errorInfo()[2]));
+ }
+
+ // Auth
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM auth.users');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access users table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_USER] = $statement->fetchColumn();
+ }
+
+ // Databases
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $report[Resource::TYPE_DATABASE] = 1;
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access tables table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_COLLECTION] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access columns table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_ATTRIBUTE] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM pg_indexes WHERE schemaname = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access indexes table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_INDEX] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access tables table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_DOCUMENT] = $statement->fetchColumn();
+ }
+
+ // Storage
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM storage.buckets');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access buckets table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_BUCKET] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $statement = $db->prepare('SELECT COUNT(*) FROM storage.files');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access files table. Error: ' . $statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_FILE] = $statement->fetchColumn();
+ }
+
+ return $report;
+ }
+
+ protected function exportGroupAuth(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $this->exportUsers($batchSize);
+ }
+ }
+
+ private function exportUsers(int $batchSize)
+ {
+ $db = $this->getDatabase();
+
+ $total = $db->query('SELECT COUNT(*) FROM auth.users')->fetchColumn();
+
+ $offset = 0;
+
+ while ($offset < $total) {
+ $statement = $db->prepare('SELECT * FROM auth.users order by created_at LIMIT :limit OFFSET :offset');
+ $statement->bindValue(':limit', $batchSize, \PDO::PARAM_INT);
+ $statement->bindValue(':offset', $offset, \PDO::PARAM_INT);
+ $statement->execute();
+
+ $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ $transferUsers = [];
+
+ foreach ($users as $user) {
+ $transferUsers[] = new User(
+ $user['id'],
+ $user['email'] ?? '',
+ $user['display_name'] ?? '',
+ new Hash($user['password_hash'], '', Hash::ALGORITHM_BCRYPT),
+ $user['phone_number'] ?? '',
+ $this->calculateUserTypes($user),
+ '',
+ $user['email_verified'],
+ $user['phone_number_verified'],
+ $user['disabled'],
+ []
+ );
+ }
+
+ $this->callback($transferUsers);
+ }
+ }
+
+ protected function exportGroupDatabases(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $this->exportDatabases($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $this->exportCollections($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $this->exportAttributes($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $this->exportDocuments($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $this->exportIndexes($batchSize);
+ }
+ }
+
+ private function exportDatabases(int $batchSize): void
+ {
+ // We'll only transfer the public database for now, since it's the only one that exists by default.
+ //TODO: Handle edge cases where there are user created databases and data.
+ $transferDatabase = new Database('public', 'public');
+ $this->callback([$transferDatabase]);
+ }
+
+ private function exportCollections(int $batchSize)
+ {
+ $databases = $this->cache->get(Database::getName());
+ $db = $this->getDatabase();
+
+ foreach ($databases as $database) {
+ /** @var Database $database */
+ $statement = $db->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = :database');
+ $statement->execute([':database' => $database->getName()]);
+ $total = $statement->fetchColumn();
+
+ $offset = 0;
+
+ while ($offset < $total) {
+ $statement = $db->prepare('SELECT table_name FROM information_schema.tables WHERE table_schema = \'public\' order by table_name LIMIT :limit OFFSET :offset');
+ $statement->execute([':limit' => $batchSize, ':offset' => $offset]);
+
+ $tables = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ $transferCollections = [];
+
+ foreach ($tables as $table) {
+ $transferCollections[] = new Collection($database, $table['table_name'], $table['table_name']);
+ }
+
+ $this->callback($transferCollections);
+ }
+ }
+ }
+
+ private function exportAttributes(int $batchSize)
+ {
+ $collections = $this->cache->get(Collection::getName());
+ $db = $this->getDatabase();
+
+ foreach ($collections as $collection) {
+ /** @var Collection $collection */
+ $statement = $db->prepare('SELECT * FROM information_schema."columns" where "table_name" = :tableName');
+ $statement->bindValue(':tableName', $collection->getCollectionName(), \PDO::PARAM_STR);
+ $statement->execute();
+ $databaseCollection = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $attributes = [];
+
+ foreach ($databaseCollection as $column) {
+ $attributes[] = $this->convertAttribute($column, $collection);
+ }
+
+ $this->callback($attributes);
+ }
+ }
+
+ private function exportIndexes(int $batchSize)
+ {
+ $collections = $this->cache->get(Collection::getName());
+ $db = $this->getDatabase();
+
+ foreach ($collections as $collection) {
+ /** @var Collection $collection */
+ $indexStatement = $db->prepare('SELECT indexname, indexdef FROM pg_indexes WHERE tablename = :tableName');
+ $indexStatement->bindValue(':tableName', $collection->getCollectionName(), \PDO::PARAM_STR);
+ $indexStatement->execute();
+
+ $databaseIndexes = $indexStatement->fetchAll(\PDO::FETCH_ASSOC);
+ $indexes = [];
+ foreach ($databaseIndexes as $index) {
+ $result = $this->convertIndex($index, $collection);
+
+ $indexes[] = $result;
+ }
+
+ $this->callback($indexes);
+ }
+ }
+
+ private function exportDocuments(int $batchSize)
+ {
+ $databases = $this->cache->get(Database::getName());
+ $db = $this->getDatabase();
+
+ foreach ($databases as $database) {
+ /** @var Database $database */
+ $collections = $database->getCollections();
+
+ foreach ($collections as $collection) {
+ $total = $db->query('SELECT COUNT(*) FROM ' . $collection->getCollectionName())->fetchColumn();
+
+ $offset = 0;
+
+ while ($offset < $total) {
+ $statement = $db->prepare('SELECT row_to_json(t) FROM (SELECT * FROM ' . $collection->getCollectionName() . ' LIMIT :limit OFFSET :offset) t;');
+ $statement->bindValue(':limit', $batchSize, \PDO::PARAM_INT);
+ $statement->bindValue(':offset', $offset, \PDO::PARAM_INT);
+ $statement->execute();
+
+ $documents = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ $transferDocuments = [];
+
+ $attributes = $this->cache->get(Attribute::getName());
+ $collectionAttributes = array_filter($attributes, function (Attribute $attribute) use ($collection) {
+ return $attribute->getId() === $collection->getId();
+ });
+
+ foreach ($documents as $document) {
+ $data = json_decode($document['row_to_json'], true);
+
+ $processedData = [];
+ foreach ($collectionAttributes as $attribute) {
+ /** @var Attribute $attribute */
+ if (!$attribute->getArray() && \is_array($data[$attribute->getKey()])) {
+ $processedData[$attribute->getKey()] = json_encode($data[$attribute->getKey()]);
+ } else {
+ $processedData[$attribute->getKey()] = $data[$attribute->getKey()];
+ }
+ }
+
+ $transferDocuments[] = new Document('unique()', $database, $collection, $processedData);
+ }
+
+ $this->callback($transferDocuments);
+ }
+ }
+ }
+ }
+
+ private function convertAttribute(array $column, Collection $collection): Attribute
+ {
+ $isArray = $column['data_type'] === 'ARRAY';
+
+ switch ($isArray ? str_replace('_', '', $column['udt_name']) : $column['data_type']) {
+ // Numbers
+ case 'boolean':
+ case 'bool':
+ return new Boolean($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, $column['column_default']);
+ case 'smallint':
+ case 'int2':
+ return new Integer($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, $column['column_default'], -32768, 32767);
+ case 'integer':
+ case 'int4':
+ return new Integer($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, $column['column_default'], -2147483648, 2147483647);
+ case 'bigint':
+ case 'int8':
+ case 'numeric':
+ return new Integer($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, $column['column_default']);
+ case 'decimal':
+ case 'real':
+ case 'double precision':
+ case 'float4':
+ case 'float8':
+ case 'money':
+ return new Decimal($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, $column['column_default']);
+ // Time (Conversion happens with documents)
+ case 'timestamp with time zone':
+ case 'date':
+ case 'time with time zone':
+ case 'timestamp without time zone':
+ case 'timestamptz':
+ case 'timestamp':
+ case 'time':
+ case 'timetz':
+ case 'interval':
+ return new DateTime($column['column_name'], $collection, $column['is_nullable'] === 'NO', $isArray, null);
+ break;
+ // Strings and Objects
+ case 'uuid':
+ case 'character varying':
+ case 'text':
+ case 'character':
+ case 'json':
+ case 'jsonb':
+ case 'varchar':
+ case 'bytea':
+ return new Text(
+ $column['column_name'],
+ $collection,
+ $column['is_nullable'] === 'NO',
+ $isArray,
+ $column['column_default'],
+ $column['character_maximum_length'] ?? $column['character_octet_length'] ?? 10485760
+ );
+ break;
+ default:
+ return new Text(
+ $column['column_name'],
+ $collection,
+ $column['is_nullable'] === 'NO',
+ $isArray,
+ $column['column_default'],
+ $column['character_maximum_length'] ?? $column['character_octet_length'] ?? 10485760
+ );
+ break;
+ }
+ }
+
+ private function convertIndex(array $index, Collection $collection): Index|false
+ {
+ $pattern = "/CREATE (?\w+)? INDEX (?\w+) ON (?\w+\.\w+) USING (?\w+) \((?\w+)\)/";
+
+ if (\preg_match($pattern, $index['indexdef'], $matches)) {
+ // We only support BTree indexes
+ if ($matches['method'] !== 'btree') {
+ //TODO: Figure out how to deal with warnings
+ // Add warning here for unsupported index type
+ return false;
+ }
+
+ $type = '';
+
+ if ($matches['type'] === 'UNIQUE') {
+ $type = Index::TYPE_UNIQUE;
+ } elseif ($matches['type'] === 'FULLTEXT') {
+ $type = Index::TYPE_FULLTEXT;
+ } else {
+ $type = Index::TYPE_KEY;
+ }
+
+ $attributes = [];
+ $order = [];
+
+ $targets = explode(',', $matches['columns']);
+
+ foreach ($targets as $target) {
+ if (\strpos($target, ' ') !== false) {
+ $target = \explode(' ', $target);
+ $attributes[] = $target[0];
+ $order[] = $target[1];
+ } else {
+ $attributes[] = $target;
+ $order[] = 'ASC';
+ }
+ }
+
+ return new Index($matches['name'], $matches['name'], $collection, $type, $attributes, $order);
+ } else {
+ return false;
+ }
+ }
+
+ private function calculateUserTypes(array $user): array
+ {
+ if (empty($user['password_hash']) && empty($user['phone_number'])) {
+ return [User::TYPE_ANONYMOUS];
+ }
+
+ $types = [];
+
+ if (!empty($user['password_hash'])) {
+ $types[] = User::TYPE_EMAIL;
+ }
+
+ if (!empty($user['phone_number'])) {
+ $types[] = User::TYPE_PHONE;
+ }
+
+ return $types;
+ }
+
+ protected function exportGroupStorage(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $this->exportBuckets($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $this->exportFiles($batchSize);
+ }
+ }
+
+ protected function exportBuckets(int $batchSize)
+ {
+ $db = $this->getDatabase();
+ $total = $db->query('SELECT COUNT(*) FROM storage.buckets')->fetchColumn();
+
+ $offset = 0;
+
+ while ($offset < $total) {
+ $statement = $db->prepare('SELECT * FROM storage.buckets order by created_at LIMIT :limit OFFSET :offset');
+ $statement->bindValue(':limit', $batchSize, \PDO::PARAM_INT);
+ $statement->bindValue(':offset', $offset, \PDO::PARAM_INT);
+ $statement->execute();
+
+ $buckets = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ $transferBuckets = [];
+
+ foreach ($buckets as $bucket) {
+ $transferBuckets[] = new Bucket(
+ $bucket['id'],
+ [],
+ false,
+ $bucket['id'],
+ true,
+ $bucket['max_upload_file_size'],
+ [],
+ '',
+ false,
+ false
+ );
+ }
+
+ $this->callback($transferBuckets);
+ }
+ }
+
+ private function exportFiles(int $batchSize)
+ {
+ $buckets = $this->cache->get(Bucket::getName());
+ $db = $this->getDatabase();
+
+ foreach ($buckets as $bucket) {
+ /** @var Bucket $bucket */
+ $totalStatement = $db->prepare('SELECT COUNT(*) FROM storage.files WHERE bucket_id=:bucketId');
+ $totalStatement->execute([':bucketId' => $bucket->getId()]);
+ $total = $totalStatement->fetchColumn();
+
+ $offset = 0;
+ while ($offset < $total) {
+ $statement = $db->prepare('SELECT * FROM storage.files WHERE bucket_id=:bucketId order by created_at LIMIT :limit OFFSET :offset');
+ $statement->bindValue(':limit', $batchSize, \PDO::PARAM_INT);
+ $statement->bindValue(':offset', $offset, \PDO::PARAM_INT);
+ $statement->bindValue(':bucketId', $bucket->getId(), \PDO::PARAM_STR);
+ $statement->execute();
+
+ $files = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ foreach ($files as $file) {
+ $this->exportFile(new File(
+ $file['id'],
+ $bucket,
+ $file['name'],
+ '',
+ $file['mime_type'],
+ [],
+ $file['size'],
+ ));
+ }
+ }
+ }
+ }
+
+ private function exportFile(File $file)
+ {
+ $url = "https://{$this->subdomain}.storage.{$this->region}.nhost.run";
+ $start = 0;
+ $end = Transfer::STORAGE_MAX_CHUNK_SIZE - 1;
+
+ $fileSize = $file->getSize();
+ $response = $this->call('GET', $url . "/v1/files/{$file->getId()}/presignedurl", [
+ 'X-Hasura-Admin-Secret' => $this->adminSecret,
+ ]);
+
+ $fileUrl = $response['url'];
+ $refreshTime = \time() + $response['expiration'];
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+
+ while ($start < $fileSize) {
+ if (\time() > $refreshTime) {
+ $response = $this->call('GET', "/v1/files/{$file->getId()}/presignedurl", [
+ 'X-Hasura-Admin-Secret' => $this->adminSecret,
+ ]);
+
+ $fileUrl = $response['url'];
+ $refreshTime = \time() + $response['expiration'];
+ }
+
+ $chunkData = $this->call(
+ 'GET',
+ $fileUrl,
+ ['range' => "bytes=$start-$end"]
+ );
+
+ $file->setData($chunkData)
+ ->setStart($start)
+ ->setEnd($end);
+
+ $this->callback([$file]);
+
+ $start += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ $end += Transfer::STORAGE_MAX_CHUNK_SIZE;
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+ }
+ }
+
+ protected function exportGroupFunctions(int $batchSize, array $resources)
+ {
+ throw new \Exception('Not Implemented');
+ }
+}
diff --git a/src/Transfer/Sources/Supabase.php b/src/Transfer/Sources/Supabase.php
new file mode 100644
index 00000000..4e0efc62
--- /dev/null
+++ b/src/Transfer/Sources/Supabase.php
@@ -0,0 +1,531 @@
+ '3g2',
+ 'video/3gp' => '3gp',
+ 'video/3gpp' => '3gp',
+ 'application/x-compressed' => '7zip',
+ 'audio/x-acc' => 'aac',
+ 'audio/ac3' => 'ac3',
+ 'application/postscript' => 'ai',
+ 'audio/x-aiff' => 'aif',
+ 'audio/aiff' => 'aif',
+ 'audio/x-au' => 'au',
+ 'video/x-msvideo' => 'avi',
+ 'video/msvideo' => 'avi',
+ 'video/avi' => 'avi',
+ 'application/x-troff-msvideo' => 'avi',
+ 'application/macbinary' => 'bin',
+ 'application/mac-binary' => 'bin',
+ 'application/x-binary' => 'bin',
+ 'application/x-macbinary' => 'bin',
+ 'image/bmp' => 'bmp',
+ 'image/x-bmp' => 'bmp',
+ 'image/x-bitmap' => 'bmp',
+ 'image/x-xbitmap' => 'bmp',
+ 'image/x-win-bitmap' => 'bmp',
+ 'image/x-windows-bmp' => 'bmp',
+ 'image/ms-bmp' => 'bmp',
+ 'image/x-ms-bmp' => 'bmp',
+ 'application/bmp' => 'bmp',
+ 'application/x-bmp' => 'bmp',
+ 'application/x-win-bitmap' => 'bmp',
+ 'application/cdr' => 'cdr',
+ 'application/coreldraw' => 'cdr',
+ 'application/x-cdr' => 'cdr',
+ 'application/x-coreldraw' => 'cdr',
+ 'image/cdr' => 'cdr',
+ 'image/x-cdr' => 'cdr',
+ 'zz-application/zz-winassoc-cdr' => 'cdr',
+ 'application/mac-compactpro' => 'cpt',
+ 'application/pkix-crl' => 'crl',
+ 'application/pkcs-crl' => 'crl',
+ 'application/x-x509-ca-cert' => 'crt',
+ 'application/pkix-cert' => 'crt',
+ 'text/css' => 'css',
+ 'text/x-comma-separated-values' => 'csv',
+ 'text/comma-separated-values' => 'csv',
+ 'application/vnd.msexcel' => 'csv',
+ 'application/x-director' => 'dcr',
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
+ 'application/x-dvi' => 'dvi',
+ 'message/rfc822' => 'eml',
+ 'application/x-msdownload' => 'exe',
+ 'video/x-f4v' => 'f4v',
+ 'audio/x-flac' => 'flac',
+ 'video/x-flv' => 'flv',
+ 'image/gif' => 'gif',
+ 'application/gpg-keys' => 'gpg',
+ 'application/x-gtar' => 'gtar',
+ 'application/x-gzip' => 'gzip',
+ 'application/mac-binhex40' => 'hqx',
+ 'application/mac-binhex' => 'hqx',
+ 'application/x-binhex40' => 'hqx',
+ 'application/x-mac-binhex40' => 'hqx',
+ 'text/html' => 'html',
+ 'image/x-icon' => 'ico',
+ 'image/x-ico' => 'ico',
+ 'image/vnd.microsoft.icon' => 'ico',
+ 'text/calendar' => 'ics',
+ 'application/java-archive' => 'jar',
+ 'application/x-java-application' => 'jar',
+ 'application/x-jar' => 'jar',
+ 'image/jp2' => 'jp2',
+ 'video/mj2' => 'jp2',
+ 'image/jpx' => 'jp2',
+ 'image/jpm' => 'jp2',
+ 'image/jpeg' => 'jpeg',
+ 'image/jpg' => 'jpeg',
+ 'image/pjpeg' => 'jpeg',
+ 'application/x-javascript' => 'js',
+ 'application/json' => 'json',
+ 'text/json' => 'json',
+ 'application/vnd.google-earth.kml+xml' => 'kml',
+ 'application/vnd.google-earth.kmz' => 'kmz',
+ 'text/x-log' => 'log',
+ 'audio/x-m4a' => 'm4a',
+ 'audio/mp4' => 'm4a',
+ 'application/vnd.mpegurl' => 'm4u',
+ 'audio/midi' => 'mid',
+ 'application/vnd.mif' => 'mif',
+ 'video/quicktime' => 'mov',
+ 'video/x-sgi-movie' => 'movie',
+ 'audio/mpeg' => 'mp3',
+ 'audio/mpg' => 'mp3',
+ 'audio/mpeg3' => 'mp3',
+ 'audio/mp3' => 'mp3',
+ 'video/mp4' => 'mp4',
+ 'video/mpeg' => 'mpeg',
+ 'application/oda' => 'oda',
+ 'audio/ogg' => 'ogg',
+ 'video/ogg' => 'ogg',
+ 'application/ogg' => 'ogg',
+ 'font/otf' => 'otf',
+ 'application/x-pkcs10' => 'p10',
+ 'application/pkcs10' => 'p10',
+ 'application/x-pkcs12' => 'p12',
+ 'application/x-pkcs7-signature' => 'p7a',
+ 'application/pkcs7-mime' => 'p7c',
+ 'application/x-pkcs7-mime' => 'p7c',
+ 'application/x-pkcs7-certreqresp' => 'p7r',
+ 'application/pkcs7-signature' => 'p7s',
+ 'application/pdf' => 'pdf',
+ 'application/octet-stream' => 'pdf',
+ 'application/x-x509-user-cert' => 'pem',
+ 'application/x-pem-file' => 'pem',
+ 'application/pgp' => 'pgp',
+ 'application/x-httpd-php' => 'php',
+ 'application/php' => 'php',
+ 'application/x-php' => 'php',
+ 'text/php' => 'php',
+ 'text/x-php' => 'php',
+ 'application/x-httpd-php-source' => 'php',
+ 'image/png' => 'png',
+ 'image/x-png' => 'png',
+ 'application/powerpoint' => 'ppt',
+ 'application/vnd.ms-powerpoint' => 'ppt',
+ 'application/vnd.ms-office' => 'ppt',
+ 'application/msword' => 'doc',
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx',
+ 'application/x-photoshop' => 'psd',
+ 'image/vnd.adobe.photoshop' => 'psd',
+ 'audio/x-realaudio' => 'ra',
+ 'audio/x-pn-realaudio' => 'ram',
+ 'application/x-rar' => 'rar',
+ 'application/rar' => 'rar',
+ 'application/x-rar-compressed' => 'rar',
+ 'audio/x-pn-realaudio-plugin' => 'rpm',
+ 'application/x-pkcs7' => 'rsa',
+ 'text/rtf' => 'rtf',
+ 'text/richtext' => 'rtx',
+ 'video/vnd.rn-realvideo' => 'rv',
+ 'application/x-stuffit' => 'sit',
+ 'application/smil' => 'smil',
+ 'text/srt' => 'srt',
+ 'image/svg+xml' => 'svg',
+ 'application/x-shockwave-flash' => 'swf',
+ 'application/x-tar' => 'tar',
+ 'application/x-gzip-compressed' => 'tgz',
+ 'image/tiff' => 'tiff',
+ 'font/ttf' => 'ttf',
+ 'text/plain' => 'txt',
+ 'text/x-vcard' => 'vcf',
+ 'application/videolan' => 'vlc',
+ 'text/vtt' => 'vtt',
+ 'audio/x-wav' => 'wav',
+ 'audio/wave' => 'wav',
+ 'audio/wav' => 'wav',
+ 'application/wbxml' => 'wbxml',
+ 'video/webm' => 'webm',
+ 'image/webp' => 'webp',
+ 'audio/x-ms-wma' => 'wma',
+ 'application/wmlc' => 'wmlc',
+ 'video/x-ms-wmv' => 'wmv',
+ 'video/x-ms-asf' => 'wmv',
+ 'font/woff' => 'woff',
+ 'font/woff2' => 'woff2',
+ 'application/xhtml+xml' => 'xhtml',
+ 'application/excel' => 'xl',
+ 'application/msexcel' => 'xls',
+ 'application/x-msexcel' => 'xls',
+ 'application/x-ms-excel' => 'xls',
+ 'application/x-excel' => 'xls',
+ 'application/x-dos_ms_excel' => 'xls',
+ 'application/xls' => 'xls',
+ 'application/x-xls' => 'xls',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
+ 'application/vnd.ms-excel' => 'xlsx',
+ 'application/xml' => 'xml',
+ 'text/xml' => 'xml',
+ 'text/xsl' => 'xsl',
+ 'application/xspf+xml' => 'xspf',
+ 'application/x-compress' => 'z',
+ 'application/x-zip' => 'zip',
+ 'application/zip' => 'zip',
+ 'application/x-zip-compressed' => 'zip',
+ 'application/s-compressed' => 'zip',
+ 'multipart/x-zip' => 'zip',
+ 'text/x-scriptzsh' => 'zsh'
+];
+
+class Supabase extends NHost
+{
+ public static function getName(): string
+ {
+ return 'Supabase';
+ }
+
+ protected string $key;
+
+ protected string $host;
+
+ /**
+ * Constructor
+ *
+ *
+ * @return self
+ */
+ public function __construct(string $endpoint
+ , string $key, string $host, string $databaseName, string $username, string $password, string $port = '5432')
+ {
+ $this->endpoint = $endpoint;
+ $this->key = $key;
+ $this->host = $host;
+ $this->databaseName = $databaseName;
+ $this->username = $username;
+ $this->password = $password;
+ $this->port = $port;
+
+ $this->headers['Authorization'] = 'Bearer '.$this->key;
+
+ try {
+ $this->pdo = new \PDO('pgsql:host='.$this->host.';port='.$this->port.';dbname='.$this->databaseName, $this->username, $this->password);
+ } catch (\PDOException $e) {
+ throw new \Exception('Failed to connect to database: '.$e->getMessage());
+ }
+ }
+
+ public function report(array $resources = []): array
+ {
+ $report = [];
+
+ if (empty($resources)) {
+ $resources = $this->getSupportedResources();
+ }
+
+ try {
+ $this->pdo = new \PDO('pgsql:host='.$this->host.';port='.$this->port.';dbname='.$this->databaseName, $this->username, $this->password);
+ } catch (\PDOException $e) {
+ throw new \Exception('Failed to connect to database. PDO Code: '.$e->getCode().' Error: '.$e->getMessage());
+ }
+
+ if (!empty($this->pdo->errorCode())) {
+ throw new \Exception('Failed to connect to database. PDO Code: '.$this->pdo->errorCode().(empty($this->pdo->errorInfo()[2]) ? '' : ' Error: '.$this->pdo->errorInfo()[2]));
+ }
+
+ // Auth
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM auth.users');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access users table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_USER] = $statement->fetchColumn();
+ }
+
+ // Databases
+ if (in_array(Resource::TYPE_DATABASE, $resources)) {
+ $report[Resource::TYPE_DATABASE] = 1;
+ }
+
+ if (in_array(Resource::TYPE_COLLECTION, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access tables table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_COLLECTION] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_ATTRIBUTE, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access columns table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_ATTRIBUTE] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_INDEX, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM pg_indexes WHERE schemaname = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access indexes table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_INDEX] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_DOCUMENT, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \'public\'');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access tables table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_DOCUMENT] = $statement->fetchColumn();
+ }
+
+ // Storage
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM storage.buckets');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access buckets table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_BUCKET] = $statement->fetchColumn();
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $statement = $this->pdo->prepare('SELECT COUNT(*) FROM storage.objects');
+ $statement->execute();
+
+ if ($statement->errorCode() !== '00000') {
+ throw new \Exception('Failed to access files table. Error: '.$statement->errorInfo()[2]);
+ }
+
+ $report[Resource::TYPE_FILE] = $statement->fetchColumn();
+ }
+
+ return $report;
+ }
+
+ protected function exportGroupAuth(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_USER, $resources)) {
+ $this->exportUsers($batchSize);
+ }
+ }
+
+ private function exportUsers(int $batchSize)
+ {
+ $total = $this->pdo->query('SELECT COUNT(*) FROM auth.users')->fetchColumn();
+
+ $offset = 0;
+
+ while ($offset < $total) {
+ $statement = $this->pdo->prepare('SELECT * FROM auth.users order by created_at LIMIT :limit OFFSET :offset');
+ $statement->bindValue(':limit', $batchSize, \PDO::PARAM_INT);
+ $statement->bindValue(':offset', $offset, \PDO::PARAM_INT);
+ $statement->execute();
+
+ $users = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ $transferUsers = [];
+
+ foreach ($users as $user) {
+ $transferUsers[] = new User(
+ $user['id'],
+ $user['email'] ?? '',
+ '',
+ new Hash($user['encrypted_password'], '', Hash::ALGORITHM_BCRYPT),
+ $user['phone'] ?? '',
+ $this->calculateAuthTypes($user),
+ '',
+ !empty($user['email_confirmed_at']),
+ !empty($user['phone_confirmed_at']),
+ false,
+ []
+ );
+ }
+
+ $this->callback($transferUsers);
+ }
+ }
+
+ private function convertMimes(array $mimes): array
+ {
+ $extensions = [];
+
+ foreach ($mimes as $mime) {
+ $extensions[] = MIME_MAP[$mime] ?? '';
+ }
+
+ return $extensions;
+ }
+
+ private function calculateAuthTypes(array $user): array
+ {
+ if (empty($user['encrypted_password']) && empty($user['phone'])) {
+ return [User::TYPE_ANONYMOUS];
+ }
+
+ $types = [];
+
+ if (!empty($user['encrypted_password'])) {
+ $types[] = User::TYPE_EMAIL;
+ }
+
+ if (!empty($user['phone'])) {
+ $types[] = User::TYPE_PHONE;
+ }
+
+ return $types;
+ }
+
+ protected function exportGroupStorage(int $batchSize, array $resources)
+ {
+ if (in_array(Resource::TYPE_BUCKET, $resources)) {
+ $this->exportBuckets($batchSize);
+ }
+
+ if (in_array(Resource::TYPE_FILE, $resources)) {
+ $this->exportFiles($batchSize);
+ }
+ }
+
+ protected function exportBuckets(int $batchSize)
+ {
+ $statement = $this->pdo->prepare('SELECT * FROM storage.buckets order by created_at');
+ $statement->execute();
+
+ $buckets = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $transferBuckets = [];
+
+ foreach ($buckets as $bucket) {
+ $transferBuckets[] = new Bucket(
+ '',
+ [],
+ false,
+ $bucket['name'],
+ true,
+ $bucket['file_size_limit'] ?? 0,
+ $bucket['allowed_mime_types'] ? $this->convertMimes($bucket['allowed_mime_types']) : [],
+ );
+ }
+
+ $this->callback($transferBuckets);
+ }
+
+ public function exportFiles(int $batchSize)
+ {
+ /**
+ * TODO: Supabase has folders, with enough folders within folders this could cause us to hit the max name length
+ * Need to figure out a solution to this.
+ */
+ $buckets = $this->cache->get(Bucket::getName());
+
+ foreach ($buckets as $bucket) {
+ /** @var Bucket $bucket */
+ $totalStatement = $this->pdo->prepare('SELECT COUNT(*) FROM storage.objects WHERE bucket_id=:bucketId');
+ $totalStatement->execute([':bucketId' => $bucket->getId()]);
+ $total = $totalStatement->fetchColumn();
+
+ $offset = 0;
+ while ($offset < $total) {
+ $statement = $this->pdo->prepare('SELECT * FROM storage.objects WHERE bucket_id=:bucketId ORDER BY created_at LIMIT :limit OFFSET :offset');
+ $statement->execute([
+ ':bucketId' => $bucket->getId(),
+ ':limit' => $batchSize,
+ ':offset' => $offset,
+ ]);
+
+ $files = $statement->fetchAll(\PDO::FETCH_ASSOC);
+
+ $offset += $batchSize;
+
+ foreach ($files as $file) {
+ $metadata = json_decode($file['metadata'], true);
+
+ $this->exportFile(new File(
+ $file['id'],
+ $bucket,
+ $file['name'],
+ '',
+ $metadata['mimetype'],
+ [],
+ $metadata['size']
+ ));
+ }
+ }
+ }
+ }
+
+ public function exportFile(File $file)
+ {
+ $start = 0;
+ $end = Transfer::STORAGE_MAX_CHUNK_SIZE - 1;
+
+ $fileSize = $file->getSize();
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+
+ // Loop until the entire file is downloaded
+ while ($start < $fileSize) {
+ $chunkData = $this->call(
+ 'GET',
+ '/storage/v1/object/'.
+ rawurlencode($file->getBucket()->getId()).'/'.rawurlencode($file->getFileName()),
+ ['range' => "bytes=$start-$end"]
+ );
+
+ // Send the chunk to the callback function
+ $file->setData($chunkData)
+ ->setStart($start)
+ ->setEnd($end);
+
+ $this->callback([$file]);
+
+ // Update the range
+ $start += Transfer::STORAGE_MAX_CHUNK_SIZE;
+ $end += Transfer::STORAGE_MAX_CHUNK_SIZE;
+
+ if ($end > $fileSize) {
+ $end = $fileSize - 1;
+ }
+ }
+ }
+}
diff --git a/src/Transfer/Target.php b/src/Transfer/Target.php
new file mode 100644
index 00000000..a6ac944c
--- /dev/null
+++ b/src/Transfer/Target.php
@@ -0,0 +1,168 @@
+ '',
+ ];
+
+ /**
+ * Cache
+ *
+ * @var Cache
+ */
+ public $cache;
+
+ /**
+ * Endpoint
+ *
+ * @var string
+ */
+ protected $endpoint = '';
+
+ /**
+ * Gets the name of the adapter.
+ */
+ abstract public static function getName(): string;
+
+ /**
+ * Get Supported Resources
+ */
+ abstract static function getSupportedResources(): array;
+
+ /**
+ * Register Cache
+ */
+ public function registerCache(Cache &$cache): void
+ {
+ $this->cache = &$cache;
+ }
+
+ /**
+ * Run Transfer
+ */
+ abstract public function run(array $resources, callable $callback): void;
+
+ /**
+ * Report Resources
+ *
+ * This function performs a count of all resources that are available for transfer.
+ * It also serves a secondary purpose of checking if the API is available for the given adapter.
+ *
+ * On Destinations, this function should just return nothing but still check if the API is available.
+ * If any issues are found then an exception should be thrown with an error message.
+ */
+ abstract public function report(array $resources = []): array;
+
+ /**
+ * Call
+ *
+ * Make an API call
+ *
+ * @throws \Exception
+ */
+ protected function call(string $method, string $path = '', array $headers = [], array $params = []): array|string
+ {
+ $headers = array_merge($this->headers, $headers);
+ $ch = curl_init((str_contains($path, 'http') ? $path.(($method == 'GET' && !empty($params)) ? '?'.http_build_query($params) : '') : $this->endpoint.$path.(($method == 'GET' && !empty($params)) ? '?'.http_build_query($params) : '')));
+ $responseHeaders = [];
+ $responseStatus = -1;
+ $responseType = '';
+ $responseBody = '';
+
+ switch ($headers['Content-Type']) {
+ case 'application/json':
+ $query = json_encode($params);
+ break;
+
+ case 'multipart/form-data':
+ $query = $this->flatten($params);
+ break;
+
+ default:
+ $query = http_build_query($params);
+ break;
+ }
+
+ foreach ($headers as $i => $header) {
+ $headers[] = $i.':'.$header;
+ unset($headers[$i]);
+ }
+
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_USERAGENT, php_uname('s').'-'.php_uname('r').':php-'.phpversion());
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
+ $len = strlen($header);
+ $header = explode(':', strtolower($header), 2);
+
+ if (count($header) < 2) { // ignore invalid headers
+ return $len;
+ }
+
+ $responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
+
+ return $len;
+ });
+
+ if ($method != 'GET') {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
+ }
+
+ $responseBody = curl_exec($ch);
+
+ $responseType = $responseHeaders['Content-Type'] ?? $responseHeaders['content-type'] ?? '';
+ $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+ switch (substr($responseType, 0, strpos($responseType, ';'))) {
+ case 'application/json':
+ $responseBody = json_decode($responseBody, true);
+ break;
+ }
+
+ if (curl_errno($ch)) {
+ throw new \Exception(curl_error($ch));
+ }
+
+ curl_close($ch);
+
+ if ($responseStatus >= 400) {
+ if (is_array($responseBody)) {
+ throw new \Exception(json_encode($responseBody));
+ } else {
+ throw new \Exception($responseStatus.': '.$responseBody);
+ }
+ }
+
+ return $responseBody;
+ }
+
+ /**
+ * Flatten params array to PHP multiple format
+ */
+ protected function flatten(array $data, string $prefix = ''): array
+ {
+ $output = [];
+
+ foreach ($data as $key => $value) {
+ $finalKey = $prefix ? "{$prefix}[{$key}]" : $key;
+
+ if (is_array($value)) {
+ $output += $this->flatten($value, $finalKey);
+ } else {
+ $output[$finalKey] = $value;
+ }
+ }
+
+ return $output;
+ }
+}
diff --git a/src/Transfer/Transfer.php b/src/Transfer/Transfer.php
new file mode 100644
index 00000000..16f091bc
--- /dev/null
+++ b/src/Transfer/Transfer.php
@@ -0,0 +1,165 @@
+source = $source;
+ $this->destination = $destination;
+ $this->cache = new Cache();
+
+ $this->source->registerCache($this->cache);
+ $this->destination->registerCache($this->cache);
+ $this->destination->setSource($source);
+
+ return $this;
+ }
+
+ protected Source $source;
+
+ protected Destination $destination;
+
+ protected string $currentResource;
+
+ /**
+ * A local cache of resources that were transferred.
+ */
+ protected Cache $cache;
+
+ protected array $options = [];
+
+ protected array $callbacks = [];
+
+ protected array $events = [];
+
+ public function getStatusCounters()
+ {
+ $status = [];
+
+ foreach ($this->cache->getAll() as $resources) {
+ foreach ($resources as $resource) {
+ /** @var Resource $resource */
+ if (!array_key_exists($resource->getName(), $status)) {
+ $status[$resource->getName()] = [
+ Resource::STATUS_PENDING => 0,
+ Resource::STATUS_SUCCESS => 0,
+ Resource::STATUS_ERROR => 0,
+ Resource::STATUS_SKIPPED => 0,
+ Resource::STATUS_PROCESSING => 0,
+ Resource::STATUS_WARNING => 0,
+ ];
+ }
+
+ $status[$resource->getName()][$resource->getStatus()]++;
+ }
+ }
+
+ return $status;
+ }
+
+ /**
+ * Transfer Resources between adapters
+ *
+ * @param callable $callback (array $resources)
+ */
+ public function run(array $resources, callable $callback): void
+ {
+ // Allows you to push entire groups if you want.
+ $computedResources = [];
+ foreach ($resources as $resource) {
+ if (is_array($resource)) {
+ $computedResources = array_merge($computedResources, $resource);
+ } else {
+ $computedResources[] = $resource;
+ }
+ }
+
+ $this->destination->run($computedResources, $callback, $this->source);
+ }
+
+ /**
+ * Get Cache
+ */
+ public function getCache(): Cache
+ {
+ return $this->cache;
+ }
+
+ /**
+ * Get Current Resource
+ *
+ **/
+ public function getCurrentResource(): string
+ {
+ return $this->currentResource;
+ }
+
+ /**
+ * Get Transfer Report
+ *
+ * @param string $statusLevel
+ * If no status level is provided, all status types will be returned.
+ */
+ public function getReport(string $statusLevel = ''): array
+ {
+ $report = [];
+
+ $cache = $this->cache->getAll();
+
+ foreach ($cache as $type => $resources) {
+ foreach ($resources as $resource) {
+ if ($statusLevel && $resource->getStatus() !== $statusLevel) {
+ continue;
+ }
+
+ $report[] = [
+ 'resource' => $type,
+ 'id' => $resource->getId(),
+ 'status' => $resource->getStatus(),
+ 'message' => $resource->getReason(),
+ ];
+ }
+ }
+
+ return $report;
+ }
+}
diff --git a/tests/Transfer/E2E/Adapters/Mock.php b/tests/Transfer/E2E/Adapters/Mock.php
new file mode 100644
index 00000000..b0de6bf6
--- /dev/null
+++ b/tests/Transfer/E2E/Adapters/Mock.php
@@ -0,0 +1,86 @@
+getName()) {
+ case 'Deployment':
+ /** @var Deployment $resource */
+ if ($resource->getStart() === 0) {
+ $this->data[$resource->getGroup()][$resource->getName()][$resource->getInternalId()] = $resource->asArray();
+ }
+
+ // file_put_contents($this->path . 'deployments/' . $resource->getId() . '.tar.gz', $resource->getData(), FILE_APPEND);
+ break;
+ case 'File':
+ //TODO: Handle Files and Deployments
+ // /** @var File $resource */
+
+ // // Handle folders
+ // if (str_contains($resource->getFileName(), '/')) {
+ // $folders = explode('/', $resource->getFileName());
+ // $folderPath = $this->path . '/files';
+
+ // foreach ($folders as $folder) {
+ // $folderPath .= '/' . $folder;
+
+ // if (!\file_exists($folderPath) && str_contains($folder, '.') === false) {
+ // mkdir($folderPath, 0777, true);
+ // }
+ // }
+ // }
+
+ // if ($resource->getStart() === 0 && \file_exists($this->path . '/files/' . $resource->getFileName())) {
+ // unlink($this->path . '/files/' . $resource->getFileName());
+ // }
+
+ // file_put_contents($this->path . '/files/' . $resource->getFileName(), $resource->getData(), FILE_APPEND);
+ // break;
+ }
+
+ $resource->setStatus(Resource::STATUS_SUCCESS);
+ $this->cache->update($resource);
+ }
+
+ $callback($resources);
+ }
+
+ public function report(array $groups = []): array
+ {
+ return [];
+ }
+}
diff --git a/tests/Transfer/E2E/Sources/Base.php b/tests/Transfer/E2E/Sources/Base.php
new file mode 100644
index 00000000..e1d06ef8
--- /dev/null
+++ b/tests/Transfer/E2E/Sources/Base.php
@@ -0,0 +1,48 @@
+source)
+ throw new \Exception('Source not set');
+
+ $this->destination = new Mock();
+ $this->transfer = new Transfer($this->source, $this->destination);
+ }
+
+ public function testGetName(): void
+ {
+ $this->assertNotEmpty($this->source::getName());
+ }
+
+ public function testGetSupportedResources(): void
+ {
+ $this->assertNotEmpty($this->source->getSupportedResources());
+
+ foreach ($this->source->getSupportedResources() as $resource) {
+ $this->assertContains($resource, Resource::ALL_RESOURCES);
+ }
+ }
+
+ public function testCache(): void
+ {
+ $this->source->registerCache($this->createMock(\Utopia\Transfer\Cache::class));
+
+ $this->assertNotNull($this->source->cache);
+ }
+}
diff --git a/tests/Transfer/E2E/Sources/NHostTest.php b/tests/Transfer/E2E/Sources/NHostTest.php
new file mode 100644
index 00000000..700478f7
--- /dev/null
+++ b/tests/Transfer/E2E/Sources/NHostTest.php
@@ -0,0 +1,51 @@
+source = new NHost(
+ 'xxxxxxxxxxxx',
+ 'eu-central-1',
+ 'xxxxxxxxxxxxxxxxxx',
+ 'xxxxxxxxxxxxxxx',
+ 'xxxxxxxxx',
+ 'xxxxxxxxxxxxxxxx'
+ );
+
+ $this->destination = new Mock();
+ $this->transfer = new Transfer($this->source, $this->destination);
+
+ // $this->source->pdo = new \PDO('pgsql:host=nhost-db' . ';port=5432;dbname=postgres', 'postgres', 'postgres');
+ }
+
+ public function testSourceReport(): void
+ {
+ // Test report all
+ $report = $this->source->report();
+
+ $this->assertNotEmpty($report);
+ }
+
+ public function testRunTransfer(): void
+ {
+ $this->transfer->run(
+ $this->source->getSupportedResources(),
+ function ($data) {
+ $this->assertNotEmpty($data);
+ }
+ );
+ }
+}
diff --git a/tests/Transfer/resources/nhost/backup.tar b/tests/Transfer/resources/nhost/backup.tar
new file mode 100644
index 00000000..6657eca1
--- /dev/null
+++ b/tests/Transfer/resources/nhost/backup.tar
@@ -0,0 +1,2361 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 14.5 (Debian 14.5-2.pgdg110+2)
+-- Dumped by pg_dump version 15.2
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- Name: auth; Type: SCHEMA; Schema: -; Owner: nhost_admin
+--
+
+CREATE SCHEMA auth;
+
+
+ALTER SCHEMA auth OWNER TO nhost_admin;
+
+--
+-- Name: hdb_catalog; Type: SCHEMA; Schema: -; Owner: nhost_hasura
+--
+
+CREATE SCHEMA hdb_catalog;
+
+
+ALTER SCHEMA hdb_catalog OWNER TO nhost_hasura;
+
+--
+-- Name: pgbouncer; Type: SCHEMA; Schema: -; Owner: nhost_admin
+--
+
+CREATE SCHEMA pgbouncer;
+
+
+ALTER SCHEMA pgbouncer OWNER TO nhost_admin;
+
+--
+-- Name: public; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+-- *not* creating schema, since initdb creates it
+
+
+ALTER SCHEMA public OWNER TO postgres;
+
+--
+-- Name: storage; Type: SCHEMA; Schema: -; Owner: nhost_admin
+--
+
+CREATE SCHEMA storage;
+
+
+ALTER SCHEMA storage OWNER TO nhost_admin;
+
+--
+-- Name: citext; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;
+
+
+--
+-- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings';
+
+
+--
+-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public;
+
+
+--
+-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';
+
+
+--
+-- Name: email; Type: DOMAIN; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE DOMAIN auth.email AS public.citext
+ CONSTRAINT email_check CHECK (((VALUE)::text ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'::text));
+
+
+ALTER DOMAIN auth.email OWNER TO nhost_auth_admin;
+
+--
+-- Name: set_current_timestamp_updated_at(); Type: FUNCTION; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE FUNCTION auth.set_current_timestamp_updated_at() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ _new record;
+BEGIN
+ _new := new;
+ _new. "updated_at" = now();
+ RETURN _new;
+END;
+$$;
+
+
+ALTER FUNCTION auth.set_current_timestamp_updated_at() OWNER TO nhost_auth_admin;
+
+--
+-- Name: gen_hasura_uuid(); Type: FUNCTION; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE FUNCTION hdb_catalog.gen_hasura_uuid() RETURNS uuid
+ LANGUAGE sql
+ AS $$select gen_random_uuid()$$;
+
+
+ALTER FUNCTION hdb_catalog.gen_hasura_uuid() OWNER TO nhost_hasura;
+
+--
+-- Name: user_lookup(text); Type: FUNCTION; Schema: pgbouncer; Owner: postgres
+--
+
+CREATE FUNCTION pgbouncer.user_lookup(i_username text, OUT uname text, OUT phash text) RETURNS record
+ LANGUAGE plpgsql SECURITY DEFINER
+ AS $$
+BEGIN
+ SELECT usename, passwd FROM pg_catalog.pg_shadow
+ WHERE usename = i_username INTO uname, phash;
+ RETURN;
+END;
+$$;
+
+
+ALTER FUNCTION pgbouncer.user_lookup(i_username text, OUT uname text, OUT phash text) OWNER TO postgres;
+
+--
+-- Name: protect_default_bucket_delete(); Type: FUNCTION; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE FUNCTION storage.protect_default_bucket_delete() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF OLD.ID = 'default' THEN
+ RAISE EXCEPTION 'Can not delete default bucket';
+ END IF;
+ RETURN OLD;
+END;
+$$;
+
+
+ALTER FUNCTION storage.protect_default_bucket_delete() OWNER TO nhost_storage_admin;
+
+--
+-- Name: protect_default_bucket_update(); Type: FUNCTION; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE FUNCTION storage.protect_default_bucket_update() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF OLD.ID = 'default' AND NEW.ID <> 'default' THEN
+ RAISE EXCEPTION 'Can not rename default bucket';
+ END IF;
+ RETURN NEW;
+END;
+$$;
+
+
+ALTER FUNCTION storage.protect_default_bucket_update() OWNER TO nhost_storage_admin;
+
+--
+-- Name: set_current_timestamp_updated_at(); Type: FUNCTION; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE FUNCTION storage.set_current_timestamp_updated_at() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ _new record;
+BEGIN
+ _new := new;
+ _new. "updated_at" = now();
+ RETURN _new;
+END;
+$$;
+
+
+ALTER FUNCTION storage.set_current_timestamp_updated_at() OWNER TO nhost_storage_admin;
+
+SET default_tablespace = '';
+
+SET default_table_access_method = heap;
+
+--
+-- Name: migrations; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.migrations (
+ id integer NOT NULL,
+ name character varying(100) NOT NULL,
+ hash character varying(40) NOT NULL,
+ executed_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
+);
+
+
+ALTER TABLE auth.migrations OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE migrations; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.migrations IS 'Internal table for tracking migrations. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: provider_requests; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.provider_requests (
+ id uuid NOT NULL,
+ options jsonb
+);
+
+
+ALTER TABLE auth.provider_requests OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE provider_requests; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.provider_requests IS 'Oauth requests, inserted before redirecting to the provider''s site. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: providers; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.providers (
+ id text NOT NULL
+);
+
+
+ALTER TABLE auth.providers OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE providers; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.providers IS 'List of available Oauth providers. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: refresh_tokens; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.refresh_tokens (
+ refresh_token uuid NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ expires_at timestamp with time zone NOT NULL,
+ user_id uuid NOT NULL,
+ refresh_token_hash character varying(255) GENERATED ALWAYS AS (sha256(((refresh_token)::text)::bytea)) STORED
+);
+
+
+ALTER TABLE auth.refresh_tokens OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE refresh_tokens; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.refresh_tokens IS 'User refresh tokens. Hasura auth uses them to rotate new access tokens as long as the refresh token is not expired. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: COLUMN refresh_tokens.refresh_token; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON COLUMN auth.refresh_tokens.refresh_token IS 'DEPRECATED: auto-generated refresh token id. Will be replaced by a genereric id column that will be used as a primary key, not the refresh token itself. Use refresh_token_hash instead.';
+
+
+--
+-- Name: roles; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.roles (
+ role text NOT NULL
+);
+
+
+ALTER TABLE auth.roles OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE roles; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.roles IS 'Persistent Hasura roles for users. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: user_providers; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.user_providers (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ user_id uuid NOT NULL,
+ access_token text NOT NULL,
+ refresh_token text,
+ provider_id text NOT NULL,
+ provider_user_id text NOT NULL
+);
+
+
+ALTER TABLE auth.user_providers OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE user_providers; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.user_providers IS 'Active providers for a given user. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: user_roles; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.user_roles (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ user_id uuid NOT NULL,
+ role text NOT NULL
+);
+
+
+ALTER TABLE auth.user_roles OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE user_roles; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.user_roles IS 'Roles of users. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: user_security_keys; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.user_security_keys (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ user_id uuid NOT NULL,
+ credential_id text NOT NULL,
+ credential_public_key bytea,
+ counter bigint DEFAULT 0 NOT NULL,
+ transports character varying(255) DEFAULT ''::character varying NOT NULL,
+ nickname text
+);
+
+
+ALTER TABLE auth.user_security_keys OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE user_security_keys; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.user_security_keys IS 'User webauthn security keys. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: users; Type: TABLE; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TABLE auth.users (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ last_seen timestamp with time zone,
+ disabled boolean DEFAULT false NOT NULL,
+ display_name text DEFAULT ''::text NOT NULL,
+ avatar_url text DEFAULT ''::text NOT NULL,
+ locale character varying(2) NOT NULL,
+ email auth.email,
+ phone_number text,
+ password_hash text,
+ email_verified boolean DEFAULT false NOT NULL,
+ phone_number_verified boolean DEFAULT false NOT NULL,
+ new_email auth.email,
+ otp_method_last_used text,
+ otp_hash text,
+ otp_hash_expires_at timestamp with time zone DEFAULT now() NOT NULL,
+ default_role text DEFAULT 'user'::text NOT NULL,
+ is_anonymous boolean DEFAULT false NOT NULL,
+ totp_secret text,
+ active_mfa_type text,
+ ticket text,
+ ticket_expires_at timestamp with time zone DEFAULT now() NOT NULL,
+ metadata jsonb,
+ webauthn_current_challenge text,
+ CONSTRAINT active_mfa_types_check CHECK (((active_mfa_type = 'totp'::text) OR (active_mfa_type = 'sms'::text)))
+);
+
+
+ALTER TABLE auth.users OWNER TO nhost_auth_admin;
+
+--
+-- Name: TABLE users; Type: COMMENT; Schema: auth; Owner: nhost_auth_admin
+--
+
+COMMENT ON TABLE auth.users IS 'User account information. Don''t modify its structure as Hasura Auth relies on it to function properly.';
+
+
+--
+-- Name: hdb_action_log; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_action_log (
+ id uuid DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ action_name text,
+ input_payload jsonb NOT NULL,
+ request_headers jsonb NOT NULL,
+ session_variables jsonb NOT NULL,
+ response_payload jsonb,
+ errors jsonb,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ response_received_at timestamp with time zone,
+ status text NOT NULL,
+ CONSTRAINT hdb_action_log_status_check CHECK ((status = ANY (ARRAY['created'::text, 'processing'::text, 'completed'::text, 'error'::text])))
+);
+
+
+ALTER TABLE hdb_catalog.hdb_action_log OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_cron_event_invocation_logs; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_cron_event_invocation_logs (
+ id text DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ event_id text,
+ status integer,
+ request json,
+ response json,
+ created_at timestamp with time zone DEFAULT now()
+);
+
+
+ALTER TABLE hdb_catalog.hdb_cron_event_invocation_logs OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_cron_events; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_cron_events (
+ id text DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ trigger_name text NOT NULL,
+ scheduled_time timestamp with time zone NOT NULL,
+ status text DEFAULT 'scheduled'::text NOT NULL,
+ tries integer DEFAULT 0 NOT NULL,
+ created_at timestamp with time zone DEFAULT now(),
+ next_retry_at timestamp with time zone,
+ CONSTRAINT valid_status CHECK ((status = ANY (ARRAY['scheduled'::text, 'locked'::text, 'delivered'::text, 'error'::text, 'dead'::text])))
+);
+
+
+ALTER TABLE hdb_catalog.hdb_cron_events OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_metadata; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_metadata (
+ id integer NOT NULL,
+ metadata json NOT NULL,
+ resource_version integer DEFAULT 1 NOT NULL
+);
+
+
+ALTER TABLE hdb_catalog.hdb_metadata OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_scheduled_event_invocation_logs; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_scheduled_event_invocation_logs (
+ id text DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ event_id text,
+ status integer,
+ request json,
+ response json,
+ created_at timestamp with time zone DEFAULT now()
+);
+
+
+ALTER TABLE hdb_catalog.hdb_scheduled_event_invocation_logs OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_scheduled_events; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_scheduled_events (
+ id text DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ webhook_conf json NOT NULL,
+ scheduled_time timestamp with time zone NOT NULL,
+ retry_conf json,
+ payload json,
+ header_conf json,
+ status text DEFAULT 'scheduled'::text NOT NULL,
+ tries integer DEFAULT 0 NOT NULL,
+ created_at timestamp with time zone DEFAULT now(),
+ next_retry_at timestamp with time zone,
+ comment text,
+ CONSTRAINT valid_status CHECK ((status = ANY (ARRAY['scheduled'::text, 'locked'::text, 'delivered'::text, 'error'::text, 'dead'::text])))
+);
+
+
+ALTER TABLE hdb_catalog.hdb_scheduled_events OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_schema_notifications; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_schema_notifications (
+ id integer NOT NULL,
+ notification json NOT NULL,
+ resource_version integer DEFAULT 1 NOT NULL,
+ instance_id uuid NOT NULL,
+ updated_at timestamp with time zone DEFAULT now(),
+ CONSTRAINT hdb_schema_notifications_id_check CHECK ((id = 1))
+);
+
+
+ALTER TABLE hdb_catalog.hdb_schema_notifications OWNER TO nhost_hasura;
+
+--
+-- Name: hdb_version; Type: TABLE; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE TABLE hdb_catalog.hdb_version (
+ hasura_uuid uuid DEFAULT hdb_catalog.gen_hasura_uuid() NOT NULL,
+ version text NOT NULL,
+ upgraded_on timestamp with time zone NOT NULL,
+ cli_state jsonb DEFAULT '{}'::jsonb NOT NULL,
+ console_state jsonb DEFAULT '{}'::jsonb NOT NULL
+);
+
+
+ALTER TABLE hdb_catalog.hdb_version OWNER TO nhost_hasura;
+
+--
+-- Name: data_test; Type: TABLE; Schema: public; Owner: nhost_hasura
+--
+
+CREATE TABLE public.data_test (
+ text text NOT NULL,
+ charvar character varying NOT NULL,
+ "char" bpchar NOT NULL,
+ uuid uuid NOT NULL,
+ json json NOT NULL,
+ jsonb jsonb NOT NULL,
+ "smallint" smallint NOT NULL,
+ "integer" integer NOT NULL,
+ "bigint" bigint NOT NULL,
+ "decimal" numeric NOT NULL,
+ "numeric" numeric NOT NULL,
+ "real" real NOT NULL,
+ double_precision double precision NOT NULL,
+ bool boolean NOT NULL,
+ date date NOT NULL,
+ "timestamp" timestamp without time zone NOT NULL,
+ timestamptz timestamp with time zone NOT NULL,
+ "time" time without time zone NOT NULL,
+ timetz timestamp with time zone NOT NULL,
+ "interval" interval NOT NULL,
+ bytea bytea NOT NULL,
+ money money NOT NULL
+);
+
+
+ALTER TABLE public.data_test OWNER TO nhost_hasura;
+
+--
+-- Name: test_table_1; Type: TABLE; Schema: public; Owner: nhost_hasura
+--
+
+CREATE TABLE public.test_table_1 (
+ name text NOT NULL,
+ uuid uuid,
+ user_data json NOT NULL,
+ json_binary jsonb
+);
+
+
+ALTER TABLE public.test_table_1 OWNER TO nhost_hasura;
+
+--
+-- Name: buckets; Type: TABLE; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TABLE storage.buckets (
+ id text NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ download_expiration integer DEFAULT 30 NOT NULL,
+ min_upload_file_size integer DEFAULT 1 NOT NULL,
+ max_upload_file_size integer DEFAULT 50000000 NOT NULL,
+ cache_control text DEFAULT 'max-age=3600'::text,
+ presigned_urls_enabled boolean DEFAULT true NOT NULL,
+ CONSTRAINT download_expiration_valid_range CHECK (((download_expiration >= 1) AND (download_expiration <= 604800)))
+);
+
+
+ALTER TABLE storage.buckets OWNER TO nhost_storage_admin;
+
+--
+-- Name: files; Type: TABLE; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TABLE storage.files (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
+ updated_at timestamp with time zone DEFAULT now() NOT NULL,
+ bucket_id text DEFAULT 'default'::text NOT NULL,
+ name text,
+ size integer,
+ mime_type text,
+ etag text,
+ is_uploaded boolean DEFAULT false,
+ uploaded_by_user_id uuid
+);
+
+
+ALTER TABLE storage.files OWNER TO nhost_storage_admin;
+
+--
+-- Name: schema_migrations; Type: TABLE; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TABLE storage.schema_migrations (
+ version bigint NOT NULL,
+ dirty boolean NOT NULL
+);
+
+
+ALTER TABLE storage.schema_migrations OWNER TO nhost_storage_admin;
+
+--
+-- Data for Name: migrations; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.migrations (id, name, hash, executed_at) FROM stdin;
+0 create-migrations-table 9c0c864e0ccb0f8d1c77ab0576ef9f2841ec1b68 2023-04-18 03:08:07.102223
+1 create-initial-tables c16083c88329c867581a9c73c3f140783a1a5df4 2023-04-18 03:08:07.190394
+2 custom-user-fields 78236c9c2b50da88786bcf50099dd290f820e000 2023-04-18 03:08:07.194918
+3 discord-twitch-providers 857db1e92c7a8034e61a3d88ea672aec9b424036 2023-04-18 03:08:07.198837
+4 provider-request-options 42428265112b904903d9ad7833d8acf2812a00ed 2023-04-18 03:08:07.202855
+5 table-comments 78f76f88eff3b11ebab9be4f2469020dae017110 2023-04-18 03:08:07.204858
+6 setup-webauthn 87ba279363f8ecf8b450a681938a74b788cf536c 2023-04-18 03:08:07.221819
+7 add_authenticator_nickname d32fd62bb7a441eea48c5434f5f3744f2e334288 2023-04-18 03:08:07.22606
+8 workos-provider 0727238a633ff119bedcbebfec6a9ea83b2bd01d 2023-04-18 03:08:07.230566
+9 rename-authenticator-to-security-key fd7e00bef4d141a6193cf9642afd88fb6fe2b283 2023-04-18 03:08:07.235551
+10 azuread-provider f492ff4780f8210016e1c12fa0ed83eb4278a780 2023-04-18 03:08:07.243968
+11 add_refresh_token_hash_column 62a2cd295f63153dd9f16f3159d1ab2a49b01c2f 2023-04-18 03:08:07.262305
+\.
+
+
+--
+-- Data for Name: provider_requests; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.provider_requests (id, options) FROM stdin;
+\.
+
+
+--
+-- Data for Name: providers; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.providers (id) FROM stdin;
+github
+facebook
+twitter
+google
+apple
+linkedin
+windowslive
+spotify
+strava
+gitlab
+bitbucket
+discord
+twitch
+workos
+azuread
+\.
+
+
+--
+-- Data for Name: refresh_tokens; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.refresh_tokens (refresh_token, created_at, expires_at, user_id) FROM stdin;
+\.
+
+
+--
+-- Data for Name: roles; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.roles (role) FROM stdin;
+user
+anonymous
+me
+\.
+
+
+--
+-- Data for Name: user_providers; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.user_providers (id, created_at, updated_at, user_id, access_token, refresh_token, provider_id, provider_user_id) FROM stdin;
+\.
+
+
+--
+-- Data for Name: user_roles; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.user_roles (id, created_at, user_id, role) FROM stdin;
+31f489e2-18a2-446f-989d-5c51aa490d38 2023-05-11 05:01:30.97538+00 d148130e-b92f-4aed-ba91-7885a988dbad me
+fefa3f20-6d80-4593-8753-09c29cf5446a 2023-05-11 05:01:30.97538+00 d148130e-b92f-4aed-ba91-7885a988dbad user
+\.
+
+
+--
+-- Data for Name: user_security_keys; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.user_security_keys (id, user_id, credential_id, credential_public_key, counter, transports, nickname) FROM stdin;
+\.
+
+
+--
+-- Data for Name: users; Type: TABLE DATA; Schema: auth; Owner: nhost_auth_admin
+--
+
+COPY auth.users (id, created_at, updated_at, last_seen, disabled, display_name, avatar_url, locale, email, phone_number, password_hash, email_verified, phone_number_verified, new_email, otp_method_last_used, otp_hash, otp_hash_expires_at, default_role, is_anonymous, totp_secret, active_mfa_type, ticket, ticket_expires_at, metadata, webauthn_current_challenge) FROM stdin;
+d148130e-b92f-4aed-ba91-7885a988dbad 2023-05-11 05:01:30.97538+00 2023-05-11 05:01:30.97538+00 \N f test@test.com https://s.gravatar.com/avatar/b642b4217b34b1e8d3bd915fc65c4452?r=g&default=blank en test@test.com \N $2a$10$J77xU.nuyH2f/6k1jfsn..Mty1i9dMeuKQdMcuBAqLcrDW7f9vKoK f f \N \N \N 2023-05-11 05:01:30.97538+00 user f \N \N verifyEmail:872dc13f-c73d-43a7-ad7b-bd88d0a8e43c 2023-06-10 05:01:30.967+00 {} \N
+\.
+
+
+--
+-- Data for Name: hdb_action_log; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_action_log (id, action_name, input_payload, request_headers, session_variables, response_payload, errors, created_at, response_received_at, status) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hdb_cron_event_invocation_logs; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_cron_event_invocation_logs (id, event_id, status, request, response, created_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hdb_cron_events; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_cron_events (id, trigger_name, scheduled_time, status, tries, created_at, next_retry_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hdb_metadata; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_metadata (id, metadata, resource_version) FROM stdin;
+1 {"sources":[{"configuration":{"connection_info":{"database_url":{"from_env":"HASURA_GRAPHQL_DATABASE_URL"},"isolation_level":"read-committed","pool_settings":{"connection_lifetime":600,"idle_timeout":180,"max_connections":50,"retries":1},"use_prepared_statements":true}},"kind":"postgres","name":"default","tables":[{"configuration":{"column_config":{"id":{"custom_name":"id"},"options":{"custom_name":"options"}},"custom_column_names":{"id":"id","options":"options"},"custom_name":"authProviderRequests","custom_root_fields":{"delete":"deleteAuthProviderRequests","delete_by_pk":"deleteAuthProviderRequest","insert":"insertAuthProviderRequests","insert_one":"insertAuthProviderRequest","select":"authProviderRequests","select_aggregate":"authProviderRequestsAggregate","select_by_pk":"authProviderRequest","update":"updateAuthProviderRequests","update_by_pk":"updateAuthProviderRequest"}},"table":{"name":"provider_requests","schema":"auth"}},{"array_relationships":[{"name":"userProviders","using":{"foreign_key_constraint_on":{"column":"provider_id","table":{"name":"user_providers","schema":"auth"}}}}],"configuration":{"column_config":{"id":{"custom_name":"id"}},"custom_column_names":{"id":"id"},"custom_name":"authProviders","custom_root_fields":{"delete":"deleteAuthProviders","delete_by_pk":"deleteAuthProvider","insert":"insertAuthProviders","insert_one":"insertAuthProvider","select":"authProviders","select_aggregate":"authProvidersAggregate","select_by_pk":"authProvider","update":"updateAuthProviders","update_by_pk":"updateAuthProvider"}},"table":{"name":"providers","schema":"auth"}},{"configuration":{"column_config":{"created_at":{"custom_name":"createdAt"},"expires_at":{"custom_name":"expiresAt"},"refresh_token":{"custom_name":"refreshToken"},"refresh_token_hash":{"custom_name":"refreshTokenHash"},"user_id":{"custom_name":"userId"}},"custom_column_names":{"created_at":"createdAt","expires_at":"expiresAt","refresh_token":"refreshToken","refresh_token_hash":"refreshTokenHash","user_id":"userId"},"custom_name":"authRefreshTokens","custom_root_fields":{"delete":"deleteAuthRefreshTokens","delete_by_pk":"deleteAuthRefreshToken","insert":"insertAuthRefreshTokens","insert_one":"insertAuthRefreshToken","select":"authRefreshTokens","select_aggregate":"authRefreshTokensAggregate","select_by_pk":"authRefreshToken","update":"updateAuthRefreshTokens","update_by_pk":"updateAuthRefreshToken"}},"object_relationships":[{"name":"user","using":{"foreign_key_constraint_on":"user_id"}}],"table":{"name":"refresh_tokens","schema":"auth"}},{"array_relationships":[{"name":"userRoles","using":{"foreign_key_constraint_on":{"column":"role","table":{"name":"user_roles","schema":"auth"}}}},{"name":"usersByDefaultRole","using":{"foreign_key_constraint_on":{"column":"default_role","table":{"name":"users","schema":"auth"}}}}],"configuration":{"column_config":{"role":{"custom_name":"role"}},"custom_column_names":{"role":"role"},"custom_name":"authRoles","custom_root_fields":{"delete":"deleteAuthRoles","delete_by_pk":"deleteAuthRole","insert":"insertAuthRoles","insert_one":"insertAuthRole","select":"authRoles","select_aggregate":"authRolesAggregate","select_by_pk":"authRole","update":"updateAuthRoles","update_by_pk":"updateAuthRole"}},"table":{"name":"roles","schema":"auth"}},{"configuration":{"column_config":{"access_token":{"custom_name":"accessToken"},"created_at":{"custom_name":"createdAt"},"id":{"custom_name":"id"},"provider_id":{"custom_name":"providerId"},"provider_user_id":{"custom_name":"providerUserId"},"refresh_token":{"custom_name":"refreshToken"},"updated_at":{"custom_name":"updatedAt"},"user_id":{"custom_name":"userId"}},"custom_column_names":{"access_token":"accessToken","created_at":"createdAt","id":"id","provider_id":"providerId","provider_user_id":"providerUserId","refresh_token":"refreshToken","updated_at":"updatedAt","user_id":"userId"},"custom_name":"authUserProviders","custom_root_fields":{"delete":"deleteAuthUserProviders","delete_by_pk":"deleteAuthUserProvider","insert":"insertAuthUserProviders","insert_one":"insertAuthUserProvider","select":"authUserProviders","select_aggregate":"authUserProvidersAggregate","select_by_pk":"authUserProvider","update":"updateAuthUserProviders","update_by_pk":"updateAuthUserProvider"}},"object_relationships":[{"name":"provider","using":{"foreign_key_constraint_on":"provider_id"}},{"name":"user","using":{"foreign_key_constraint_on":"user_id"}}],"table":{"name":"user_providers","schema":"auth"}},{"configuration":{"column_config":{"created_at":{"custom_name":"createdAt"},"id":{"custom_name":"id"},"role":{"custom_name":"role"},"user_id":{"custom_name":"userId"}},"custom_column_names":{"created_at":"createdAt","id":"id","role":"role","user_id":"userId"},"custom_name":"authUserRoles","custom_root_fields":{"delete":"deleteAuthUserRoles","delete_by_pk":"deleteAuthUserRole","insert":"insertAuthUserRoles","insert_one":"insertAuthUserRole","select":"authUserRoles","select_aggregate":"authUserRolesAggregate","select_by_pk":"authUserRole","update":"updateAuthUserRoles","update_by_pk":"updateAuthUserRole"}},"object_relationships":[{"name":"roleByRole","using":{"foreign_key_constraint_on":"role"}},{"name":"user","using":{"foreign_key_constraint_on":"user_id"}}],"table":{"name":"user_roles","schema":"auth"}},{"configuration":{"column_config":{"credential_id":{"custom_name":"credentialId"},"credential_public_key":{"custom_name":"credentialPublicKey"},"id":{"custom_name":"id"},"user_id":{"custom_name":"userId"}},"custom_column_names":{"credential_id":"credentialId","credential_public_key":"credentialPublicKey","id":"id","user_id":"userId"},"custom_name":"authUserSecurityKeys","custom_root_fields":{"delete":"deleteAuthUserSecurityKeys","delete_by_pk":"deleteAuthUserSecurityKey","insert":"insertAuthUserSecurityKeys","insert_one":"insertAuthUserSecurityKey","select":"authUserSecurityKeys","select_aggregate":"authUserSecurityKeysAggregate","select_by_pk":"authUserSecurityKey","update":"updateAuthUserSecurityKeys","update_by_pk":"updateAuthUserSecurityKey"}},"object_relationships":[{"name":"user","using":{"foreign_key_constraint_on":"user_id"}}],"table":{"name":"user_security_keys","schema":"auth"}},{"array_relationships":[{"name":"refreshTokens","using":{"foreign_key_constraint_on":{"column":"user_id","table":{"name":"refresh_tokens","schema":"auth"}}}},{"name":"roles","using":{"foreign_key_constraint_on":{"column":"user_id","table":{"name":"user_roles","schema":"auth"}}}},{"name":"securityKeys","using":{"foreign_key_constraint_on":{"column":"user_id","table":{"name":"user_security_keys","schema":"auth"}}}},{"name":"userProviders","using":{"foreign_key_constraint_on":{"column":"user_id","table":{"name":"user_providers","schema":"auth"}}}}],"configuration":{"column_config":{"active_mfa_type":{"custom_name":"activeMfaType"},"avatar_url":{"custom_name":"avatarUrl"},"created_at":{"custom_name":"createdAt"},"default_role":{"custom_name":"defaultRole"},"disabled":{"custom_name":"disabled"},"display_name":{"custom_name":"displayName"},"email":{"custom_name":"email"},"email_verified":{"custom_name":"emailVerified"},"id":{"custom_name":"id"},"is_anonymous":{"custom_name":"isAnonymous"},"last_seen":{"custom_name":"lastSeen"},"locale":{"custom_name":"locale"},"new_email":{"custom_name":"newEmail"},"otp_hash":{"custom_name":"otpHash"},"otp_hash_expires_at":{"custom_name":"otpHashExpiresAt"},"otp_method_last_used":{"custom_name":"otpMethodLastUsed"},"password_hash":{"custom_name":"passwordHash"},"phone_number":{"custom_name":"phoneNumber"},"phone_number_verified":{"custom_name":"phoneNumberVerified"},"ticket":{"custom_name":"ticket"},"ticket_expires_at":{"custom_name":"ticketExpiresAt"},"totp_secret":{"custom_name":"totpSecret"},"updated_at":{"custom_name":"updatedAt"},"webauthn_current_challenge":{"custom_name":"currentChallenge"}},"custom_column_names":{"active_mfa_type":"activeMfaType","avatar_url":"avatarUrl","created_at":"createdAt","default_role":"defaultRole","disabled":"disabled","display_name":"displayName","email":"email","email_verified":"emailVerified","id":"id","is_anonymous":"isAnonymous","last_seen":"lastSeen","locale":"locale","new_email":"newEmail","otp_hash":"otpHash","otp_hash_expires_at":"otpHashExpiresAt","otp_method_last_used":"otpMethodLastUsed","password_hash":"passwordHash","phone_number":"phoneNumber","phone_number_verified":"phoneNumberVerified","ticket":"ticket","ticket_expires_at":"ticketExpiresAt","totp_secret":"totpSecret","updated_at":"updatedAt","webauthn_current_challenge":"currentChallenge"},"custom_name":"users","custom_root_fields":{"delete":"deleteUsers","delete_by_pk":"deleteUser","insert":"insertUsers","insert_one":"insertUser","select":"users","select_aggregate":"usersAggregate","select_by_pk":"user","update":"updateUsers","update_by_pk":"updateUser"}},"object_relationships":[{"name":"defaultRoleByRole","using":{"foreign_key_constraint_on":"default_role"}}],"table":{"name":"users","schema":"auth"}},{"table":{"name":"data_test","schema":"public"}},{"table":{"name":"test_table_1","schema":"public"}},{"array_relationships":[{"name":"files","using":{"foreign_key_constraint_on":{"column":"bucket_id","table":{"name":"files","schema":"storage"}}}}],"configuration":{"column_config":{"cache_control":{"custom_name":"cacheControl"},"created_at":{"custom_name":"createdAt"},"download_expiration":{"custom_name":"downloadExpiration"},"id":{"custom_name":"id"},"max_upload_file_size":{"custom_name":"maxUploadFileSize"},"min_upload_file_size":{"custom_name":"minUploadFileSize"},"presigned_urls_enabled":{"custom_name":"presignedUrlsEnabled"},"updated_at":{"custom_name":"updatedAt"}},"custom_column_names":{"cache_control":"cacheControl","created_at":"createdAt","download_expiration":"downloadExpiration","id":"id","max_upload_file_size":"maxUploadFileSize","min_upload_file_size":"minUploadFileSize","presigned_urls_enabled":"presignedUrlsEnabled","updated_at":"updatedAt"},"custom_name":"buckets","custom_root_fields":{"delete":"deleteBuckets","delete_by_pk":"deleteBucket","insert":"insertBuckets","insert_one":"insertBucket","select":"buckets","select_aggregate":"bucketsAggregate","select_by_pk":"bucket","update":"updateBuckets","update_by_pk":"updateBucket"}},"table":{"name":"buckets","schema":"storage"}},{"configuration":{"column_config":{"bucket_id":{"custom_name":"bucketId"},"created_at":{"custom_name":"createdAt"},"etag":{"custom_name":"etag"},"id":{"custom_name":"id"},"is_uploaded":{"custom_name":"isUploaded"},"mime_type":{"custom_name":"mimeType"},"name":{"custom_name":"name"},"size":{"custom_name":"size"},"updated_at":{"custom_name":"updatedAt"},"uploaded_by_user_id":{"custom_name":"uploadedByUserId"}},"custom_column_names":{"bucket_id":"bucketId","created_at":"createdAt","etag":"etag","id":"id","is_uploaded":"isUploaded","mime_type":"mimeType","name":"name","size":"size","updated_at":"updatedAt","uploaded_by_user_id":"uploadedByUserId"},"custom_name":"files","custom_root_fields":{"delete":"deleteFiles","delete_by_pk":"deleteFile","insert":"insertFiles","insert_one":"insertFile","select":"files","select_aggregate":"filesAggregate","select_by_pk":"file","update":"updateFiles","update_by_pk":"updateFile"}},"object_relationships":[{"name":"bucket","using":{"foreign_key_constraint_on":"bucket_id"}}],"table":{"name":"files","schema":"storage"}}]}],"version":3} 21
+\.
+
+
+--
+-- Data for Name: hdb_scheduled_event_invocation_logs; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_scheduled_event_invocation_logs (id, event_id, status, request, response, created_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hdb_scheduled_events; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_scheduled_events (id, webhook_conf, scheduled_time, retry_conf, payload, header_conf, status, tries, created_at, next_retry_at, comment) FROM stdin;
+\.
+
+
+--
+-- Data for Name: hdb_schema_notifications; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_schema_notifications (id, notification, resource_version, instance_id, updated_at) FROM stdin;
+1 {"metadata":false,"remote_schemas":[],"sources":[],"data_connectors":[]} 21 99337c5e-5108-4930-aaf3-66e079655667 2023-04-18 03:08:07.470393+00
+\.
+
+
+--
+-- Data for Name: hdb_version; Type: TABLE DATA; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+COPY hdb_catalog.hdb_version (hasura_uuid, version, upgraded_on, cli_state, console_state) FROM stdin;
+1e3c7077-3b31-4c5d-b58b-dc7f7c1d84f9 47 2023-04-18 03:07:45.413334+00 {} {"console_notifications": {"admin": {"date": "2023-05-10T12:50:38.771Z", "read": [], "showBadge": false}}, "telemetryNotificationShown": true}
+\.
+
+
+--
+-- Data for Name: data_test; Type: TABLE DATA; Schema: public; Owner: nhost_hasura
+--
+
+COPY public.data_test (text, charvar, "char", uuid, json, jsonb, "smallint", "integer", "bigint", "decimal", "numeric", "real", double_precision, bool, date, "timestamp", timestamptz, "time", timetz, "interval", bytea, money) FROM stdin;
+text charvar bpchar c7654b8a-4e90-4da3-aff1-d58d804d1ac2 {"hello": "world!"} {"hello": "world!"} 32767 2147483647 9223372036854775807 131072 1000 100 100 t 2023-05-26 2023-05-26 10:54:23 2023-05-26 10:54:23+00 10:54:23 2023-05-26 10:54:23+00 34293:33:09 \\x68656c6c6f21 $20.23
+\.
+
+
+--
+-- Data for Name: test_table_1; Type: TABLE DATA; Schema: public; Owner: nhost_hasura
+--
+
+COPY public.test_table_1 (name, uuid, user_data, json_binary) FROM stdin;
+Sarah 22598e7c-3f7d-4d94-9690-67ad925e17ce { "name": "Sarah", "data": { "test": "Test" } } {"text": "hello world!"}
+\.
+
+
+--
+-- Data for Name: buckets; Type: TABLE DATA; Schema: storage; Owner: nhost_storage_admin
+--
+
+COPY storage.buckets (id, created_at, updated_at, download_expiration, min_upload_file_size, max_upload_file_size, cache_control, presigned_urls_enabled) FROM stdin;
+default 2023-04-18 03:07:31.49138+00 2023-04-18 03:07:31.49138+00 30 1 50000000 max-age=3600 t
+\.
+
+
+--
+-- Data for Name: files; Type: TABLE DATA; Schema: storage; Owner: nhost_storage_admin
+--
+
+COPY storage.files (id, created_at, updated_at, bucket_id, name, size, mime_type, etag, is_uploaded, uploaded_by_user_id) FROM stdin;
+fda0ec19-8d12-418d-be2f-c534653f7510 2023-05-10 11:27:09.487996+00 2023-05-10 11:27:09.919043+00 default 1 15728640 application/octet-stream "bf787d648d170d6a601792ce759705e1" t \N
+\.
+
+
+--
+-- Data for Name: schema_migrations; Type: TABLE DATA; Schema: storage; Owner: nhost_storage_admin
+--
+
+COPY storage.schema_migrations (version, dirty) FROM stdin;
+3 f
+\.
+
+
+--
+-- Name: migrations migrations_name_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.migrations
+ ADD CONSTRAINT migrations_name_key UNIQUE (name);
+
+
+--
+-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.migrations
+ ADD CONSTRAINT migrations_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: provider_requests provider_requests_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.provider_requests
+ ADD CONSTRAINT provider_requests_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: providers providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.providers
+ ADD CONSTRAINT providers_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: refresh_tokens refresh_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens
+ ADD CONSTRAINT refresh_tokens_pkey PRIMARY KEY (refresh_token);
+
+
+--
+-- Name: roles roles_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.roles
+ ADD CONSTRAINT roles_pkey PRIMARY KEY (role);
+
+
+--
+-- Name: user_providers user_providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_providers
+ ADD CONSTRAINT user_providers_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: user_providers user_providers_provider_id_provider_user_id_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_providers
+ ADD CONSTRAINT user_providers_provider_id_provider_user_id_key UNIQUE (provider_id, provider_user_id);
+
+
+--
+-- Name: user_providers user_providers_user_id_provider_id_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_providers
+ ADD CONSTRAINT user_providers_user_id_provider_id_key UNIQUE (user_id, provider_id);
+
+
+--
+-- Name: user_roles user_roles_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_roles
+ ADD CONSTRAINT user_roles_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: user_roles user_roles_user_id_role_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_roles
+ ADD CONSTRAINT user_roles_user_id_role_key UNIQUE (user_id, role);
+
+
+--
+-- Name: user_security_keys user_security_key_credential_id_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_security_keys
+ ADD CONSTRAINT user_security_key_credential_id_key UNIQUE (credential_id);
+
+
+--
+-- Name: user_security_keys user_security_keys_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_security_keys
+ ADD CONSTRAINT user_security_keys_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: users users_email_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT users_email_key UNIQUE (email);
+
+
+--
+-- Name: users users_phone_number_key; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT users_phone_number_key UNIQUE (phone_number);
+
+
+--
+-- Name: users users_pkey; Type: CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT users_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_action_log hdb_action_log_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_action_log
+ ADD CONSTRAINT hdb_action_log_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_cron_event_invocation_logs hdb_cron_event_invocation_logs_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_cron_event_invocation_logs
+ ADD CONSTRAINT hdb_cron_event_invocation_logs_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_cron_events hdb_cron_events_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_cron_events
+ ADD CONSTRAINT hdb_cron_events_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_metadata hdb_metadata_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_metadata
+ ADD CONSTRAINT hdb_metadata_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_metadata hdb_metadata_resource_version_key; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_metadata
+ ADD CONSTRAINT hdb_metadata_resource_version_key UNIQUE (resource_version);
+
+
+--
+-- Name: hdb_scheduled_event_invocation_logs hdb_scheduled_event_invocation_logs_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_scheduled_event_invocation_logs
+ ADD CONSTRAINT hdb_scheduled_event_invocation_logs_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_scheduled_events hdb_scheduled_events_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_scheduled_events
+ ADD CONSTRAINT hdb_scheduled_events_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_schema_notifications hdb_schema_notifications_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_schema_notifications
+ ADD CONSTRAINT hdb_schema_notifications_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: hdb_version hdb_version_pkey; Type: CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_version
+ ADD CONSTRAINT hdb_version_pkey PRIMARY KEY (hasura_uuid);
+
+
+--
+-- Name: data_test data_test_pkey; Type: CONSTRAINT; Schema: public; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY public.data_test
+ ADD CONSTRAINT data_test_pkey PRIMARY KEY (text);
+
+
+--
+-- Name: test_table_1 test_table_1_pkey; Type: CONSTRAINT; Schema: public; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY public.test_table_1
+ ADD CONSTRAINT test_table_1_pkey PRIMARY KEY (name);
+
+
+--
+-- Name: test_table_1 test_table_1_uuid_key; Type: CONSTRAINT; Schema: public; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY public.test_table_1
+ ADD CONSTRAINT test_table_1_uuid_key UNIQUE (uuid);
+
+
+--
+-- Name: buckets buckets_pkey; Type: CONSTRAINT; Schema: storage; Owner: nhost_storage_admin
+--
+
+ALTER TABLE ONLY storage.buckets
+ ADD CONSTRAINT buckets_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: files files_pkey; Type: CONSTRAINT; Schema: storage; Owner: nhost_storage_admin
+--
+
+ALTER TABLE ONLY storage.files
+ ADD CONSTRAINT files_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: storage; Owner: nhost_storage_admin
+--
+
+ALTER TABLE ONLY storage.schema_migrations
+ ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
+
+
+--
+-- Name: hdb_cron_event_invocation_event_id; Type: INDEX; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE INDEX hdb_cron_event_invocation_event_id ON hdb_catalog.hdb_cron_event_invocation_logs USING btree (event_id);
+
+
+--
+-- Name: hdb_cron_event_status; Type: INDEX; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE INDEX hdb_cron_event_status ON hdb_catalog.hdb_cron_events USING btree (status);
+
+
+--
+-- Name: hdb_cron_events_unique_scheduled; Type: INDEX; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE UNIQUE INDEX hdb_cron_events_unique_scheduled ON hdb_catalog.hdb_cron_events USING btree (trigger_name, scheduled_time) WHERE (status = 'scheduled'::text);
+
+
+--
+-- Name: hdb_scheduled_event_status; Type: INDEX; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE INDEX hdb_scheduled_event_status ON hdb_catalog.hdb_scheduled_events USING btree (status);
+
+
+--
+-- Name: hdb_version_one_row; Type: INDEX; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+CREATE UNIQUE INDEX hdb_version_one_row ON hdb_catalog.hdb_version USING btree (((version IS NOT NULL)));
+
+
+--
+-- Name: user_providers set_auth_user_providers_updated_at; Type: TRIGGER; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TRIGGER set_auth_user_providers_updated_at BEFORE UPDATE ON auth.user_providers FOR EACH ROW EXECUTE FUNCTION auth.set_current_timestamp_updated_at();
+
+
+--
+-- Name: users set_auth_users_updated_at; Type: TRIGGER; Schema: auth; Owner: nhost_auth_admin
+--
+
+CREATE TRIGGER set_auth_users_updated_at BEFORE UPDATE ON auth.users FOR EACH ROW EXECUTE FUNCTION auth.set_current_timestamp_updated_at();
+
+
+--
+-- Name: buckets check_default_bucket_delete; Type: TRIGGER; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TRIGGER check_default_bucket_delete BEFORE DELETE ON storage.buckets FOR EACH ROW EXECUTE FUNCTION storage.protect_default_bucket_delete();
+
+
+--
+-- Name: buckets check_default_bucket_update; Type: TRIGGER; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TRIGGER check_default_bucket_update BEFORE UPDATE ON storage.buckets FOR EACH ROW EXECUTE FUNCTION storage.protect_default_bucket_update();
+
+
+--
+-- Name: buckets set_storage_buckets_updated_at; Type: TRIGGER; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TRIGGER set_storage_buckets_updated_at BEFORE UPDATE ON storage.buckets FOR EACH ROW EXECUTE FUNCTION storage.set_current_timestamp_updated_at();
+
+
+--
+-- Name: files set_storage_files_updated_at; Type: TRIGGER; Schema: storage; Owner: nhost_storage_admin
+--
+
+CREATE TRIGGER set_storage_files_updated_at BEFORE UPDATE ON storage.files FOR EACH ROW EXECUTE FUNCTION storage.set_current_timestamp_updated_at();
+
+
+--
+-- Name: users fk_default_role; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT fk_default_role FOREIGN KEY (default_role) REFERENCES auth.roles(role) ON UPDATE CASCADE ON DELETE RESTRICT;
+
+
+--
+-- Name: user_providers fk_provider; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_providers
+ ADD CONSTRAINT fk_provider FOREIGN KEY (provider_id) REFERENCES auth.providers(id) ON UPDATE CASCADE ON DELETE RESTRICT;
+
+
+--
+-- Name: user_roles fk_role; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_roles
+ ADD CONSTRAINT fk_role FOREIGN KEY (role) REFERENCES auth.roles(role) ON UPDATE CASCADE ON DELETE RESTRICT;
+
+
+--
+-- Name: user_providers fk_user; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_providers
+ ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: user_roles fk_user; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_roles
+ ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: refresh_tokens fk_user; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens
+ ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: user_security_keys fk_user; Type: FK CONSTRAINT; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER TABLE ONLY auth.user_security_keys
+ ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES auth.users(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: hdb_cron_event_invocation_logs hdb_cron_event_invocation_logs_event_id_fkey; Type: FK CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_cron_event_invocation_logs
+ ADD CONSTRAINT hdb_cron_event_invocation_logs_event_id_fkey FOREIGN KEY (event_id) REFERENCES hdb_catalog.hdb_cron_events(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: hdb_scheduled_event_invocation_logs hdb_scheduled_event_invocation_logs_event_id_fkey; Type: FK CONSTRAINT; Schema: hdb_catalog; Owner: nhost_hasura
+--
+
+ALTER TABLE ONLY hdb_catalog.hdb_scheduled_event_invocation_logs
+ ADD CONSTRAINT hdb_scheduled_event_invocation_logs_event_id_fkey FOREIGN KEY (event_id) REFERENCES hdb_catalog.hdb_scheduled_events(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: files fk_bucket; Type: FK CONSTRAINT; Schema: storage; Owner: nhost_storage_admin
+--
+
+ALTER TABLE ONLY storage.files
+ ADD CONSTRAINT fk_bucket FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: SCHEMA auth; Type: ACL; Schema: -; Owner: nhost_admin
+--
+
+GRANT ALL ON SCHEMA auth TO nhost_auth_admin;
+GRANT USAGE ON SCHEMA auth TO nhost_hasura;
+
+
+--
+-- Name: SCHEMA pgbouncer; Type: ACL; Schema: -; Owner: nhost_admin
+--
+
+GRANT USAGE ON SCHEMA pgbouncer TO pgbouncer;
+
+
+--
+-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE USAGE ON SCHEMA public FROM PUBLIC;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+GRANT USAGE ON SCHEMA public TO nhost_hasura;
+
+
+--
+-- Name: SCHEMA storage; Type: ACL; Schema: -; Owner: nhost_admin
+--
+
+GRANT ALL ON SCHEMA storage TO nhost_storage_admin;
+GRANT USAGE ON SCHEMA storage TO nhost_hasura;
+
+
+--
+-- Name: FUNCTION user_lookup(i_username text, OUT uname text, OUT phash text); Type: ACL; Schema: pgbouncer; Owner: postgres
+--
+
+REVOKE ALL ON FUNCTION pgbouncer.user_lookup(i_username text, OUT uname text, OUT phash text) FROM PUBLIC;
+GRANT ALL ON FUNCTION pgbouncer.user_lookup(i_username text, OUT uname text, OUT phash text) TO pgbouncer;
+
+
+--
+-- Name: TABLE migrations; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.migrations TO nhost_hasura;
+
+
+--
+-- Name: TABLE provider_requests; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.provider_requests TO nhost_hasura;
+
+
+--
+-- Name: TABLE providers; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.providers TO nhost_hasura;
+
+
+--
+-- Name: TABLE refresh_tokens; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.refresh_tokens TO nhost_hasura;
+
+
+--
+-- Name: TABLE roles; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.roles TO nhost_hasura;
+
+
+--
+-- Name: TABLE user_providers; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.user_providers TO nhost_hasura;
+
+
+--
+-- Name: TABLE user_roles; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.user_roles TO nhost_hasura;
+
+
+--
+-- Name: TABLE user_security_keys; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.user_security_keys TO nhost_hasura;
+
+
+--
+-- Name: TABLE users; Type: ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+GRANT ALL ON TABLE auth.users TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_aggregate; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_aggregate TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_am; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_am TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_amop; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_amop TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_amproc; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_amproc TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_attrdef; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_attrdef TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_attribute; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_attribute TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_auth_members; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_auth_members TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_authid; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_authid TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_available_extension_versions; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_available_extension_versions TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_available_extensions; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_available_extensions TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_backend_memory_contexts; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_backend_memory_contexts TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_cast; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_cast TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_class; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_class TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_collation; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_collation TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_config; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_config TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_constraint; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_constraint TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_conversion; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_conversion TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_cursors; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_cursors TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_database; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_database TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_db_role_setting; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_db_role_setting TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_default_acl; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_default_acl TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_depend; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_depend TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_description; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_description TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_enum; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_enum TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_event_trigger; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_event_trigger TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_extension; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_extension TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_file_settings; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_file_settings TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_foreign_data_wrapper; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_foreign_data_wrapper TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_foreign_server; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_foreign_server TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_foreign_table; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_foreign_table TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_group; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_group TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_hba_file_rules; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_hba_file_rules TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_index; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_index TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_inherits; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_inherits TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_init_privs; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_init_privs TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_language; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_language TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_largeobject; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_largeobject TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_largeobject_metadata; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_largeobject_metadata TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_locks; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_locks TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_matviews; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_matviews TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_namespace; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_namespace TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_opclass; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_opclass TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_operator; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_operator TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_opfamily; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_opfamily TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_partitioned_table; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_partitioned_table TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_policies; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_policies TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_policy; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_policy TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_prepared_statements; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_prepared_statements TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_prepared_xacts; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_prepared_xacts TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_proc; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_proc TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_publication; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_publication TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_publication_rel; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_publication_rel TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_publication_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_publication_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_range; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_range TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_replication_origin; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_replication_origin TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_replication_origin_status; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_replication_origin_status TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_replication_slots; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_replication_slots TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_rewrite; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_rewrite TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_roles; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_roles TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_rules; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_rules TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_seclabel; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_seclabel TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_seclabels; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_seclabels TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_sequence; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_sequence TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_sequences; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_sequences TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_settings; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_settings TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_shadow; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_shadow TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_shdepend; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_shdepend TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_shdescription; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_shdescription TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_shmem_allocations; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_shmem_allocations TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_shseclabel; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_shseclabel TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_activity; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_activity TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_all_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_all_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_all_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_all_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_archiver; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_archiver TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_bgwriter; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_bgwriter TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_database; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_database TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_database_conflicts; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_database_conflicts TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_gssapi; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_gssapi TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_analyze; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_analyze TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_basebackup; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_basebackup TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_cluster; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_cluster TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_copy; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_copy TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_create_index; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_create_index TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_progress_vacuum; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_progress_vacuum TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_replication; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_replication TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_replication_slots; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_replication_slots TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_slru; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_slru TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_ssl; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_ssl TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_subscription; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_subscription TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_sys_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_sys_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_sys_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_sys_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_user_functions; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_user_functions TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_user_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_user_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_user_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_user_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_wal; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_wal TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_wal_receiver; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_wal_receiver TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_xact_all_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_xact_all_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_xact_sys_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_xact_sys_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_xact_user_functions; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_xact_user_functions TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stat_xact_user_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stat_xact_user_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_all_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_all_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_all_sequences; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_all_sequences TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_all_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_all_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_sys_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_sys_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_sys_sequences; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_sys_sequences TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_sys_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_sys_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_user_indexes; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_user_indexes TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_user_sequences; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_user_sequences TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statio_user_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statio_user_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statistic; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statistic TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statistic_ext; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statistic_ext TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_statistic_ext_data; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_statistic_ext_data TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stats; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stats TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stats_ext; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stats_ext TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_stats_ext_exprs; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_stats_ext_exprs TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_subscription; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_subscription TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_subscription_rel; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_subscription_rel TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_tables; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_tables TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_tablespace; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_tablespace TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_timezone_abbrevs; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_timezone_abbrevs TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_timezone_names; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_timezone_names TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_transform; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_transform TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_trigger; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_trigger TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_ts_config; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_ts_config TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_ts_config_map; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_ts_config_map TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_ts_dict; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_ts_dict TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_ts_parser; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_ts_parser TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_ts_template; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_ts_template TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_type; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_type TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_user; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_user TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_user_mapping; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_user_mapping TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_user_mappings; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_user_mappings TO nhost_hasura;
+
+
+--
+-- Name: TABLE pg_views; Type: ACL; Schema: pg_catalog; Owner: postgres
+--
+
+GRANT SELECT ON TABLE pg_catalog.pg_views TO nhost_hasura;
+
+
+--
+-- Name: TABLE buckets; Type: ACL; Schema: storage; Owner: nhost_storage_admin
+--
+
+GRANT ALL ON TABLE storage.buckets TO nhost_hasura;
+
+
+--
+-- Name: TABLE files; Type: ACL; Schema: storage; Owner: nhost_storage_admin
+--
+
+GRANT ALL ON TABLE storage.files TO nhost_hasura;
+
+
+--
+-- Name: TABLE schema_migrations; Type: ACL; Schema: storage; Owner: nhost_storage_admin
+--
+
+GRANT ALL ON TABLE storage.schema_migrations TO nhost_hasura;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: auth; Owner: nhost_auth_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE nhost_auth_admin IN SCHEMA auth GRANT ALL ON TABLES TO nhost_hasura;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: storage; Owner: nhost_storage_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE nhost_storage_admin IN SCHEMA storage GRANT ALL ON TABLES TO nhost_hasura;
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/tests/Transfer/resources/restore.sh b/tests/Transfer/resources/restore.sh
new file mode 100644
index 00000000..45c8b7f6
--- /dev/null
+++ b/tests/Transfer/resources/restore.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+set -e
+pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" -F t /docker-entrypoint-initdb.d/backup.tar
\ No newline at end of file
diff --git a/tests/Transfer/resources/supabase/backup.tar b/tests/Transfer/resources/supabase/backup.tar
new file mode 100644
index 00000000..ac30a06d
--- /dev/null
+++ b/tests/Transfer/resources/supabase/backup.tar
@@ -0,0 +1,4405 @@
+--
+-- PostgreSQL database dump
+--
+
+-- Dumped from database version 15.1
+-- Dumped by pg_dump version 15.2
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET idle_in_transaction_session_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SELECT pg_catalog.set_config('search_path', '', false);
+SET check_function_bodies = false;
+SET xmloption = content;
+SET client_min_messages = warning;
+SET row_security = off;
+
+--
+-- Name: auth; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA auth;
+
+
+ALTER SCHEMA auth OWNER TO supabase_admin;
+
+--
+-- Name: extensions; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA extensions;
+
+
+ALTER SCHEMA extensions OWNER TO postgres;
+
+--
+-- Name: graphql; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA graphql;
+
+
+ALTER SCHEMA graphql OWNER TO supabase_admin;
+
+--
+-- Name: graphql_public; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA graphql_public;
+
+
+ALTER SCHEMA graphql_public OWNER TO supabase_admin;
+
+--
+-- Name: pgbouncer; Type: SCHEMA; Schema: -; Owner: pgbouncer
+--
+
+CREATE SCHEMA pgbouncer;
+
+
+ALTER SCHEMA pgbouncer OWNER TO pgbouncer;
+
+--
+-- Name: pgsodium; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+CREATE SCHEMA pgsodium;
+
+
+ALTER SCHEMA pgsodium OWNER TO postgres;
+
+--
+-- Name: pgsodium; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pgsodium WITH SCHEMA pgsodium;
+
+
+--
+-- Name: EXTENSION pgsodium; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pgsodium IS 'Pgsodium is a modern cryptography library for Postgres.';
+
+
+--
+-- Name: pgtle; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA pgtle;
+
+
+ALTER SCHEMA pgtle OWNER TO supabase_admin;
+
+--
+-- Name: public; Type: SCHEMA; Schema: -; Owner: postgres
+--
+
+-- *not* creating schema, since initdb creates it
+
+
+ALTER SCHEMA public OWNER TO postgres;
+
+--
+-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres
+--
+
+COMMENT ON SCHEMA public IS '';
+
+
+--
+-- Name: realtime; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA realtime;
+
+
+ALTER SCHEMA realtime OWNER TO supabase_admin;
+
+--
+-- Name: storage; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA storage;
+
+
+ALTER SCHEMA storage OWNER TO supabase_admin;
+
+--
+-- Name: vault; Type: SCHEMA; Schema: -; Owner: supabase_admin
+--
+
+CREATE SCHEMA vault;
+
+
+ALTER SCHEMA vault OWNER TO supabase_admin;
+
+--
+-- Name: pg_graphql; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pg_graphql WITH SCHEMA graphql;
+
+
+--
+-- Name: EXTENSION pg_graphql; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pg_graphql IS 'pg_graphql: GraphQL support';
+
+
+--
+-- Name: pg_stat_statements; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pg_stat_statements WITH SCHEMA extensions;
+
+
+--
+-- Name: EXTENSION pg_stat_statements; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pg_stat_statements IS 'track planning and execution statistics of all SQL statements executed';
+
+
+--
+-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA extensions;
+
+
+--
+-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions';
+
+
+--
+-- Name: pgjwt; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS pgjwt WITH SCHEMA extensions;
+
+
+--
+-- Name: EXTENSION pgjwt; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION pgjwt IS 'JSON Web Token API for Postgresql';
+
+
+--
+-- Name: supabase_vault; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS supabase_vault WITH SCHEMA vault;
+
+
+--
+-- Name: EXTENSION supabase_vault; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION supabase_vault IS 'Supabase Vault Extension';
+
+
+--
+-- Name: uuid-ossp; Type: EXTENSION; Schema: -; Owner: -
+--
+
+CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA extensions;
+
+
+--
+-- Name: EXTENSION "uuid-ossp"; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION "uuid-ossp" IS 'generate universally unique identifiers (UUIDs)';
+
+
+--
+-- Name: aal_level; Type: TYPE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TYPE auth.aal_level AS ENUM (
+ 'aal1',
+ 'aal2',
+ 'aal3'
+);
+
+
+ALTER TYPE auth.aal_level OWNER TO supabase_auth_admin;
+
+--
+-- Name: code_challenge_method; Type: TYPE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TYPE auth.code_challenge_method AS ENUM (
+ 's256',
+ 'plain'
+);
+
+
+ALTER TYPE auth.code_challenge_method OWNER TO supabase_auth_admin;
+
+--
+-- Name: factor_status; Type: TYPE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TYPE auth.factor_status AS ENUM (
+ 'unverified',
+ 'verified'
+);
+
+
+ALTER TYPE auth.factor_status OWNER TO supabase_auth_admin;
+
+--
+-- Name: factor_type; Type: TYPE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TYPE auth.factor_type AS ENUM (
+ 'totp',
+ 'webauthn'
+);
+
+
+ALTER TYPE auth.factor_type OWNER TO supabase_auth_admin;
+
+--
+-- Name: email(); Type: FUNCTION; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE FUNCTION auth.email() RETURNS text
+ LANGUAGE sql STABLE
+ AS $$
+ select
+ coalesce(
+ nullif(current_setting('request.jwt.claim.email', true), ''),
+ (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email')
+ )::text
+$$;
+
+
+ALTER FUNCTION auth.email() OWNER TO supabase_auth_admin;
+
+--
+-- Name: FUNCTION email(); Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON FUNCTION auth.email() IS 'Deprecated. Use auth.jwt() -> ''email'' instead.';
+
+
+--
+-- Name: jwt(); Type: FUNCTION; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE FUNCTION auth.jwt() RETURNS jsonb
+ LANGUAGE sql STABLE
+ AS $$
+ select
+ coalesce(
+ nullif(current_setting('request.jwt.claim', true), ''),
+ nullif(current_setting('request.jwt.claims', true), '')
+ )::jsonb
+$$;
+
+
+ALTER FUNCTION auth.jwt() OWNER TO supabase_auth_admin;
+
+--
+-- Name: role(); Type: FUNCTION; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE FUNCTION auth.role() RETURNS text
+ LANGUAGE sql STABLE
+ AS $$
+ select
+ coalesce(
+ nullif(current_setting('request.jwt.claim.role', true), ''),
+ (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role')
+ )::text
+$$;
+
+
+ALTER FUNCTION auth.role() OWNER TO supabase_auth_admin;
+
+--
+-- Name: FUNCTION role(); Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON FUNCTION auth.role() IS 'Deprecated. Use auth.jwt() -> ''role'' instead.';
+
+
+--
+-- Name: uid(); Type: FUNCTION; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE FUNCTION auth.uid() RETURNS uuid
+ LANGUAGE sql STABLE
+ AS $$
+ select
+ coalesce(
+ nullif(current_setting('request.jwt.claim.sub', true), ''),
+ (nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
+ )::uuid
+$$;
+
+
+ALTER FUNCTION auth.uid() OWNER TO supabase_auth_admin;
+
+--
+-- Name: FUNCTION uid(); Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON FUNCTION auth.uid() IS 'Deprecated. Use auth.jwt() -> ''sub'' instead.';
+
+
+--
+-- Name: grant_pg_cron_access(); Type: FUNCTION; Schema: extensions; Owner: postgres
+--
+
+CREATE FUNCTION extensions.grant_pg_cron_access() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ schema_is_cron bool;
+BEGIN
+ schema_is_cron = (
+ SELECT n.nspname = 'cron'
+ FROM pg_event_trigger_ddl_commands() AS ev
+ LEFT JOIN pg_catalog.pg_namespace AS n
+ ON ev.objid = n.oid
+ );
+
+ IF schema_is_cron
+ THEN
+ grant usage on schema cron to postgres with grant option;
+
+ alter default privileges in schema cron grant all on tables to postgres with grant option;
+ alter default privileges in schema cron grant all on functions to postgres with grant option;
+ alter default privileges in schema cron grant all on sequences to postgres with grant option;
+
+ alter default privileges for user supabase_admin in schema cron grant all
+ on sequences to postgres with grant option;
+ alter default privileges for user supabase_admin in schema cron grant all
+ on tables to postgres with grant option;
+ alter default privileges for user supabase_admin in schema cron grant all
+ on functions to postgres with grant option;
+
+ grant all privileges on all tables in schema cron to postgres with grant option;
+
+ END IF;
+
+END;
+$$;
+
+
+ALTER FUNCTION extensions.grant_pg_cron_access() OWNER TO postgres;
+
+--
+-- Name: FUNCTION grant_pg_cron_access(); Type: COMMENT; Schema: extensions; Owner: postgres
+--
+
+COMMENT ON FUNCTION extensions.grant_pg_cron_access() IS 'Grants access to pg_cron';
+
+
+--
+-- Name: grant_pg_graphql_access(); Type: FUNCTION; Schema: extensions; Owner: supabase_admin
+--
+
+CREATE FUNCTION extensions.grant_pg_graphql_access() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $_$
+DECLARE
+ func_is_graphql_resolve bool;
+BEGIN
+ func_is_graphql_resolve = (
+ SELECT n.proname = 'resolve'
+ FROM pg_event_trigger_ddl_commands() AS ev
+ LEFT JOIN pg_catalog.pg_proc AS n
+ ON ev.objid = n.oid
+ );
+
+ IF func_is_graphql_resolve
+ THEN
+ -- Update public wrapper to pass all arguments through to the pg_graphql resolve func
+ DROP FUNCTION IF EXISTS graphql_public.graphql;
+ create or replace function graphql_public.graphql(
+ "operationName" text default null,
+ query text default null,
+ variables jsonb default null,
+ extensions jsonb default null
+ )
+ returns jsonb
+ language sql
+ as $$
+ select graphql.resolve(
+ query := query,
+ variables := coalesce(variables, '{}'),
+ "operationName" := "operationName",
+ extensions := extensions
+ );
+ $$;
+
+ -- This hook executes when `graphql.resolve` is created. That is not necessarily the last
+ -- function in the extension so we need to grant permissions on existing entities AND
+ -- update default permissions to any others that are created after `graphql.resolve`
+ grant usage on schema graphql to postgres, anon, authenticated, service_role;
+ grant select on all tables in schema graphql to postgres, anon, authenticated, service_role;
+ grant execute on all functions in schema graphql to postgres, anon, authenticated, service_role;
+ grant all on all sequences in schema graphql to postgres, anon, authenticated, service_role;
+ alter default privileges in schema graphql grant all on tables to postgres, anon, authenticated, service_role;
+ alter default privileges in schema graphql grant all on functions to postgres, anon, authenticated, service_role;
+ alter default privileges in schema graphql grant all on sequences to postgres, anon, authenticated, service_role;
+ END IF;
+
+END;
+$_$;
+
+
+ALTER FUNCTION extensions.grant_pg_graphql_access() OWNER TO supabase_admin;
+
+--
+-- Name: FUNCTION grant_pg_graphql_access(); Type: COMMENT; Schema: extensions; Owner: supabase_admin
+--
+
+COMMENT ON FUNCTION extensions.grant_pg_graphql_access() IS 'Grants access to pg_graphql';
+
+
+--
+-- Name: grant_pg_net_access(); Type: FUNCTION; Schema: extensions; Owner: postgres
+--
+
+CREATE FUNCTION extensions.grant_pg_net_access() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ IF EXISTS (
+ SELECT 1
+ FROM pg_event_trigger_ddl_commands() AS ev
+ JOIN pg_extension AS ext
+ ON ev.objid = ext.oid
+ WHERE ext.extname = 'pg_net'
+ )
+ THEN
+ IF NOT EXISTS (
+ SELECT 1
+ FROM pg_roles
+ WHERE rolname = 'supabase_functions_admin'
+ )
+ THEN
+ CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
+ END IF;
+
+ GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+
+ ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+ ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+ ALTER function net.http_collect_response(request_id bigint, async boolean) SECURITY DEFINER;
+
+ ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+ ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+ ALTER function net.http_collect_response(request_id bigint, async boolean) SET search_path = net;
+
+ REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+ REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+ REVOKE ALL ON FUNCTION net.http_collect_response(request_id bigint, async boolean) FROM PUBLIC;
+
+ GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+ GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+ GRANT EXECUTE ON FUNCTION net.http_collect_response(request_id bigint, async boolean) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+ END IF;
+END;
+$$;
+
+
+ALTER FUNCTION extensions.grant_pg_net_access() OWNER TO postgres;
+
+--
+-- Name: FUNCTION grant_pg_net_access(); Type: COMMENT; Schema: extensions; Owner: postgres
+--
+
+COMMENT ON FUNCTION extensions.grant_pg_net_access() IS 'Grants access to pg_net';
+
+
+--
+-- Name: pgrst_ddl_watch(); Type: FUNCTION; Schema: extensions; Owner: supabase_admin
+--
+
+CREATE FUNCTION extensions.pgrst_ddl_watch() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ cmd record;
+BEGIN
+ FOR cmd IN SELECT * FROM pg_event_trigger_ddl_commands()
+ LOOP
+ IF cmd.command_tag IN (
+ 'CREATE SCHEMA', 'ALTER SCHEMA'
+ , 'CREATE TABLE', 'CREATE TABLE AS', 'SELECT INTO', 'ALTER TABLE'
+ , 'CREATE FOREIGN TABLE', 'ALTER FOREIGN TABLE'
+ , 'CREATE VIEW', 'ALTER VIEW'
+ , 'CREATE MATERIALIZED VIEW', 'ALTER MATERIALIZED VIEW'
+ , 'CREATE FUNCTION', 'ALTER FUNCTION'
+ , 'CREATE TRIGGER'
+ , 'CREATE TYPE', 'ALTER TYPE'
+ , 'CREATE RULE'
+ , 'COMMENT'
+ )
+ -- don't notify in case of CREATE TEMP table or other objects created on pg_temp
+ AND cmd.schema_name is distinct from 'pg_temp'
+ THEN
+ NOTIFY pgrst, 'reload schema';
+ END IF;
+ END LOOP;
+END; $$;
+
+
+ALTER FUNCTION extensions.pgrst_ddl_watch() OWNER TO supabase_admin;
+
+--
+-- Name: pgrst_drop_watch(); Type: FUNCTION; Schema: extensions; Owner: supabase_admin
+--
+
+CREATE FUNCTION extensions.pgrst_drop_watch() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+ obj record;
+BEGIN
+ FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects()
+ LOOP
+ IF obj.object_type IN (
+ 'schema'
+ , 'table'
+ , 'foreign table'
+ , 'view'
+ , 'materialized view'
+ , 'function'
+ , 'trigger'
+ , 'type'
+ , 'rule'
+ )
+ AND obj.is_temporary IS false -- no pg_temp objects
+ THEN
+ NOTIFY pgrst, 'reload schema';
+ END IF;
+ END LOOP;
+END; $$;
+
+
+ALTER FUNCTION extensions.pgrst_drop_watch() OWNER TO supabase_admin;
+
+--
+-- Name: set_graphql_placeholder(); Type: FUNCTION; Schema: extensions; Owner: supabase_admin
+--
+
+CREATE FUNCTION extensions.set_graphql_placeholder() RETURNS event_trigger
+ LANGUAGE plpgsql
+ AS $_$
+ DECLARE
+ graphql_is_dropped bool;
+ BEGIN
+ graphql_is_dropped = (
+ SELECT ev.schema_name = 'graphql_public'
+ FROM pg_event_trigger_dropped_objects() AS ev
+ WHERE ev.schema_name = 'graphql_public'
+ );
+
+ IF graphql_is_dropped
+ THEN
+ create or replace function graphql_public.graphql(
+ "operationName" text default null,
+ query text default null,
+ variables jsonb default null,
+ extensions jsonb default null
+ )
+ returns jsonb
+ language plpgsql
+ as $$
+ DECLARE
+ server_version float;
+ BEGIN
+ server_version = (SELECT (SPLIT_PART((select version()), ' ', 2))::float);
+
+ IF server_version >= 14 THEN
+ RETURN jsonb_build_object(
+ 'errors', jsonb_build_array(
+ jsonb_build_object(
+ 'message', 'pg_graphql extension is not enabled.'
+ )
+ )
+ );
+ ELSE
+ RETURN jsonb_build_object(
+ 'errors', jsonb_build_array(
+ jsonb_build_object(
+ 'message', 'pg_graphql is only available on projects running Postgres 14 onwards.'
+ )
+ )
+ );
+ END IF;
+ END;
+ $$;
+ END IF;
+
+ END;
+$_$;
+
+
+ALTER FUNCTION extensions.set_graphql_placeholder() OWNER TO supabase_admin;
+
+--
+-- Name: FUNCTION set_graphql_placeholder(); Type: COMMENT; Schema: extensions; Owner: supabase_admin
+--
+
+COMMENT ON FUNCTION extensions.set_graphql_placeholder() IS 'Reintroduces placeholder function for graphql_public.graphql';
+
+
+--
+-- Name: get_auth(text); Type: FUNCTION; Schema: pgbouncer; Owner: postgres
+--
+
+CREATE FUNCTION pgbouncer.get_auth(p_usename text) RETURNS TABLE(username text, password text)
+ LANGUAGE plpgsql SECURITY DEFINER
+ AS $$
+BEGIN
+ RAISE WARNING 'PgBouncer auth request: %', p_usename;
+
+ RETURN QUERY
+ SELECT usename::TEXT, passwd::TEXT FROM pg_catalog.pg_shadow
+ WHERE usename = p_usename;
+END;
+$$;
+
+
+ALTER FUNCTION pgbouncer.get_auth(p_usename text) OWNER TO postgres;
+
+--
+-- Name: can_insert_object(text, text, uuid, jsonb); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) RETURNS void
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ INSERT INTO "storage"."objects" ("bucket_id", "name", "owner", "metadata") VALUES (bucketid, name, owner, metadata);
+ -- hack to rollback the successful insert
+ RAISE sqlstate 'PT200' using
+ message = 'ROLLBACK',
+ detail = 'rollback successful insert';
+END
+$$;
+
+
+ALTER FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) OWNER TO supabase_storage_admin;
+
+--
+-- Name: extension(text); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.extension(name text) RETURNS text
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+_parts text[];
+_filename text;
+BEGIN
+ select string_to_array(name, '/') into _parts;
+ select _parts[array_length(_parts,1)] into _filename;
+ -- @todo return the last part instead of 2
+ return split_part(_filename, '.', 2);
+END
+$$;
+
+
+ALTER FUNCTION storage.extension(name text) OWNER TO supabase_storage_admin;
+
+--
+-- Name: filename(text); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.filename(name text) RETURNS text
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+_parts text[];
+BEGIN
+ select string_to_array(name, '/') into _parts;
+ return _parts[array_length(_parts,1)];
+END
+$$;
+
+
+ALTER FUNCTION storage.filename(name text) OWNER TO supabase_storage_admin;
+
+--
+-- Name: foldername(text); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.foldername(name text) RETURNS text[]
+ LANGUAGE plpgsql
+ AS $$
+DECLARE
+_parts text[];
+BEGIN
+ select string_to_array(name, '/') into _parts;
+ return _parts[1:array_length(_parts,1)-1];
+END
+$$;
+
+
+ALTER FUNCTION storage.foldername(name text) OWNER TO supabase_storage_admin;
+
+--
+-- Name: get_size_by_bucket(); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.get_size_by_bucket() RETURNS TABLE(size bigint, bucket_id text)
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ return query
+ select sum((metadata->>'size')::int) as size, obj.bucket_id
+ from "storage".objects as obj
+ group by obj.bucket_id;
+END
+$$;
+
+
+ALTER FUNCTION storage.get_size_by_bucket() OWNER TO supabase_storage_admin;
+
+--
+-- Name: search(text, text, integer, integer, integer, text, text, text); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.search(prefix text, bucketname text, limits integer DEFAULT 100, levels integer DEFAULT 1, offsets integer DEFAULT 0, search text DEFAULT ''::text, sortcolumn text DEFAULT 'name'::text, sortorder text DEFAULT 'asc'::text) RETURNS TABLE(name text, id uuid, updated_at timestamp with time zone, created_at timestamp with time zone, last_accessed_at timestamp with time zone, metadata jsonb)
+ LANGUAGE plpgsql STABLE
+ AS $_$
+declare
+ v_order_by text;
+ v_sort_order text;
+begin
+ case
+ when sortcolumn = 'name' then
+ v_order_by = 'name';
+ when sortcolumn = 'updated_at' then
+ v_order_by = 'updated_at';
+ when sortcolumn = 'created_at' then
+ v_order_by = 'created_at';
+ when sortcolumn = 'last_accessed_at' then
+ v_order_by = 'last_accessed_at';
+ else
+ v_order_by = 'name';
+ end case;
+
+ case
+ when sortorder = 'asc' then
+ v_sort_order = 'asc';
+ when sortorder = 'desc' then
+ v_sort_order = 'desc';
+ else
+ v_sort_order = 'asc';
+ end case;
+
+ v_order_by = v_order_by || ' ' || v_sort_order;
+
+ return query execute
+ 'with folders as (
+ select path_tokens[$1] as folder
+ from storage.objects
+ where objects.name ilike $2 || $3 || ''%''
+ and bucket_id = $4
+ and array_length(regexp_split_to_array(objects.name, ''/''), 1) <> $1
+ group by folder
+ order by folder ' || v_sort_order || '
+ )
+ (select folder as "name",
+ null as id,
+ null as updated_at,
+ null as created_at,
+ null as last_accessed_at,
+ null as metadata from folders)
+ union all
+ (select path_tokens[$1] as "name",
+ id,
+ updated_at,
+ created_at,
+ last_accessed_at,
+ metadata
+ from storage.objects
+ where objects.name ilike $2 || $3 || ''%''
+ and bucket_id = $4
+ and array_length(regexp_split_to_array(objects.name, ''/''), 1) = $1
+ order by ' || v_order_by || ')
+ limit $5
+ offset $6' using levels, prefix, search, bucketname, limits, offsets;
+end;
+$_$;
+
+
+ALTER FUNCTION storage.search(prefix text, bucketname text, limits integer, levels integer, offsets integer, search text, sortcolumn text, sortorder text) OWNER TO supabase_storage_admin;
+
+--
+-- Name: update_updated_at_column(); Type: FUNCTION; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE FUNCTION storage.update_updated_at_column() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW.updated_at = now();
+ RETURN NEW;
+END;
+$$;
+
+
+ALTER FUNCTION storage.update_updated_at_column() OWNER TO supabase_storage_admin;
+
+--
+-- Name: secrets_encrypt_secret_secret(); Type: FUNCTION; Schema: vault; Owner: supabase_admin
+--
+
+CREATE FUNCTION vault.secrets_encrypt_secret_secret() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+ BEGIN
+ new.secret = CASE WHEN new.secret IS NULL THEN NULL ELSE
+ CASE WHEN new.key_id IS NULL THEN NULL ELSE pg_catalog.encode(
+ pgsodium.crypto_aead_det_encrypt(
+ pg_catalog.convert_to(new.secret, 'utf8'),
+ pg_catalog.convert_to((new.id::text || new.description::text || new.created_at::text || new.updated_at::text)::text, 'utf8'),
+ new.key_id::uuid,
+ new.nonce
+ ),
+ 'base64') END END;
+ RETURN new;
+ END;
+ $$;
+
+
+ALTER FUNCTION vault.secrets_encrypt_secret_secret() OWNER TO supabase_admin;
+
+SET default_tablespace = '';
+
+SET default_table_access_method = heap;
+
+--
+-- Name: audit_log_entries; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.audit_log_entries (
+ instance_id uuid,
+ id uuid NOT NULL,
+ payload json,
+ created_at timestamp with time zone,
+ ip_address character varying(64) DEFAULT ''::character varying NOT NULL
+);
+
+
+ALTER TABLE auth.audit_log_entries OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE audit_log_entries; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.audit_log_entries IS 'Auth: Audit trail for user actions.';
+
+
+--
+-- Name: flow_state; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.flow_state (
+ id uuid NOT NULL,
+ user_id uuid,
+ auth_code text NOT NULL,
+ code_challenge_method auth.code_challenge_method NOT NULL,
+ code_challenge text NOT NULL,
+ provider_type text NOT NULL,
+ provider_access_token text,
+ provider_refresh_token text,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ authentication_method text NOT NULL
+);
+
+
+ALTER TABLE auth.flow_state OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE flow_state; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.flow_state IS 'stores metadata for pkce logins';
+
+
+--
+-- Name: identities; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.identities (
+ id text NOT NULL,
+ user_id uuid NOT NULL,
+ identity_data jsonb NOT NULL,
+ provider text NOT NULL,
+ last_sign_in_at timestamp with time zone,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ email text GENERATED ALWAYS AS (lower((identity_data ->> 'email'::text))) STORED
+);
+
+
+ALTER TABLE auth.identities OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE identities; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.identities IS 'Auth: Stores identities associated to a user.';
+
+
+--
+-- Name: COLUMN identities.email; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON COLUMN auth.identities.email IS 'Auth: Email is a generated column that references the optional email property in the identity_data';
+
+
+--
+-- Name: instances; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.instances (
+ id uuid NOT NULL,
+ uuid uuid,
+ raw_base_config text,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone
+);
+
+
+ALTER TABLE auth.instances OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE instances; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.instances IS 'Auth: Manages users across multiple sites.';
+
+
+--
+-- Name: mfa_amr_claims; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.mfa_amr_claims (
+ session_id uuid NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ authentication_method text NOT NULL,
+ id uuid NOT NULL
+);
+
+
+ALTER TABLE auth.mfa_amr_claims OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE mfa_amr_claims; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.mfa_amr_claims IS 'auth: stores authenticator method reference claims for multi factor authentication';
+
+
+--
+-- Name: mfa_challenges; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.mfa_challenges (
+ id uuid NOT NULL,
+ factor_id uuid NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ verified_at timestamp with time zone,
+ ip_address inet NOT NULL
+);
+
+
+ALTER TABLE auth.mfa_challenges OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE mfa_challenges; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.mfa_challenges IS 'auth: stores metadata about challenge requests made';
+
+
+--
+-- Name: mfa_factors; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.mfa_factors (
+ id uuid NOT NULL,
+ user_id uuid NOT NULL,
+ friendly_name text,
+ factor_type auth.factor_type NOT NULL,
+ status auth.factor_status NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ secret text
+);
+
+
+ALTER TABLE auth.mfa_factors OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE mfa_factors; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.mfa_factors IS 'auth: stores metadata about factors';
+
+
+--
+-- Name: refresh_tokens; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.refresh_tokens (
+ instance_id uuid,
+ id bigint NOT NULL,
+ token character varying(255),
+ user_id character varying(255),
+ revoked boolean,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ parent character varying(255),
+ session_id uuid
+);
+
+
+ALTER TABLE auth.refresh_tokens OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE refresh_tokens; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.refresh_tokens IS 'Auth: Store of tokens used to refresh JWT tokens once they expire.';
+
+
+--
+-- Name: refresh_tokens_id_seq; Type: SEQUENCE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE SEQUENCE auth.refresh_tokens_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE auth.refresh_tokens_id_seq OWNER TO supabase_auth_admin;
+
+--
+-- Name: refresh_tokens_id_seq; Type: SEQUENCE OWNED BY; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER SEQUENCE auth.refresh_tokens_id_seq OWNED BY auth.refresh_tokens.id;
+
+
+--
+-- Name: saml_providers; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.saml_providers (
+ id uuid NOT NULL,
+ sso_provider_id uuid NOT NULL,
+ entity_id text NOT NULL,
+ metadata_xml text NOT NULL,
+ metadata_url text,
+ attribute_mapping jsonb,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ CONSTRAINT "entity_id not empty" CHECK ((char_length(entity_id) > 0)),
+ CONSTRAINT "metadata_url not empty" CHECK (((metadata_url = NULL::text) OR (char_length(metadata_url) > 0))),
+ CONSTRAINT "metadata_xml not empty" CHECK ((char_length(metadata_xml) > 0))
+);
+
+
+ALTER TABLE auth.saml_providers OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE saml_providers; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.saml_providers IS 'Auth: Manages SAML Identity Provider connections.';
+
+
+--
+-- Name: saml_relay_states; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.saml_relay_states (
+ id uuid NOT NULL,
+ sso_provider_id uuid NOT NULL,
+ request_id text NOT NULL,
+ for_email text,
+ redirect_to text,
+ from_ip_address inet,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ CONSTRAINT "request_id not empty" CHECK ((char_length(request_id) > 0))
+);
+
+
+ALTER TABLE auth.saml_relay_states OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE saml_relay_states; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.saml_relay_states IS 'Auth: Contains SAML Relay State information for each Service Provider initiated login.';
+
+
+--
+-- Name: schema_migrations; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.schema_migrations (
+ version character varying(255) NOT NULL
+);
+
+
+ALTER TABLE auth.schema_migrations OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE schema_migrations; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.schema_migrations IS 'Auth: Manages updates to the auth system.';
+
+
+--
+-- Name: sessions; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.sessions (
+ id uuid NOT NULL,
+ user_id uuid NOT NULL,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ factor_id uuid,
+ aal auth.aal_level,
+ not_after timestamp with time zone
+);
+
+
+ALTER TABLE auth.sessions OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE sessions; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.sessions IS 'Auth: Stores session data associated to a user.';
+
+
+--
+-- Name: COLUMN sessions.not_after; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON COLUMN auth.sessions.not_after IS 'Auth: Not after is a nullable column that contains a timestamp after which the session should be regarded as expired.';
+
+
+--
+-- Name: sso_domains; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.sso_domains (
+ id uuid NOT NULL,
+ sso_provider_id uuid NOT NULL,
+ domain text NOT NULL,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ CONSTRAINT "domain not empty" CHECK ((char_length(domain) > 0))
+);
+
+
+ALTER TABLE auth.sso_domains OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE sso_domains; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.sso_domains IS 'Auth: Manages SSO email address domain mapping to an SSO Identity Provider.';
+
+
+--
+-- Name: sso_providers; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.sso_providers (
+ id uuid NOT NULL,
+ resource_id text,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ CONSTRAINT "resource_id not empty" CHECK (((resource_id = NULL::text) OR (char_length(resource_id) > 0)))
+);
+
+
+ALTER TABLE auth.sso_providers OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE sso_providers; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.sso_providers IS 'Auth: Manages SSO identity provider information; see saml_providers for SAML.';
+
+
+--
+-- Name: COLUMN sso_providers.resource_id; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON COLUMN auth.sso_providers.resource_id IS 'Auth: Uniquely identifies a SSO provider according to a user-chosen resource ID (case insensitive), useful in infrastructure as code.';
+
+
+--
+-- Name: users; Type: TABLE; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE TABLE auth.users (
+ instance_id uuid,
+ id uuid NOT NULL,
+ aud character varying(255),
+ role character varying(255),
+ email character varying(255),
+ encrypted_password character varying(255),
+ email_confirmed_at timestamp with time zone,
+ invited_at timestamp with time zone,
+ confirmation_token character varying(255),
+ confirmation_sent_at timestamp with time zone,
+ recovery_token character varying(255),
+ recovery_sent_at timestamp with time zone,
+ email_change_token_new character varying(255),
+ email_change character varying(255),
+ email_change_sent_at timestamp with time zone,
+ last_sign_in_at timestamp with time zone,
+ raw_app_meta_data jsonb,
+ raw_user_meta_data jsonb,
+ is_super_admin boolean,
+ created_at timestamp with time zone,
+ updated_at timestamp with time zone,
+ phone text DEFAULT NULL::character varying,
+ phone_confirmed_at timestamp with time zone,
+ phone_change text DEFAULT ''::character varying,
+ phone_change_token character varying(255) DEFAULT ''::character varying,
+ phone_change_sent_at timestamp with time zone,
+ confirmed_at timestamp with time zone GENERATED ALWAYS AS (LEAST(email_confirmed_at, phone_confirmed_at)) STORED,
+ email_change_token_current character varying(255) DEFAULT ''::character varying,
+ email_change_confirm_status smallint DEFAULT 0,
+ banned_until timestamp with time zone,
+ reauthentication_token character varying(255) DEFAULT ''::character varying,
+ reauthentication_sent_at timestamp with time zone,
+ is_sso_user boolean DEFAULT false NOT NULL,
+ deleted_at timestamp with time zone,
+ CONSTRAINT users_email_change_confirm_status_check CHECK (((email_change_confirm_status >= 0) AND (email_change_confirm_status <= 2)))
+);
+
+
+ALTER TABLE auth.users OWNER TO supabase_auth_admin;
+
+--
+-- Name: TABLE users; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON TABLE auth.users IS 'Auth: Stores user login data within a secure schema.';
+
+
+--
+-- Name: COLUMN users.is_sso_user; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON COLUMN auth.users.is_sso_user IS 'Auth: Set this column to true when the account comes from SSO. These accounts can have duplicate emails.';
+
+
+--
+-- Name: test; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.test (
+ id bigint NOT NULL,
+ int2 smallint,
+ int4 integer,
+ int8 bigint,
+ float4 real,
+ float8 double precision,
+ "numeric" numeric,
+ json json,
+ jsonb jsonb,
+ text text[],
+ "varchar" character varying[],
+ uuid uuid,
+ date date,
+ timetz time with time zone,
+ "timestamp" timestamp without time zone,
+ timestamptz timestamp with time zone,
+ bool boolean,
+ boolarr boolean[]
+);
+
+
+ALTER TABLE public.test OWNER TO postgres;
+
+--
+-- Name: TABLE test; Type: COMMENT; Schema: public; Owner: postgres
+--
+
+COMMENT ON TABLE public.test IS 'test';
+
+
+--
+-- Name: test2; Type: TABLE; Schema: public; Owner: postgres
+--
+
+CREATE TABLE public.test2 (
+ id bigint NOT NULL,
+ created_at timestamp with time zone DEFAULT now(),
+ int4 smallint[],
+ int5 integer[],
+ int8 bigint[],
+ float4 real[],
+ float8 double precision[],
+ "numeric" numeric[],
+ json json[],
+ jsonb jsonb[],
+ text text[],
+ "varchar" character varying[],
+ uuid uuid[],
+ date date[],
+ "time" time without time zone[],
+ timetz time with time zone[],
+ "timestamp" timestamp without time zone[],
+ timestamptz timestamp with time zone[],
+ bool boolean[]
+);
+
+
+ALTER TABLE public.test2 OWNER TO postgres;
+
+--
+-- Name: test2_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+ALTER TABLE public.test2 ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
+ SEQUENCE NAME public.test2_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1
+);
+
+
+--
+-- Name: test_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
+--
+
+ALTER TABLE public.test ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
+ SEQUENCE NAME public.test_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1
+);
+
+
+--
+-- Name: buckets; Type: TABLE; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE TABLE storage.buckets (
+ id text NOT NULL,
+ name text NOT NULL,
+ owner uuid,
+ created_at timestamp with time zone DEFAULT now(),
+ updated_at timestamp with time zone DEFAULT now(),
+ public boolean DEFAULT false,
+ avif_autodetection boolean DEFAULT false,
+ file_size_limit bigint,
+ allowed_mime_types text[]
+);
+
+
+ALTER TABLE storage.buckets OWNER TO supabase_storage_admin;
+
+--
+-- Name: migrations; Type: TABLE; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE TABLE storage.migrations (
+ id integer NOT NULL,
+ name character varying(100) NOT NULL,
+ hash character varying(40) NOT NULL,
+ executed_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP
+);
+
+
+ALTER TABLE storage.migrations OWNER TO supabase_storage_admin;
+
+--
+-- Name: objects; Type: TABLE; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE TABLE storage.objects (
+ id uuid DEFAULT extensions.uuid_generate_v4() NOT NULL,
+ bucket_id text,
+ name text,
+ owner uuid,
+ created_at timestamp with time zone DEFAULT now(),
+ updated_at timestamp with time zone DEFAULT now(),
+ last_accessed_at timestamp with time zone DEFAULT now(),
+ metadata jsonb,
+ path_tokens text[] GENERATED ALWAYS AS (string_to_array(name, '/'::text)) STORED,
+ version text
+);
+
+
+ALTER TABLE storage.objects OWNER TO supabase_storage_admin;
+
+--
+-- Name: decrypted_secrets; Type: VIEW; Schema: vault; Owner: supabase_admin
+--
+
+CREATE VIEW vault.decrypted_secrets AS
+ SELECT secrets.id,
+ secrets.name,
+ secrets.description,
+ secrets.secret,
+ CASE
+ WHEN (secrets.secret IS NULL) THEN NULL::text
+ ELSE
+ CASE
+ WHEN (secrets.key_id IS NULL) THEN NULL::text
+ ELSE convert_from(pgsodium.crypto_aead_det_decrypt(decode(secrets.secret, 'base64'::text), convert_to(((((secrets.id)::text || secrets.description) || (secrets.created_at)::text) || (secrets.updated_at)::text), 'utf8'::name), secrets.key_id, secrets.nonce), 'utf8'::name)
+ END
+ END AS decrypted_secret,
+ secrets.key_id,
+ secrets.nonce,
+ secrets.created_at,
+ secrets.updated_at
+ FROM vault.secrets;
+
+
+ALTER TABLE vault.decrypted_secrets OWNER TO supabase_admin;
+
+--
+-- Name: refresh_tokens id; Type: DEFAULT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens ALTER COLUMN id SET DEFAULT nextval('auth.refresh_tokens_id_seq'::regclass);
+
+
+--
+-- Data for Name: audit_log_entries; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.audit_log_entries (instance_id, id, payload, created_at, ip_address) FROM stdin;
+00000000-0000-0000-0000-000000000000 c1902f19-1b8c-4f4d-aed7-433edce6876e {"action":"user_invited","actor_id":"00000000-0000-0000-0000-000000000000","actor_username":"supabase_admin","log_type":"team","traits":{"user_email":"ionicisere@gmail.com","user_id":"be55c6cf-94d2-44a4-a119-61297d68c0e8"}} 2022-08-30 12:59:35.98897+00
+00000000-0000-0000-0000-000000000000 27d0dfc7-35aa-49ff-bf42-cf94e85f01b2 {"action":"user_signedup","actor_id":"be55c6cf-94d2-44a4-a119-61297d68c0e8","actor_username":"ionicisere@gmail.com","log_type":"team"} 2022-08-30 12:59:49.901362+00
+00000000-0000-0000-0000-000000000000 4cb58f1d-eabd-4ac7-9731-7eb9aabb37e1 {"action":"user_invited","actor_id":"00000000-0000-0000-0000-000000000000","actor_username":"supabase_admin","log_type":"team","traits":{"user_email":"bradley@appwrite.io","user_id":"1b48e703-cb29-4b76-b804-82a53f074b93"}} 2022-09-14 10:09:18.311141+00
+00000000-0000-0000-0000-000000000000 59a6ff0f-2ae2-4674-a05a-ce889368762a {"action":"user_signedup","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"team"} 2022-09-14 10:19:09.440989+00
+00000000-0000-0000-0000-000000000000 7c93bde4-e3d6-4725-a251-dc37554f765d {"action":"user_recovery_requested","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"user"} 2022-09-20 09:05:38.36561+00
+00000000-0000-0000-0000-000000000000 c9ef1c90-0ac3-4ac7-9548-80b190bdb90d {"action":"login","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"account"} 2022-09-20 09:06:33.909469+00
+00000000-0000-0000-0000-000000000000 1067d0f5-59ed-4ee2-9c91-c4196e4167b5 {"action":"user_recovery_requested","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"user"} 2022-09-20 09:23:34.466842+00
+00000000-0000-0000-0000-000000000000 2c794d09-7cb6-4c08-9e20-106c90389806 {"action":"login","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"account"} 2022-09-20 09:23:51.627032+00
+00000000-0000-0000-0000-000000000000 a6598240-a79f-4778-b76e-0882f3534441 {"action":"user_modified","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"user"} 2022-09-20 09:27:11.738268+00
+00000000-0000-0000-0000-000000000000 63009024-ef8c-42b6-822f-b1f6608f065d {"action":"user_recovery_requested","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"user"} 2022-09-20 09:32:37.016522+00
+00000000-0000-0000-0000-000000000000 fe9287eb-9306-4d92-97c7-ff8cfeaf6214 {"action":"login","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"account"} 2022-09-20 09:32:43.909748+00
+00000000-0000-0000-0000-000000000000 c1abbcfc-4627-4755-a1ec-f512d8316440 {"action":"user_modified","actor_id":"1b48e703-cb29-4b76-b804-82a53f074b93","actor_username":"bradley@appwrite.io","log_type":"user"} 2022-09-20 09:33:47.027108+00
+00000000-0000-0000-0000-000000000000 2b65dfee-555c-4996-9411-d824a5858f92 {"action":"user_confirmation_requested","actor_id":"88043554-4aac-46de-8437-c02fdacfdc9c","actor_username":"misael.upton98@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:37.980112+00
+00000000-0000-0000-0000-000000000000 c87c281e-e62b-405c-92e4-5eadd49d88f0 {"action":"user_confirmation_requested","actor_id":"615357b8-c668-45ee-a749-c96db1aabc7a","actor_username":"albert.kihn95@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:37.986291+00
+00000000-0000-0000-0000-000000000000 988b85c7-b39a-4d0d-bd95-ee975f054aed {"action":"user_confirmation_requested","actor_id":"369664ac-9358-4b51-91b5-79ddca7ef0b2","actor_username":"maida_walsh61@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:37.992667+00
+00000000-0000-0000-0000-000000000000 7f936ded-7ac9-4f10-baa1-ef7a0633fead {"action":"user_confirmation_requested","actor_id":"e7faf866-0438-4b7c-8de3-1c134c707806","actor_username":"osvaldo.bogan15@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:37.997493+00
+00000000-0000-0000-0000-000000000000 44f1d5d8-acc5-4c64-bc0e-b73bf6f81bc4 {"action":"user_confirmation_requested","actor_id":"af00f659-028a-4268-b6b5-fa36e40e190e","actor_username":"wyman67@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.005148+00
+00000000-0000-0000-0000-000000000000 cf54912a-f78d-44c8-ad1b-1611e0bf65bd {"action":"user_confirmation_requested","actor_id":"07616a1c-e8ce-489a-a74b-adab1f4e1b32","actor_username":"rylee68@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.021094+00
+00000000-0000-0000-0000-000000000000 f8ce7a46-e40d-487f-b44b-74649e73e358 {"action":"user_confirmation_requested","actor_id":"ab38ad48-7b50-4e66-85b1-7d78a61a04f0","actor_username":"devin.rath@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.030918+00
+00000000-0000-0000-0000-000000000000 dcfaa287-546a-49aa-b4c0-45bb8ff58b52 {"action":"user_confirmation_requested","actor_id":"23e19499-63e4-4fee-9718-bd24584fdca0","actor_username":"royce_hermiston@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.033558+00
+00000000-0000-0000-0000-000000000000 ee411931-e9c0-4c47-b2a0-ad5a224c97f8 {"action":"user_confirmation_requested","actor_id":"932ce7f7-e57d-45c3-bc7d-63362e2d67aa","actor_username":"eino_considine67@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.033417+00
+00000000-0000-0000-0000-000000000000 c2e9c5c8-9469-4a7d-931f-daf8b0386149 {"action":"user_confirmation_requested","actor_id":"b301a3c1-022f-49fa-a6fb-41c8cdd521a9","actor_username":"jerrod70@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.046936+00
+00000000-0000-0000-0000-000000000000 00a03660-31a1-4648-a06f-dd9e019f0633 {"action":"user_confirmation_requested","actor_id":"a7ca4ce7-7763-4edc-869a-dc3afb4dc1c2","actor_username":"ada.parker@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.627452+00
+00000000-0000-0000-0000-000000000000 fd3bbe3c-6b0b-418d-99a0-e521b3465133 {"action":"user_confirmation_requested","actor_id":"d977c288-485b-44f4-aa34-94c232decbed","actor_username":"aryanna_dickens47@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.798551+00
+00000000-0000-0000-0000-000000000000 95152226-2a61-4d46-97ab-e1ab5e559516 {"action":"user_confirmation_requested","actor_id":"53cd7be4-c374-492c-aa18-06febf196607","actor_username":"lonnie_huels69@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.817815+00
+00000000-0000-0000-0000-000000000000 7c0986f6-0310-4a94-9df2-6fc31d38b84c {"action":"user_confirmation_requested","actor_id":"2b817ed6-e9b4-4ab6-a97c-8a5c5cca80b5","actor_username":"jennings.watsica71@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.845262+00
+00000000-0000-0000-0000-000000000000 8e392538-f1e9-4ece-8a7c-d1bf807d5e3a {"action":"user_confirmation_requested","actor_id":"ba1d736c-18f9-4eca-8000-05bd223d097f","actor_username":"alia.emmerich42@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.884705+00
+00000000-0000-0000-0000-000000000000 88ad0d66-a780-4290-81ae-1425b86d10af {"action":"user_confirmation_requested","actor_id":"1d1c4838-d7bf-4830-945e-7f1c31934340","actor_username":"mallory_kuhn@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.909651+00
+00000000-0000-0000-0000-000000000000 521e9c38-506a-4373-807e-11df4a6d62ec {"action":"user_confirmation_requested","actor_id":"abb439a6-9812-4edb-8f54-8f99830a9d51","actor_username":"julianne.schinner98@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:38.944862+00
+00000000-0000-0000-0000-000000000000 feede8a4-1b06-4bbf-9210-4200b9df34a3 {"action":"user_confirmation_requested","actor_id":"acbbb7e0-44ff-42fa-a8aa-69ad98666e31","actor_username":"adonis_oconnell@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.011272+00
+00000000-0000-0000-0000-000000000000 8a039a1d-b856-4ed9-839f-e3922fed90ec {"action":"user_confirmation_requested","actor_id":"67cb7f0e-c295-4d41-83a0-761568b7a13c","actor_username":"craig.dietrich31@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.034958+00
+00000000-0000-0000-0000-000000000000 3c328068-021f-4d85-8cde-a25dac7e23d0 {"action":"user_confirmation_requested","actor_id":"d1c2cd22-52db-4074-b0ba-e7152df4a27d","actor_username":"sunny.welch@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.039284+00
+00000000-0000-0000-0000-000000000000 8d9dfb38-5510-4540-afde-19e7210d3cba {"action":"user_confirmation_requested","actor_id":"e6e80a3d-8435-4d09-bba3-e8f158ff93e4","actor_username":"elliott_goldner77@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.26905+00
+00000000-0000-0000-0000-000000000000 3d1d888b-99b0-4c72-a076-9e9ead3f79de {"action":"user_confirmation_requested","actor_id":"fef209ad-b677-44a7-82a9-899c33490075","actor_username":"ana.nikolaus95@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:58.679176+00
+00000000-0000-0000-0000-000000000000 ce8b1ede-1f4e-47f3-b34a-958c1e3d707a {"action":"user_confirmation_requested","actor_id":"7f08b69b-c277-4af8-a51e-9f80bad06430","actor_username":"kobe_bergnaum47@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.742489+00
+00000000-0000-0000-0000-000000000000 ab4f4854-0853-4214-805a-d1a1cdd7c5c1 {"action":"user_confirmation_requested","actor_id":"0b448f5c-7c26-498b-8d13-7049cf82037c","actor_username":"arne_bayer91@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.798011+00
+00000000-0000-0000-0000-000000000000 f8b9d51f-3e4c-4492-aa79-e6597db8707e {"action":"user_confirmation_requested","actor_id":"8e40363f-20c0-4f58-ac8f-fecaec606923","actor_username":"cheyenne_cassin@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.346177+00
+00000000-0000-0000-0000-000000000000 ef6ed7c2-17e2-430b-80a9-77c52711298d {"action":"user_confirmation_requested","actor_id":"5de1bfbc-4a77-4e6b-8adf-e5572a32e12e","actor_username":"coby91@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:58.835142+00
+00000000-0000-0000-0000-000000000000 f9509d5a-4501-4b3a-b4e0-d7e5b3fd0b30 {"action":"user_confirmation_requested","actor_id":"46867bb3-7c26-4ced-9ec0-268afda9ca10","actor_username":"lewis62@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.490841+00
+00000000-0000-0000-0000-000000000000 e0e19e16-1a57-49f0-8f3f-f08526126a23 {"action":"user_confirmation_requested","actor_id":"366b7862-08df-4b9e-8ba3-8e2d7fbe7a40","actor_username":"lue.dibbert26@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.342348+00
+00000000-0000-0000-0000-000000000000 eb4a832f-0f02-4433-9590-fc2089fb78b7 {"action":"user_confirmation_requested","actor_id":"5c6a9645-29e1-478e-9cba-d048ab579bd1","actor_username":"magdalena_metz@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.459499+00
+00000000-0000-0000-0000-000000000000 11b86e41-f5ed-4034-936a-3405666e7d86 {"action":"user_confirmation_requested","actor_id":"4535c79c-f973-447b-8692-6f2207f6efcb","actor_username":"madisen_harris32@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.505607+00
+00000000-0000-0000-0000-000000000000 8a2c5e3f-e192-43eb-b120-2681aca4dd93 {"action":"user_confirmation_requested","actor_id":"581483e9-b39a-477c-a712-a590a6bd2e8d","actor_username":"alexandre_rodriguez@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.508104+00
+00000000-0000-0000-0000-000000000000 2218eaf6-d590-4f4a-9abc-b54a0a89a2ea {"action":"user_confirmation_requested","actor_id":"0d9fd639-9b14-49c8-a755-36565a345da5","actor_username":"pierre33@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.51246+00
+00000000-0000-0000-0000-000000000000 fccbf8d7-df33-4062-b60b-3c0c0d40906e {"action":"user_confirmation_requested","actor_id":"af4d7654-d31d-40e9-8e31-8031b29651bf","actor_username":"laney.olson@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.61992+00
+00000000-0000-0000-0000-000000000000 f74d8518-8bb2-4d91-921a-3fa9e56c3ff7 {"action":"user_confirmation_requested","actor_id":"c7f6fb1f-a6d9-45b1-a732-4e80877266ea","actor_username":"jodie.wunsch60@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.637491+00
+00000000-0000-0000-0000-000000000000 b2a7a025-9dd9-4dc7-90dc-f05deb54cf7a {"action":"user_confirmation_requested","actor_id":"bdc41348-d0ff-4716-b03e-505397255296","actor_username":"micheal.homenick@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.669904+00
+00000000-0000-0000-0000-000000000000 66f804ba-5420-456e-9905-ada2c35b9911 {"action":"user_confirmation_requested","actor_id":"b5aca4b6-67f6-47b1-b2f5-794f354e183a","actor_username":"pauline.moore@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 11:08:39.697472+00
+00000000-0000-0000-0000-000000000000 dcd63ad7-5648-40e9-af68-b185645f4ff8 {"action":"user_confirmation_requested","actor_id":"68fb3828-45a2-41ee-8c32-fd87525d955e","actor_username":"vivian_rogahn@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:58.906026+00
+00000000-0000-0000-0000-000000000000 44d7e676-d605-427a-8fb4-c77f51756325 {"action":"user_confirmation_requested","actor_id":"2d7cc448-9478-4c4b-b9c1-b6005b3b2517","actor_username":"casimir.williamson41@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.074583+00
+00000000-0000-0000-0000-000000000000 fe46709a-032f-43b4-8ce3-38a55e78db8b {"action":"user_confirmation_requested","actor_id":"754e01ee-8bc6-42cf-875a-c596d4b5c108","actor_username":"rod_hoppe83@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.126499+00
+00000000-0000-0000-0000-000000000000 d7a8a31c-c1db-4d92-a1b0-b1e2756ec997 {"action":"user_confirmation_requested","actor_id":"fe8d52b3-9bb2-4063-95da-733f61763be0","actor_username":"demetris99@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.120626+00
+00000000-0000-0000-0000-000000000000 9ef5e545-5858-45d2-a4b0-b30cfd4ee0d9 {"action":"user_confirmation_requested","actor_id":"27b98fb2-2a63-4ea2-92da-845e45c1f530","actor_username":"marlon.torp45@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.175015+00
+00000000-0000-0000-0000-000000000000 9e4acd5e-bcf4-49b9-9f56-3b9eea2bb06f {"action":"user_confirmation_requested","actor_id":"88847f43-2f69-4c26-b00b-6b59a38ef164","actor_username":"cali_orn71@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.196527+00
+00000000-0000-0000-0000-000000000000 ca7a089c-702a-4bbf-a87e-c354abae8d6b {"action":"user_confirmation_requested","actor_id":"561e28e6-7ce5-4282-9f51-7f59722170ca","actor_username":"rey32@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.197341+00
+00000000-0000-0000-0000-000000000000 a17507f3-5447-4ac3-a6b5-3ebf9a16c79b {"action":"user_confirmation_requested","actor_id":"a23c4ec2-eb31-420d-bd89-ec49065bed3f","actor_username":"ansel.kessler89@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.19806+00
+00000000-0000-0000-0000-000000000000 a498aa55-2d71-4299-9aad-df1628d66dab {"action":"user_confirmation_requested","actor_id":"2e320c50-4640-43d4-8e82-5e66c430decd","actor_username":"anibal61@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.47539+00
+00000000-0000-0000-0000-000000000000 a3ed6e6c-12c7-4bc8-a75f-c604f4336370 {"action":"user_confirmation_requested","actor_id":"e42df43c-3603-45ea-a281-1c1c1b29965c","actor_username":"thora.renner@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.61507+00
+00000000-0000-0000-0000-000000000000 e7e6f7bb-eb45-4352-8b2a-677e5daa1e2a {"action":"user_confirmation_requested","actor_id":"07ede456-d7f3-4840-a2b2-6394cb6e44c6","actor_username":"estel.kovacek68@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.655022+00
+00000000-0000-0000-0000-000000000000 632de9d3-c69c-4529-9694-e557670cbb0d {"action":"user_confirmation_requested","actor_id":"8858520b-4d3e-4804-937c-e1fa8b355e1e","actor_username":"althea_dickens@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.75571+00
+00000000-0000-0000-0000-000000000000 75ab9005-95cc-43c4-98bc-6aa967b86c01 {"action":"user_confirmation_requested","actor_id":"26889fa5-94d3-4150-8b17-d7413e682652","actor_username":"francis_lockman21@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.809823+00
+00000000-0000-0000-0000-000000000000 e339fa91-ea17-4d6f-a0f9-2b06510b85a0 {"action":"user_confirmation_requested","actor_id":"9beabeb7-b51b-416c-9d3b-d23badeb7c5c","actor_username":"adonis_lemke@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.816807+00
+00000000-0000-0000-0000-000000000000 c4962a31-a422-4fde-ae3c-a117f0a70256 {"action":"user_confirmation_requested","actor_id":"b1262b76-e470-4f71-ad33-86919606391d","actor_username":"humberto_wolf@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.860563+00
+00000000-0000-0000-0000-000000000000 b2647794-d7b9-4bf6-b2ac-a94d41efee3c {"action":"user_confirmation_requested","actor_id":"3298ca3a-400a-459e-b0a7-426fd6e9b716","actor_username":"buddy_hintz@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:40:59.889159+00
+00000000-0000-0000-0000-000000000000 946fb286-eebb-4e19-ac7e-dd13f6e04015 {"action":"user_confirmation_requested","actor_id":"a413cb80-834e-4d8a-b29a-a02ecf139f7c","actor_username":"brando_treutel@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.296428+00
+00000000-0000-0000-0000-000000000000 e45fe72b-6828-4634-9165-decdd88046b4 {"action":"user_confirmation_requested","actor_id":"ca9f8106-a060-4bd5-be47-d9f384e415ca","actor_username":"gavin33@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.352987+00
+00000000-0000-0000-0000-000000000000 8f7f9be0-e1ee-43c3-a4e0-bc6dcac9727f {"action":"user_confirmation_requested","actor_id":"b096f178-9502-4837-bf3c-37acccf61eb9","actor_username":"ara_volkman7@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.381204+00
+00000000-0000-0000-0000-000000000000 ac7061d4-b248-488e-b31d-7c09097a2a63 {"action":"user_confirmation_requested","actor_id":"54b2da7d-4765-44f1-9e95-b6ebd5494530","actor_username":"horace_borer96@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.425255+00
+00000000-0000-0000-0000-000000000000 ca21b645-cf89-44d0-b70e-4af637b45548 {"action":"user_confirmation_requested","actor_id":"88e9b920-6bc9-4242-a245-2c2164c01092","actor_username":"princess24@gmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.728858+00
+00000000-0000-0000-0000-000000000000 f8e8223a-5e49-471a-a916-0863fa8c8f88 {"action":"user_confirmation_requested","actor_id":"7dff3d1f-c92e-45d8-ad4f-47976249728f","actor_username":"heather.corwin32@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.733868+00
+00000000-0000-0000-0000-000000000000 f30a282a-e7b0-419b-ad4c-64c923e03afc {"action":"user_confirmation_requested","actor_id":"ec352166-6475-453f-825b-01bee04214d9","actor_username":"jamarcus94@hotmail.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.802217+00
+00000000-0000-0000-0000-000000000000 b67c4f21-d71b-4148-852a-6ca6c14031e3 {"action":"user_confirmation_requested","actor_id":"b576f0a4-3369-4e89-8221-72a89807dde9","actor_username":"efrain37@yahoo.com","log_type":"user","traits":{"provider":"email"}} 2023-01-19 14:41:00.825823+00
+\.
+
+
+--
+-- Data for Name: flow_state; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.flow_state (id, user_id, auth_code, code_challenge_method, code_challenge, provider_type, provider_access_token, provider_refresh_token, created_at, updated_at, authentication_method) FROM stdin;
+\.
+
+
+--
+-- Data for Name: identities; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.identities (id, user_id, identity_data, provider, last_sign_in_at, created_at, updated_at) FROM stdin;
+be55c6cf-94d2-44a4-a119-61297d68c0e8 be55c6cf-94d2-44a4-a119-61297d68c0e8 {"sub": "be55c6cf-94d2-44a4-a119-61297d68c0e8", "email": "ionicisere@gmail.com"} email 2022-11-25 00:00:00+00 2022-11-25 00:00:00+00 2022-11-25 00:00:00+00
+1b48e703-cb29-4b76-b804-82a53f074b93 1b48e703-cb29-4b76-b804-82a53f074b93 {"sub": "1b48e703-cb29-4b76-b804-82a53f074b93", "email": "bradley@appwrite.io"} email 2022-11-25 00:00:00+00 2022-11-25 00:00:00+00 2022-11-25 00:00:00+00
+88043554-4aac-46de-8437-c02fdacfdc9c 88043554-4aac-46de-8437-c02fdacfdc9c {"sub": "88043554-4aac-46de-8437-c02fdacfdc9c", "email": "misael.upton98@hotmail.com"} email 2023-01-19 11:08:37.978799+00 2023-01-19 11:08:37.97884+00 2023-01-19 11:08:37.97884+00
+615357b8-c668-45ee-a749-c96db1aabc7a 615357b8-c668-45ee-a749-c96db1aabc7a {"sub": "615357b8-c668-45ee-a749-c96db1aabc7a", "email": "albert.kihn95@yahoo.com"} email 2023-01-19 11:08:37.985094+00 2023-01-19 11:08:37.98513+00 2023-01-19 11:08:37.98513+00
+369664ac-9358-4b51-91b5-79ddca7ef0b2 369664ac-9358-4b51-91b5-79ddca7ef0b2 {"sub": "369664ac-9358-4b51-91b5-79ddca7ef0b2", "email": "maida_walsh61@yahoo.com"} email 2023-01-19 11:08:37.991451+00 2023-01-19 11:08:37.991486+00 2023-01-19 11:08:37.991486+00
+e7faf866-0438-4b7c-8de3-1c134c707806 e7faf866-0438-4b7c-8de3-1c134c707806 {"sub": "e7faf866-0438-4b7c-8de3-1c134c707806", "email": "osvaldo.bogan15@yahoo.com"} email 2023-01-19 11:08:37.996337+00 2023-01-19 11:08:37.996377+00 2023-01-19 11:08:37.996377+00
+af00f659-028a-4268-b6b5-fa36e40e190e af00f659-028a-4268-b6b5-fa36e40e190e {"sub": "af00f659-028a-4268-b6b5-fa36e40e190e", "email": "wyman67@gmail.com"} email 2023-01-19 11:08:38.002463+00 2023-01-19 11:08:38.002505+00 2023-01-19 11:08:38.002505+00
+07616a1c-e8ce-489a-a74b-adab1f4e1b32 07616a1c-e8ce-489a-a74b-adab1f4e1b32 {"sub": "07616a1c-e8ce-489a-a74b-adab1f4e1b32", "email": "rylee68@yahoo.com"} email 2023-01-19 11:08:38.010583+00 2023-01-19 11:08:38.010667+00 2023-01-19 11:08:38.010667+00
+ab38ad48-7b50-4e66-85b1-7d78a61a04f0 ab38ad48-7b50-4e66-85b1-7d78a61a04f0 {"sub": "ab38ad48-7b50-4e66-85b1-7d78a61a04f0", "email": "devin.rath@gmail.com"} email 2023-01-19 11:08:38.018797+00 2023-01-19 11:08:38.018847+00 2023-01-19 11:08:38.018847+00
+932ce7f7-e57d-45c3-bc7d-63362e2d67aa 932ce7f7-e57d-45c3-bc7d-63362e2d67aa {"sub": "932ce7f7-e57d-45c3-bc7d-63362e2d67aa", "email": "eino_considine67@hotmail.com"} email 2023-01-19 11:08:38.010854+00 2023-01-19 11:08:38.01089+00 2023-01-19 11:08:38.01089+00
+23e19499-63e4-4fee-9718-bd24584fdca0 23e19499-63e4-4fee-9718-bd24584fdca0 {"sub": "23e19499-63e4-4fee-9718-bd24584fdca0", "email": "royce_hermiston@gmail.com"} email 2023-01-19 11:08:38.021799+00 2023-01-19 11:08:38.02184+00 2023-01-19 11:08:38.02184+00
+b301a3c1-022f-49fa-a6fb-41c8cdd521a9 b301a3c1-022f-49fa-a6fb-41c8cdd521a9 {"sub": "b301a3c1-022f-49fa-a6fb-41c8cdd521a9", "email": "jerrod70@yahoo.com"} email 2023-01-19 11:08:38.04489+00 2023-01-19 11:08:38.044935+00 2023-01-19 11:08:38.044935+00
+a7ca4ce7-7763-4edc-869a-dc3afb4dc1c2 a7ca4ce7-7763-4edc-869a-dc3afb4dc1c2 {"sub": "a7ca4ce7-7763-4edc-869a-dc3afb4dc1c2", "email": "ada.parker@gmail.com"} email 2023-01-19 11:08:38.626499+00 2023-01-19 11:08:38.626538+00 2023-01-19 11:08:38.626538+00
+d977c288-485b-44f4-aa34-94c232decbed d977c288-485b-44f4-aa34-94c232decbed {"sub": "d977c288-485b-44f4-aa34-94c232decbed", "email": "aryanna_dickens47@gmail.com"} email 2023-01-19 11:08:38.797556+00 2023-01-19 11:08:38.797606+00 2023-01-19 11:08:38.797606+00
+53cd7be4-c374-492c-aa18-06febf196607 53cd7be4-c374-492c-aa18-06febf196607 {"sub": "53cd7be4-c374-492c-aa18-06febf196607", "email": "lonnie_huels69@gmail.com"} email 2023-01-19 11:08:38.816211+00 2023-01-19 11:08:38.816253+00 2023-01-19 11:08:38.816253+00
+2b817ed6-e9b4-4ab6-a97c-8a5c5cca80b5 2b817ed6-e9b4-4ab6-a97c-8a5c5cca80b5 {"sub": "2b817ed6-e9b4-4ab6-a97c-8a5c5cca80b5", "email": "jennings.watsica71@hotmail.com"} email 2023-01-19 11:08:38.844286+00 2023-01-19 11:08:38.844322+00 2023-01-19 11:08:38.844322+00
+ba1d736c-18f9-4eca-8000-05bd223d097f ba1d736c-18f9-4eca-8000-05bd223d097f {"sub": "ba1d736c-18f9-4eca-8000-05bd223d097f", "email": "alia.emmerich42@hotmail.com"} email 2023-01-19 11:08:38.883805+00 2023-01-19 11:08:38.883849+00 2023-01-19 11:08:38.883849+00
+1d1c4838-d7bf-4830-945e-7f1c31934340 1d1c4838-d7bf-4830-945e-7f1c31934340 {"sub": "1d1c4838-d7bf-4830-945e-7f1c31934340", "email": "mallory_kuhn@yahoo.com"} email 2023-01-19 11:08:38.908677+00 2023-01-19 11:08:38.908717+00 2023-01-19 11:08:38.908717+00
+abb439a6-9812-4edb-8f54-8f99830a9d51 abb439a6-9812-4edb-8f54-8f99830a9d51 {"sub": "abb439a6-9812-4edb-8f54-8f99830a9d51", "email": "julianne.schinner98@gmail.com"} email 2023-01-19 11:08:38.943988+00 2023-01-19 11:08:38.944025+00 2023-01-19 11:08:38.944025+00
+acbbb7e0-44ff-42fa-a8aa-69ad98666e31 acbbb7e0-44ff-42fa-a8aa-69ad98666e31 {"sub": "acbbb7e0-44ff-42fa-a8aa-69ad98666e31", "email": "adonis_oconnell@yahoo.com"} email 2023-01-19 11:08:39.009983+00 2023-01-19 11:08:39.010021+00 2023-01-19 11:08:39.010021+00
+67cb7f0e-c295-4d41-83a0-761568b7a13c 67cb7f0e-c295-4d41-83a0-761568b7a13c {"sub": "67cb7f0e-c295-4d41-83a0-761568b7a13c", "email": "craig.dietrich31@hotmail.com"} email 2023-01-19 11:08:39.032835+00 2023-01-19 11:08:39.032875+00 2023-01-19 11:08:39.032875+00
+d1c2cd22-52db-4074-b0ba-e7152df4a27d d1c2cd22-52db-4074-b0ba-e7152df4a27d {"sub": "d1c2cd22-52db-4074-b0ba-e7152df4a27d", "email": "sunny.welch@gmail.com"} email 2023-01-19 11:08:39.03801+00 2023-01-19 11:08:39.038065+00 2023-01-19 11:08:39.038065+00
+e6e80a3d-8435-4d09-bba3-e8f158ff93e4 e6e80a3d-8435-4d09-bba3-e8f158ff93e4 {"sub": "e6e80a3d-8435-4d09-bba3-e8f158ff93e4", "email": "elliott_goldner77@yahoo.com"} email 2023-01-19 11:08:39.268192+00 2023-01-19 11:08:39.268229+00 2023-01-19 11:08:39.268229+00
+8e40363f-20c0-4f58-ac8f-fecaec606923 8e40363f-20c0-4f58-ac8f-fecaec606923 {"sub": "8e40363f-20c0-4f58-ac8f-fecaec606923", "email": "cheyenne_cassin@hotmail.com"} email 2023-01-19 11:08:39.345276+00 2023-01-19 11:08:39.345311+00 2023-01-19 11:08:39.345311+00
+5c6a9645-29e1-478e-9cba-d048ab579bd1 5c6a9645-29e1-478e-9cba-d048ab579bd1 {"sub": "5c6a9645-29e1-478e-9cba-d048ab579bd1", "email": "magdalena_metz@gmail.com"} email 2023-01-19 11:08:39.458571+00 2023-01-19 11:08:39.458609+00 2023-01-19 11:08:39.458609+00
+4535c79c-f973-447b-8692-6f2207f6efcb 4535c79c-f973-447b-8692-6f2207f6efcb {"sub": "4535c79c-f973-447b-8692-6f2207f6efcb", "email": "madisen_harris32@gmail.com"} email 2023-01-19 11:08:39.50468+00 2023-01-19 11:08:39.504717+00 2023-01-19 11:08:39.504717+00
+581483e9-b39a-477c-a712-a590a6bd2e8d 581483e9-b39a-477c-a712-a590a6bd2e8d {"sub": "581483e9-b39a-477c-a712-a590a6bd2e8d", "email": "alexandre_rodriguez@gmail.com"} email 2023-01-19 11:08:39.507102+00 2023-01-19 11:08:39.507136+00 2023-01-19 11:08:39.507136+00
+0d9fd639-9b14-49c8-a755-36565a345da5 0d9fd639-9b14-49c8-a755-36565a345da5 {"sub": "0d9fd639-9b14-49c8-a755-36565a345da5", "email": "pierre33@gmail.com"} email 2023-01-19 11:08:39.511573+00 2023-01-19 11:08:39.51161+00 2023-01-19 11:08:39.51161+00
+af4d7654-d31d-40e9-8e31-8031b29651bf af4d7654-d31d-40e9-8e31-8031b29651bf {"sub": "af4d7654-d31d-40e9-8e31-8031b29651bf", "email": "laney.olson@gmail.com"} email 2023-01-19 11:08:39.619015+00 2023-01-19 11:08:39.619079+00 2023-01-19 11:08:39.619079+00
+c7f6fb1f-a6d9-45b1-a732-4e80877266ea c7f6fb1f-a6d9-45b1-a732-4e80877266ea {"sub": "c7f6fb1f-a6d9-45b1-a732-4e80877266ea", "email": "jodie.wunsch60@gmail.com"} email 2023-01-19 11:08:39.636656+00 2023-01-19 11:08:39.636691+00 2023-01-19 11:08:39.636691+00
+bdc41348-d0ff-4716-b03e-505397255296 bdc41348-d0ff-4716-b03e-505397255296 {"sub": "bdc41348-d0ff-4716-b03e-505397255296", "email": "micheal.homenick@yahoo.com"} email 2023-01-19 11:08:39.669035+00 2023-01-19 11:08:39.669077+00 2023-01-19 11:08:39.669077+00
+b5aca4b6-67f6-47b1-b2f5-794f354e183a b5aca4b6-67f6-47b1-b2f5-794f354e183a {"sub": "b5aca4b6-67f6-47b1-b2f5-794f354e183a", "email": "pauline.moore@hotmail.com"} email 2023-01-19 11:08:39.696557+00 2023-01-19 11:08:39.696592+00 2023-01-19 11:08:39.696592+00
+fef209ad-b677-44a7-82a9-899c33490075 fef209ad-b677-44a7-82a9-899c33490075 {"sub": "fef209ad-b677-44a7-82a9-899c33490075", "email": "ana.nikolaus95@yahoo.com"} email 2023-01-19 14:40:58.677532+00 2023-01-19 14:40:58.67758+00 2023-01-19 14:40:58.67758+00
+5de1bfbc-4a77-4e6b-8adf-e5572a32e12e 5de1bfbc-4a77-4e6b-8adf-e5572a32e12e {"sub": "5de1bfbc-4a77-4e6b-8adf-e5572a32e12e", "email": "coby91@yahoo.com"} email 2023-01-19 14:40:58.672691+00 2023-01-19 14:40:58.67274+00 2023-01-19 14:40:58.67274+00
+68fb3828-45a2-41ee-8c32-fd87525d955e 68fb3828-45a2-41ee-8c32-fd87525d955e {"sub": "68fb3828-45a2-41ee-8c32-fd87525d955e", "email": "vivian_rogahn@gmail.com"} email 2023-01-19 14:40:58.904839+00 2023-01-19 14:40:58.904882+00 2023-01-19 14:40:58.904882+00
+fe8d52b3-9bb2-4063-95da-733f61763be0 fe8d52b3-9bb2-4063-95da-733f61763be0 {"sub": "fe8d52b3-9bb2-4063-95da-733f61763be0", "email": "demetris99@yahoo.com"} email 2023-01-19 14:40:59.04053+00 2023-01-19 14:40:59.040568+00 2023-01-19 14:40:59.040568+00
+2d7cc448-9478-4c4b-b9c1-b6005b3b2517 2d7cc448-9478-4c4b-b9c1-b6005b3b2517 {"sub": "2d7cc448-9478-4c4b-b9c1-b6005b3b2517", "email": "casimir.williamson41@gmail.com"} email 2023-01-19 14:40:59.073058+00 2023-01-19 14:40:59.073104+00 2023-01-19 14:40:59.073104+00
+754e01ee-8bc6-42cf-875a-c596d4b5c108 754e01ee-8bc6-42cf-875a-c596d4b5c108 {"sub": "754e01ee-8bc6-42cf-875a-c596d4b5c108", "email": "rod_hoppe83@hotmail.com"} email 2023-01-19 14:40:59.125133+00 2023-01-19 14:40:59.125176+00 2023-01-19 14:40:59.125176+00
+27b98fb2-2a63-4ea2-92da-845e45c1f530 27b98fb2-2a63-4ea2-92da-845e45c1f530 {"sub": "27b98fb2-2a63-4ea2-92da-845e45c1f530", "email": "marlon.torp45@gmail.com"} email 2023-01-19 14:40:59.164371+00 2023-01-19 14:40:59.164412+00 2023-01-19 14:40:59.164412+00
+a23c4ec2-eb31-420d-bd89-ec49065bed3f a23c4ec2-eb31-420d-bd89-ec49065bed3f {"sub": "a23c4ec2-eb31-420d-bd89-ec49065bed3f", "email": "ansel.kessler89@yahoo.com"} email 2023-01-19 14:40:59.194516+00 2023-01-19 14:40:59.194557+00 2023-01-19 14:40:59.194557+00
+88847f43-2f69-4c26-b00b-6b59a38ef164 88847f43-2f69-4c26-b00b-6b59a38ef164 {"sub": "88847f43-2f69-4c26-b00b-6b59a38ef164", "email": "cali_orn71@yahoo.com"} email 2023-01-19 14:40:59.195309+00 2023-01-19 14:40:59.195346+00 2023-01-19 14:40:59.195346+00
+561e28e6-7ce5-4282-9f51-7f59722170ca 561e28e6-7ce5-4282-9f51-7f59722170ca {"sub": "561e28e6-7ce5-4282-9f51-7f59722170ca", "email": "rey32@gmail.com"} email 2023-01-19 14:40:59.192048+00 2023-01-19 14:40:59.192086+00 2023-01-19 14:40:59.192086+00
+e42df43c-3603-45ea-a281-1c1c1b29965c e42df43c-3603-45ea-a281-1c1c1b29965c {"sub": "e42df43c-3603-45ea-a281-1c1c1b29965c", "email": "thora.renner@yahoo.com"} email 2023-01-19 14:40:59.614062+00 2023-01-19 14:40:59.614098+00 2023-01-19 14:40:59.614098+00
+07ede456-d7f3-4840-a2b2-6394cb6e44c6 07ede456-d7f3-4840-a2b2-6394cb6e44c6 {"sub": "07ede456-d7f3-4840-a2b2-6394cb6e44c6", "email": "estel.kovacek68@gmail.com"} email 2023-01-19 14:40:59.653972+00 2023-01-19 14:40:59.654015+00 2023-01-19 14:40:59.654015+00
+8858520b-4d3e-4804-937c-e1fa8b355e1e 8858520b-4d3e-4804-937c-e1fa8b355e1e {"sub": "8858520b-4d3e-4804-937c-e1fa8b355e1e", "email": "althea_dickens@hotmail.com"} email 2023-01-19 14:40:59.754789+00 2023-01-19 14:40:59.754826+00 2023-01-19 14:40:59.754826+00
+26889fa5-94d3-4150-8b17-d7413e682652 26889fa5-94d3-4150-8b17-d7413e682652 {"sub": "26889fa5-94d3-4150-8b17-d7413e682652", "email": "francis_lockman21@yahoo.com"} email 2023-01-19 14:40:59.808917+00 2023-01-19 14:40:59.808954+00 2023-01-19 14:40:59.808954+00
+9beabeb7-b51b-416c-9d3b-d23badeb7c5c 9beabeb7-b51b-416c-9d3b-d23badeb7c5c {"sub": "9beabeb7-b51b-416c-9d3b-d23badeb7c5c", "email": "adonis_lemke@gmail.com"} email 2023-01-19 14:40:59.815894+00 2023-01-19 14:40:59.815928+00 2023-01-19 14:40:59.815928+00
+b1262b76-e470-4f71-ad33-86919606391d b1262b76-e470-4f71-ad33-86919606391d {"sub": "b1262b76-e470-4f71-ad33-86919606391d", "email": "humberto_wolf@gmail.com"} email 2023-01-19 14:40:59.859656+00 2023-01-19 14:40:59.859692+00 2023-01-19 14:40:59.859692+00
+3298ca3a-400a-459e-b0a7-426fd6e9b716 3298ca3a-400a-459e-b0a7-426fd6e9b716 {"sub": "3298ca3a-400a-459e-b0a7-426fd6e9b716", "email": "buddy_hintz@gmail.com"} email 2023-01-19 14:40:59.888234+00 2023-01-19 14:40:59.888268+00 2023-01-19 14:40:59.888268+00
+a413cb80-834e-4d8a-b29a-a02ecf139f7c a413cb80-834e-4d8a-b29a-a02ecf139f7c {"sub": "a413cb80-834e-4d8a-b29a-a02ecf139f7c", "email": "brando_treutel@gmail.com"} email 2023-01-19 14:41:00.294838+00 2023-01-19 14:41:00.294879+00 2023-01-19 14:41:00.294879+00
+b096f178-9502-4837-bf3c-37acccf61eb9 b096f178-9502-4837-bf3c-37acccf61eb9 {"sub": "b096f178-9502-4837-bf3c-37acccf61eb9", "email": "ara_volkman7@gmail.com"} email 2023-01-19 14:41:00.380085+00 2023-01-19 14:41:00.380125+00 2023-01-19 14:41:00.380125+00
+54b2da7d-4765-44f1-9e95-b6ebd5494530 54b2da7d-4765-44f1-9e95-b6ebd5494530 {"sub": "54b2da7d-4765-44f1-9e95-b6ebd5494530", "email": "horace_borer96@yahoo.com"} email 2023-01-19 14:41:00.424166+00 2023-01-19 14:41:00.424205+00 2023-01-19 14:41:00.424205+00
+88e9b920-6bc9-4242-a245-2c2164c01092 88e9b920-6bc9-4242-a245-2c2164c01092 {"sub": "88e9b920-6bc9-4242-a245-2c2164c01092", "email": "princess24@gmail.com"} email 2023-01-19 14:41:00.72796+00 2023-01-19 14:41:00.727998+00 2023-01-19 14:41:00.727998+00
+7dff3d1f-c92e-45d8-ad4f-47976249728f 7dff3d1f-c92e-45d8-ad4f-47976249728f {"sub": "7dff3d1f-c92e-45d8-ad4f-47976249728f", "email": "heather.corwin32@hotmail.com"} email 2023-01-19 14:41:00.732996+00 2023-01-19 14:41:00.733031+00 2023-01-19 14:41:00.733031+00
+ec352166-6475-453f-825b-01bee04214d9 ec352166-6475-453f-825b-01bee04214d9 {"sub": "ec352166-6475-453f-825b-01bee04214d9", "email": "jamarcus94@hotmail.com"} email 2023-01-19 14:41:00.801386+00 2023-01-19 14:41:00.801419+00 2023-01-19 14:41:00.801419+00
+b576f0a4-3369-4e89-8221-72a89807dde9 b576f0a4-3369-4e89-8221-72a89807dde9 {"sub": "b576f0a4-3369-4e89-8221-72a89807dde9", "email": "efrain37@yahoo.com"} email 2023-01-19 14:41:00.824851+00 2023-01-19 14:41:00.824888+00 2023-01-19 14:41:00.824888+00
+2e320c50-4640-43d4-8e82-5e66c430decd 2e320c50-4640-43d4-8e82-5e66c430decd {"sub": "2e320c50-4640-43d4-8e82-5e66c430decd", "email": "anibal61@yahoo.com"} email 2023-01-19 14:40:59.474355+00 2023-01-19 14:40:59.474391+00 2023-01-19 14:40:59.474391+00
+ca9f8106-a060-4bd5-be47-d9f384e415ca ca9f8106-a060-4bd5-be47-d9f384e415ca {"sub": "ca9f8106-a060-4bd5-be47-d9f384e415ca", "email": "gavin33@hotmail.com"} email 2023-01-19 14:41:00.351925+00 2023-01-19 14:41:00.351966+00 2023-01-19 14:41:00.351966+00
+46867bb3-7c26-4ced-9ec0-268afda9ca10 46867bb3-7c26-4ced-9ec0-268afda9ca10 {"sub": "46867bb3-7c26-4ced-9ec0-268afda9ca10", "email": "lewis62@gmail.com"} email 2023-01-19 14:40:59.489324+00 2023-01-19 14:40:59.489361+00 2023-01-19 14:40:59.489361+00
+366b7862-08df-4b9e-8ba3-8e2d7fbe7a40 366b7862-08df-4b9e-8ba3-8e2d7fbe7a40 {"sub": "366b7862-08df-4b9e-8ba3-8e2d7fbe7a40", "email": "lue.dibbert26@hotmail.com"} email 2023-01-19 14:41:00.341378+00 2023-01-19 14:41:00.341415+00 2023-01-19 14:41:00.341415+00
+7f08b69b-c277-4af8-a51e-9f80bad06430 7f08b69b-c277-4af8-a51e-9f80bad06430 {"sub": "7f08b69b-c277-4af8-a51e-9f80bad06430", "email": "kobe_bergnaum47@yahoo.com"} email 2023-01-19 14:40:59.74144+00 2023-01-19 14:40:59.741477+00 2023-01-19 14:40:59.741477+00
+0b448f5c-7c26-498b-8d13-7049cf82037c 0b448f5c-7c26-498b-8d13-7049cf82037c {"sub": "0b448f5c-7c26-498b-8d13-7049cf82037c", "email": "arne_bayer91@yahoo.com"} email 2023-01-19 14:41:00.797067+00 2023-01-19 14:41:00.79713+00 2023-01-19 14:41:00.79713+00
+\.
+
+
+--
+-- Data for Name: instances; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.instances (id, uuid, raw_base_config, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: mfa_amr_claims; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.mfa_amr_claims (session_id, created_at, updated_at, authentication_method, id) FROM stdin;
+\.
+
+
+--
+-- Data for Name: mfa_challenges; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.mfa_challenges (id, factor_id, created_at, verified_at, ip_address) FROM stdin;
+\.
+
+
+--
+-- Data for Name: mfa_factors; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.mfa_factors (id, user_id, friendly_name, factor_type, status, created_at, updated_at, secret) FROM stdin;
+\.
+
+
+--
+-- Data for Name: refresh_tokens; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.refresh_tokens (instance_id, id, token, user_id, revoked, created_at, updated_at, parent, session_id) FROM stdin;
+00000000-0000-0000-0000-000000000000 1 pBxe3O0yvpz4MqgUFS_wnQ be55c6cf-94d2-44a4-a119-61297d68c0e8 f 2022-08-30 12:59:49.906193+00 2022-08-30 12:59:49.906197+00 \N 0511ce36-dba0-4a11-9b4c-0b68534c061f
+00000000-0000-0000-0000-000000000000 2 bhzSsrlwilQCq_Wh50aOPw 1b48e703-cb29-4b76-b804-82a53f074b93 f 2022-09-14 10:19:09.444837+00 2022-09-14 10:19:09.444841+00 \N 2cd6bfe6-1132-4ff4-95b4-026db86e8bcf
+00000000-0000-0000-0000-000000000000 3 zU3aesC_qCRQ9wchR_CpFQ 1b48e703-cb29-4b76-b804-82a53f074b93 f 2022-09-20 09:06:33.911565+00 2022-09-20 09:06:33.911568+00 \N 5f93a2d7-5712-4216-a6e7-4c7de40bafa4
+00000000-0000-0000-0000-000000000000 4 kW81POOeB4Ts45afIog8WA 1b48e703-cb29-4b76-b804-82a53f074b93 f 2022-09-20 09:23:51.629517+00 2022-09-20 09:23:51.629521+00 \N 379572ef-778e-4c81-8f42-0b2b6961d004
+00000000-0000-0000-0000-000000000000 5 r60ODOU2UxrvencX5E1U-g 1b48e703-cb29-4b76-b804-82a53f074b93 f 2022-09-20 09:32:43.911888+00 2022-09-20 09:32:43.911891+00 \N b1d77e87-9a68-448d-9c6a-7580f1649f08
+\.
+
+
+--
+-- Data for Name: saml_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.saml_providers (id, sso_provider_id, entity_id, metadata_xml, metadata_url, attribute_mapping, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: saml_relay_states; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.saml_relay_states (id, sso_provider_id, request_id, for_email, redirect_to, from_ip_address, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: schema_migrations; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.schema_migrations (version) FROM stdin;
+20171026211738
+20171026211808
+20171026211834
+20180103212743
+20180108183307
+20180119214651
+20180125194653
+00
+20210710035447
+20210722035447
+20210730183235
+20210909172000
+20210927181326
+20211122151130
+20211124214934
+20211202183645
+20220114185221
+20220114185340
+20220224000811
+20220323170000
+20220429102000
+20220531120530
+20220614074223
+20220811173540
+20221003041349
+20221003041400
+20221011041400
+20221020193600
+20221021073300
+20221021082433
+20221027105023
+20221114143122
+20221114143410
+20221125140132
+20221208132122
+20221215195500
+20221215195800
+20221215195900
+20230116124310
+20230116124412
+20230131181311
+20230322519590
+20230402418590
+20230411005111
+\.
+
+
+--
+-- Data for Name: sessions; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.sessions (id, user_id, created_at, updated_at, factor_id, aal, not_after) FROM stdin;
+0511ce36-dba0-4a11-9b4c-0b68534c061f be55c6cf-94d2-44a4-a119-61297d68c0e8 2022-08-30 12:59:49.904128+00 2022-08-30 12:59:49.904133+00 \N \N \N
+2cd6bfe6-1132-4ff4-95b4-026db86e8bcf 1b48e703-cb29-4b76-b804-82a53f074b93 2022-09-14 10:19:09.443186+00 2022-09-14 10:19:09.44319+00 \N \N \N
+5f93a2d7-5712-4216-a6e7-4c7de40bafa4 1b48e703-cb29-4b76-b804-82a53f074b93 2022-09-20 09:06:33.910434+00 2022-09-20 09:06:33.910436+00 \N \N \N
+379572ef-778e-4c81-8f42-0b2b6961d004 1b48e703-cb29-4b76-b804-82a53f074b93 2022-09-20 09:23:51.627974+00 2022-09-20 09:23:51.627976+00 \N \N \N
+b1d77e87-9a68-448d-9c6a-7580f1649f08 1b48e703-cb29-4b76-b804-82a53f074b93 2022-09-20 09:32:43.910773+00 2022-09-20 09:32:43.910776+00 \N \N \N
+\.
+
+
+--
+-- Data for Name: sso_domains; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.sso_domains (id, sso_provider_id, domain, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: sso_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.sso_providers (id, resource_id, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Data for Name: users; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
+--
+
+COPY auth.users (instance_id, id, aud, role, email, encrypted_password, email_confirmed_at, invited_at, confirmation_token, confirmation_sent_at, recovery_token, recovery_sent_at, email_change_token_new, email_change, email_change_sent_at, last_sign_in_at, raw_app_meta_data, raw_user_meta_data, is_super_admin, created_at, updated_at, phone, phone_confirmed_at, phone_change, phone_change_token, phone_change_sent_at, email_change_token_current, email_change_confirm_status, banned_until, reauthentication_token, reauthentication_sent_at, is_sso_user, deleted_at) FROM stdin;
+00000000-0000-0000-0000-000000000000 be55c6cf-94d2-44a4-a119-61297d68c0e8 authenticated authenticated ionicisere@gmail.com $2a$10$r/w9qJ9Z3yr5hYHubUweZejnj7tqhnTkuiGPo5HJ/JDigTfEWbDxS 2022-08-30 12:59:49.902581+00 2022-08-30 12:59:35.990761+00 2022-08-30 12:59:35.990761+00 \N \N 2022-08-30 12:59:49.904092+00 {"provider": "email", "providers": ["email"]} {} \N 2022-08-30 12:59:35.982779+00 2022-08-30 12:59:49.909025+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 1b48e703-cb29-4b76-b804-82a53f074b93 authenticated authenticated bradley@appwrite.io $2a$10$MjBZgSYw.PbNwWogjjA44eFDi1Wxj3qR9xwL57r38iS1W/g7mqD1e 2022-09-14 10:19:09.44204+00 2022-09-14 10:09:18.313665+00 2022-09-14 10:09:18.313665+00 2022-09-20 09:32:37.017851+00 \N 2022-09-20 09:32:43.910738+00 {"provider": "email", "providers": ["email"]} {} \N 2022-09-14 10:09:18.30351+00 2022-09-20 09:33:47.026002+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 a7ca4ce7-7763-4edc-869a-dc3afb4dc1c2 authenticated authenticated ada.parker@gmail.com $2a$10$GeeaVuNxnYP2iBpMmLl.oOWHCge9/ICG4OeduhRC9oh4WJ3bQ3E2O \N \N f40c311041b24216ebe846312fe65dd159569a3472fa477e66650d02 2023-01-19 11:08:38.627948+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.621709+00 2023-01-19 11:08:39.171258+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 e6e80a3d-8435-4d09-bba3-e8f158ff93e4 authenticated authenticated elliott_goldner77@yahoo.com $2a$10$K5FN9Y17r2M3vRnJjdBxxOc02akQY9JxN38Ps09cUuh/FdNUveoSq \N \N e5e0df9fc30adeb96c73901e04ee086ee1f1045563f16705e6e00252 2023-01-19 11:08:39.294093+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.2656+00 2023-01-19 11:08:39.856707+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 615357b8-c668-45ee-a749-c96db1aabc7a authenticated authenticated albert.kihn95@yahoo.com $2a$10$NGZAAOfXeheUoH9V3dnRoeR.r3J5ynnSZ6KjvHxOUlV8XUrulJzQa \N \N 7c6d17d95f79959cb5c2e78bcfce0f3b4d79a64d6e944c8f1c17fd0b 2023-01-19 11:08:37.987925+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.961105+00 2023-01-19 11:08:38.533265+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 932ce7f7-e57d-45c3-bc7d-63362e2d67aa authenticated authenticated eino_considine67@hotmail.com $2a$10$UAtycuP68R6/s7BBXckGbeGVg26N/CuIBqvwdTPV.//yoCaaW9sNO \N \N fe79c5e0ddc151b8d0b3d99a86b6f9c02f4fc4e3b5f8faae11ec5d4b 2023-01-19 11:08:38.04048+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.890482+00 2023-01-19 11:08:38.546294+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 e7faf866-0438-4b7c-8de3-1c134c707806 authenticated authenticated osvaldo.bogan15@yahoo.com $2a$10$hK1ujHgvMcBgzLJ4FeKH6Omz7tX6voVKzFvIVoGpEvf0R7.0HfqLW \N \N 88fa60647707bca81b0dfdb171317655fe6258bca6967a3d8f5a7147 2023-01-19 11:08:37.99834+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.832183+00 2023-01-19 11:08:38.622417+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 b301a3c1-022f-49fa-a6fb-41c8cdd521a9 authenticated authenticated jerrod70@yahoo.com $2a$10$OJSneRhPXRpWXn05ZkH6X..5/7iRVRbnU7sBtvFFhkLfSUTqAtEtu \N \N f547effd9a91b0f30b777e9696f692dfb20d56a4254c8b1ec9fa67f5 2023-01-19 11:08:38.048714+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.976452+00 2023-01-19 11:08:38.622149+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 23e19499-63e4-4fee-9718-bd24584fdca0 authenticated authenticated royce_hermiston@gmail.com $2a$10$5M2B42RfDcKhqgr9q5SoDO4OXhxYJ7i/E3XDnX8TMiGLH1U2LpDa2 \N \N 077fa18a56afb21c750fc8398d9814d3bc0b9bf0a9b255c810594607 2023-01-19 11:08:38.040758+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.915266+00 2023-01-19 11:08:38.623762+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 07616a1c-e8ce-489a-a74b-adab1f4e1b32 authenticated authenticated rylee68@yahoo.com $2a$10$ZpClmjACR4TcfxpZ1lVoWuisi5K.GCbALgFJwrOJQSJuvLF48um0K \N \N 892319f33d84c697a7f743de2afd667f39cf020eff19b0ac524257c0 2023-01-19 11:08:38.033036+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.998954+00 2023-01-19 11:08:38.641677+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 53cd7be4-c374-492c-aa18-06febf196607 authenticated authenticated lonnie_huels69@gmail.com $2a$10$DOxK2zFxiouc5o1cPMnkcuTdM4g4FoJs3tMs49Xr1zuO/HwRTGebe \N \N 9826cf5f7c345b3af8ee746cd644d917a0ea83e235e09cb866429f9c 2023-01-19 11:08:38.818433+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.641261+00 2023-01-19 11:08:39.293169+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 4535c79c-f973-447b-8692-6f2207f6efcb authenticated authenticated madisen_harris32@gmail.com $2a$10$iDDzjps6TkD.ld6Ym5L.cuKBCoTTZPGXgTfebkoLNXRF8.svFfz5. \N \N f326f2090e51ceab905155061f777c98c549cc95888cd7c1ba344d22 2023-01-19 11:08:39.506209+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.502072+00 2023-01-19 11:08:39.904436+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 ab38ad48-7b50-4e66-85b1-7d78a61a04f0 authenticated authenticated devin.rath@gmail.com $2a$10$5kCdSNjRcHN8npUjzsQ7FeHhl3nlBh79iJvzrVK461yIYbJfaWOgG \N \N 989e63c456f64ef55f43796f35b57c57114ab81ca3d1675b765e98e5 2023-01-19 11:08:38.033607+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.984272+00 2023-01-19 11:08:38.724608+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 abb439a6-9812-4edb-8f54-8f99830a9d51 authenticated authenticated julianne.schinner98@gmail.com $2a$10$vb3H97UZyGnxRnH.fFWj2ORQJsWAKAGIIg/VxVoj6H/vPrtMuGfEW \N \N 018c2302f9a0f2d411f075cfefd083d71e0f4a010341f4b68b529558 2023-01-19 11:08:38.945423+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.941342+00 2023-01-19 11:08:39.414274+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 bdc41348-d0ff-4716-b03e-505397255296 authenticated authenticated micheal.homenick@yahoo.com $2a$10$3zaSVvuuXN1R8pDFUVcDPu7UdgwJDBMVZ8h7lF2ItZ1fOCfnP1FCa \N \N b0ab2941b518793bc3dd6b78a8f7d22151a6034ea91cdfd350b76702 2023-01-19 11:08:39.670486+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.666419+00 2023-01-19 11:08:39.974713+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 369664ac-9358-4b51-91b5-79ddca7ef0b2 authenticated authenticated maida_walsh61@yahoo.com $2a$10$Q7QA.QW6tPPtX86NRzxqcORC9wR58PWaS5ixYB.9tSz/Txm8RJkJ6 \N \N e8954d47bb74535ecdd509216fbf6b7bb2bc0d82f2d167c334d2f66e 2023-01-19 11:08:37.993574+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.92671+00 2023-01-19 11:08:38.726342+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 67cb7f0e-c295-4d41-83a0-761568b7a13c authenticated authenticated craig.dietrich31@hotmail.com $2a$10$wg.NDIAgvj0zVc0udeucgO0Boc/3x2UV1pE6tWqDonXNTR1jNBc6K \N \N d477bd867d61c1ba94a4384eb406c9ab28d5cda8742cc6057fc639a1 2023-01-19 11:08:39.035758+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.015133+00 2023-01-19 11:08:39.413947+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 c7f6fb1f-a6d9-45b1-a732-4e80877266ea authenticated authenticated jodie.wunsch60@gmail.com $2a$10$Fo0K6NTjFcm5Aoq/xkhYBui0hjBNQIFlKY87aXZGImuTHrCVvn3.y \N \N 4ae77463d8a990faa1989907962d8449bf6866f196ff7ae35a1388a4 2023-01-19 11:08:39.638061+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.630447+00 2023-01-19 11:08:40.031006+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 88043554-4aac-46de-8437-c02fdacfdc9c authenticated authenticated misael.upton98@hotmail.com $2a$10$6nnhh/4pvc7ENxqSgxKeFu1k9K3/IWcXMLFngooQopnx7QRhl.xaG \N \N 12340b0d13e0b3b9ca1bcb93c8dea120c52c9d9c61cc04754b5efb73 2023-01-19 11:08:38.006529+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.952335+00 2023-01-19 11:08:38.725996+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 d1c2cd22-52db-4074-b0ba-e7152df4a27d authenticated authenticated sunny.welch@gmail.com $2a$10$MxZcZmD0RpqUVE2n.t.Vg.7/TMV2t7qPn8Jwh6Y1sK/1tgSARu3Py \N \N dab91bd4244420789fe50b5cd065930ebcdf4dcf4e3acee439e40ae8 2023-01-19 11:08:39.039895+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.029386+00 2023-01-19 11:08:39.461112+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 af4d7654-d31d-40e9-8e31-8031b29651bf authenticated authenticated laney.olson@gmail.com $2a$10$73D85ZzhLD62lQnMog4K0uRZvMlcf0fcvs3fE7NAWNqD5znfoX6aa \N \N bf0f017bc6c07aa07ac4386a62b78e09b9ca0a3060ca5052ee9fdbf9 2023-01-19 11:08:39.620535+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.595651+00 2023-01-19 11:08:39.948053+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 af00f659-028a-4268-b6b5-fa36e40e190e authenticated authenticated wyman67@gmail.com $2a$10$CtF/ECNwNRi.on9UvEmutO/5LgqlXlfLDjtI6Qqkd0tgWngfXCRP2 \N \N 05bc7419506b52d336ea2d804f94e56f52660606dd129c4c5a6b378d 2023-01-19 11:08:38.006106+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:37.88958+00 2023-01-19 11:08:38.778102+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 acbbb7e0-44ff-42fa-a8aa-69ad98666e31 authenticated authenticated adonis_oconnell@yahoo.com $2a$10$gYz/6D4ThCKCwIamrR/DQ.uJt8SM6vq5T3Jy2ux9V3t7o/nVkx2cC \N \N 308e4d2501a2cd6b1fd5c441d868580ad34b6637fb5a4d9362155a60 2023-01-19 11:08:39.011778+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.998524+00 2023-01-19 11:08:39.513701+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 b5aca4b6-67f6-47b1-b2f5-794f354e183a authenticated authenticated pauline.moore@hotmail.com $2a$10$8mzGxW07TrUW3YKfpjlvReoineG5PWWopHIR3hnER107vi4VjTaCq \N \N 0f8bc3154f92e7cd2d2c2af960662770cbc233a16699b372fe46e24a 2023-01-19 11:08:39.698148+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.693733+00 2023-01-19 11:08:40.046381+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 d977c288-485b-44f4-aa34-94c232decbed authenticated authenticated aryanna_dickens47@gmail.com $2a$10$acKiPRIGQc19DLIr2clTzesFMJ86HY0io3JnXIK9hHAna.G2Sh2J6 \N \N acec97cf6dee7adce3fd551a065839a78c2b389f880a285ea859838d 2023-01-19 11:08:38.799099+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.794485+00 2023-01-19 11:08:39.198817+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 8e40363f-20c0-4f58-ac8f-fecaec606923 authenticated authenticated cheyenne_cassin@hotmail.com $2a$10$4vED.s6uCIYpS5oHN/Ge3uUVo4EJ7p47Io.E7x0JiU8H3B/DpsYaW \N \N dc2e42e3c4b43bb7716cb2576e04b9b59ca7af22c43e5e27dcc24357 2023-01-19 11:08:39.346821+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.314765+00 2023-01-19 11:08:39.84668+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 2b817ed6-e9b4-4ab6-a97c-8a5c5cca80b5 authenticated authenticated jennings.watsica71@hotmail.com $2a$10$agWJM753ThOSQdlZNkEBa.RnNUK4oFiXywyfo.5D8D8Cuohj1ZJRe \N \N 5571f3f9f2f5bcf33c0be925871401d3a83256865b77d350082b590d 2023-01-19 11:08:38.845784+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.825053+00 2023-01-19 11:08:39.239774+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 581483e9-b39a-477c-a712-a590a6bd2e8d authenticated authenticated alexandre_rodriguez@gmail.com $2a$10$JVPIgsLvTNqwQX73f724m.k0dwQ8GKvnPdkeech9sUuxb0pdik5Vm \N \N 9f09631bdf96f286f870d52b058d2bb7daa24d97704e971f7f7ba084 2023-01-19 11:08:39.508709+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.411206+00 2023-01-19 11:08:39.892652+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 1d1c4838-d7bf-4830-945e-7f1c31934340 authenticated authenticated mallory_kuhn@yahoo.com $2a$10$fmrY.TdL/f.7YHnDyP3ZUODjglDno405Munb8K3yJ3Tw7TUpXMdCq \N \N b6818ad2fa7592e2c6bd39e5cc608aa3b2ac8f920457732a2c07eb6d 2023-01-19 11:08:38.910173+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.840443+00 2023-01-19 11:08:39.280097+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 5c6a9645-29e1-478e-9cba-d048ab579bd1 authenticated authenticated magdalena_metz@gmail.com $2a$10$14tT9gkqI2nTMWWQFaXT..qnSzbdTQGr5bnZQGkhcjgQT041sIxty \N \N a7d1a730cf9c469069d36270bf16a8f7b719efbb35f498df854b11f4 2023-01-19 11:08:39.482243+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.455923+00 2023-01-19 11:08:39.925029+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 5de1bfbc-4a77-4e6b-8adf-e5572a32e12e authenticated authenticated coby91@yahoo.com $2a$10$ZarjL3uOinIDiJaqXXdQNuCj9Ol6E0pHmTwGYjnDtTV8fjvwLU4p2 \N \N e7cb8b0c7e3f84612f5b127411fc0431e8f2c3f146feb3e3660e8986 2023-01-19 14:40:58.835941+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:58.617251+00 2023-01-19 14:40:59.393384+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 ba1d736c-18f9-4eca-8000-05bd223d097f authenticated authenticated alia.emmerich42@hotmail.com $2a$10$DfXcVwodmMCPyUkkVJhpvOY2qPX1elMpnkmY5RmVfJ6/QYZlluPSG \N \N 49132c9b2f2495e94ffe7e5b51c37f1080ad244941c79ae0cd3ad107 2023-01-19 11:08:38.885235+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:38.880933+00 2023-01-19 11:08:39.260143+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 0d9fd639-9b14-49c8-a755-36565a345da5 authenticated authenticated pierre33@gmail.com $2a$10$VzskcnSwVR3WJflIBh9foeP9zvSIAEs2DUgpl4YnEbZcFMW9O5mmC \N \N 48788ad0d702a5613ba8528faa6d8c5bfe747e1d53981fb37bc02d90 2023-01-19 11:08:39.513064+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 11:08:39.481569+00 2023-01-19 11:08:39.85781+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 07ede456-d7f3-4840-a2b2-6394cb6e44c6 authenticated authenticated estel.kovacek68@gmail.com $2a$10$OkPbpEQ7cFTlJBZbAMLNWu0wvSKI3O11P56RqzN7h.8nwy6aSl2J2 \N \N e4eb7055f04178cd8cf9ece4bb45ba9ad57d1d6ff0eb75aefcb26c64 2023-01-19 14:40:59.655644+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.619794+00 2023-01-19 14:41:00.151257+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 a23c4ec2-eb31-420d-bd89-ec49065bed3f authenticated authenticated ansel.kessler89@yahoo.com $2a$10$90aSXQyDc.VfwmkQX9tFp.DGOx5lknqC/nA8M8yOqaufGCktFmVHW \N \N 795af0b942dd0fbf8860286b6072f592aa0dd21b64a264500468c540 2023-01-19 14:40:59.201093+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.144565+00 2023-01-19 14:40:59.616499+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 27b98fb2-2a63-4ea2-92da-845e45c1f530 authenticated authenticated marlon.torp45@gmail.com $2a$10$ltqikNmlYh/bOgUnnUh.1OiUHTndQUpl9d856BHM7NmlrsJEhqPzy \N \N a912390b874a3a88ac09aad04eb80b509392e427acfbce093e4d58a9 2023-01-19 14:40:59.179137+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.158889+00 2023-01-19 14:40:59.620199+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 88847f43-2f69-4c26-b00b-6b59a38ef164 authenticated authenticated cali_orn71@yahoo.com $2a$10$i/VNgA5Q22gGQ0OCyvcUauCpwVbFUmGx5reFaFoX8ac7a34rTZyCS \N \N a89d90f30b2859d523e8ee9702311dfadfadcd55f9c2e78aa3366149 2023-01-19 14:40:59.197369+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.172183+00 2023-01-19 14:40:59.725418+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 b1262b76-e470-4f71-ad33-86919606391d authenticated authenticated humberto_wolf@gmail.com $2a$10$UDK5nDmKCwix.PYQdpFiQ.KPRDn7cYaL1xuI7dpYKxS4FZtpnCuRO \N \N 2710337612b98c95e51b8bc7900323999363f5a96f163d6fabf73a97 2023-01-19 14:40:59.861071+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.856837+00 2023-01-19 14:41:00.641247+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 366b7862-08df-4b9e-8ba3-8e2d7fbe7a40 authenticated authenticated lue.dibbert26@hotmail.com $2a$10$rH9sNLFro/A32zhE3KJ14eezpNV6axRauEUrvkVVHsiCdiw1QBnti \N \N 10e028c37d3e4ae9eb741c9da1a3615b8b381d81c70f7f71e1e420e4 2023-01-19 14:41:00.342917+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.297873+00 2023-01-19 14:41:00.80361+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 68fb3828-45a2-41ee-8c32-fd87525d955e authenticated authenticated vivian_rogahn@gmail.com $2a$10$L2qcapE93Sq35WR.lHeQ3eRN641Axr9F.QNM/5M6OeqnZdxCzaJIi \N \N a9e8d2db7d93206e509b05a1dd7a3cb10e82ab0bc6465cbd171d634e 2023-01-19 14:40:58.906891+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:58.899728+00 2023-01-19 14:40:59.357833+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 2d7cc448-9478-4c4b-b9c1-b6005b3b2517 authenticated authenticated casimir.williamson41@gmail.com $2a$10$ImEdz6ANAscNyInjDuYGHOCySiEWzV031mQElBoEUp9Q6B7V6EVom \N \N 1848d5557a10b20be09448fc4e8cbf35154ec4cd75f6df06616e113a 2023-01-19 14:40:59.076775+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.017546+00 2023-01-19 14:40:59.488707+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 754e01ee-8bc6-42cf-875a-c596d4b5c108 authenticated authenticated rod_hoppe83@hotmail.com $2a$10$2Is3g0GMBSrY48CZt8OF6u6/tlhzX6OutrWnzUpHt9hZVpp2IQCt. \N \N 923b1d84244e5473b83d8d904e3ca4db70756a21556e85a324be07f1 2023-01-19 14:40:59.127685+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:58.989152+00 2023-01-19 14:40:59.50326+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 fe8d52b3-9bb2-4063-95da-733f61763be0 authenticated authenticated demetris99@yahoo.com $2a$10$qH3xbDG8SP9m5tGLI.dRh.XW31lamljcDfPG0ygyGYV45FIrsVRyu \N \N e99c1d4bdb036ab3073293832c8a78ca4381e6f75a033fa955cd8e41 2023-01-19 14:40:59.173555+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:58.917486+00 2023-01-19 14:40:59.621773+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 b576f0a4-3369-4e89-8221-72a89807dde9 authenticated authenticated efrain37@yahoo.com $2a$10$86vlB0oTb9cdD96.qJ4IDe6pFw.GcjKdaVwwWBpapfGuTYvbEkT8O \N \N 7209056df97fcceaaae6e0782e945ff1ad4ce93cc308596a7a1d776c 2023-01-19 14:41:00.826379+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.821857+00 2023-01-19 14:41:01.163667+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 ca9f8106-a060-4bd5-be47-d9f384e415ca authenticated authenticated gavin33@hotmail.com $2a$10$zvkZ82K9xbd.0NUQpl2.JuAe4mAN9rsd1lMAASR9mRneM.8C530/K \N \N 82eab8491e8bb28564e3ce4e25b7f5e35b280d81a46faa6b14d827fa 2023-01-19 14:41:00.353569+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.338685+00 2023-01-19 14:41:01.164308+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 46867bb3-7c26-4ced-9ec0-268afda9ca10 authenticated authenticated lewis62@gmail.com $2a$10$Ao8UXsOm.mYJx5Y5uxMIXeIySE8TxuS99tTLm2B3iOWwmgV/aCbQm \N \N 98912a145b10712750d9cca55eed5429d0a3b9833bdddaf82322e907 2023-01-19 14:40:59.491954+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.485996+00 2023-01-19 14:41:00.022215+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 2e320c50-4640-43d4-8e82-5e66c430decd authenticated authenticated anibal61@yahoo.com $2a$10$G8qYQ/rI8yteJwQ0hVuqVeaG63IbA.JpU/y19C6yida7Zsq47CVFG \N \N 2cad37b24957edc589b422386958fcb15d676a4339cce9dfbeacc9ea 2023-01-19 14:40:59.475874+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.471653+00 2023-01-19 14:41:00.039101+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 fef209ad-b677-44a7-82a9-899c33490075 authenticated authenticated ana.nikolaus95@yahoo.com $2a$10$xL1HjHXBtGkD05wTk3cx6eefp8GQgb0gngGEhoRu0ipGntps7Kdqm \N \N 20d90286908d350ab9ce64d82bfc26f86abbd0619bebfc25c0c42d21 2023-01-19 14:40:58.725194+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:58.637887+00 2023-01-19 14:40:59.552296+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 7f08b69b-c277-4af8-a51e-9f80bad06430 authenticated authenticated kobe_bergnaum47@yahoo.com $2a$10$FTYKtvyg3bUT6C17QrmGp.FWF91QYzkX5QMMj1YoyqUmtb4VmiWru \N \N 13b88b3e70e3d7f0be7d139a584f87a34673c26613744b532e6d09dc 2023-01-19 14:40:59.833432+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.738616+00 2023-01-19 14:41:00.620983+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 0b448f5c-7c26-498b-8d13-7049cf82037c authenticated authenticated arne_bayer91@yahoo.com $2a$10$FAGausswNagoC2.o5zAEaeGkqcyHYgbbYvM/NpSKki7IsD.Pf2d3C \N \N 5d02b72c31d4551b0e8206a8e2f99ac6a03637614ee91e9549df59ed 2023-01-19 14:41:00.798582+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.794406+00 2023-01-19 14:41:01.192666+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 561e28e6-7ce5-4282-9f51-7f59722170ca authenticated authenticated rey32@gmail.com $2a$10$n9whZrraPvrDrwDORkWUB.9QIZr/8ej10iQWfB5KS2eN3Vqki6S/W \N \N a409dd4395aac24d5dbeff7bfec69b585815213f8b100f5f5a7d222b 2023-01-19 14:40:59.19846+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.150226+00 2023-01-19 14:40:59.574338+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 8858520b-4d3e-4804-937c-e1fa8b355e1e authenticated authenticated althea_dickens@hotmail.com $2a$10$f5rqFcHddSeTVflKLC94/u5x.a9VcISaLnzhussrHbvMlCf/.Gjda \N \N dbc774b5a842c40dc355b06c28af7a610279eb4ee3c0200443a27d13 2023-01-19 14:40:59.756207+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.709773+00 2023-01-19 14:41:00.186285+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 54b2da7d-4765-44f1-9e95-b6ebd5494530 authenticated authenticated horace_borer96@yahoo.com $2a$10$uiyeTSCdmPN639oB.jNXueIHvxlY0rPAhMR2vSg9QTLjW.5h2vL.u \N \N e8c0615575cd86a33292106b3379d6a35798d1fb7c1a0288aa7ce15f 2023-01-19 14:41:00.425868+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.420619+00 2023-01-19 14:41:00.968277+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 e42df43c-3603-45ea-a281-1c1c1b29965c authenticated authenticated thora.renner@yahoo.com $2a$10$mk8kCvtTJUEvNAmpZiqel.F1CUQEefQTlay/ydx3iUcK4v5jG6TDi \N \N 6b02a01a66b56e26e56e7cdd6516ab062f17e162490873002135236e 2023-01-19 14:40:59.615636+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.597518+00 2023-01-19 14:41:00.036891+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 a413cb80-834e-4d8a-b29a-a02ecf139f7c authenticated authenticated brando_treutel@gmail.com $2a$10$EWlXNwEQ4emuyb.BKr2lNuayuBZs/pZ.Ho.KPCNf8wp7h4s/UNDYG \N \N e22020c1d53d0768bbbf2663041053fc141da7a5f48ac3210bec12af 2023-01-19 14:41:00.354617+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.291317+00 2023-01-19 14:41:00.799496+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 b096f178-9502-4837-bf3c-37acccf61eb9 authenticated authenticated ara_volkman7@gmail.com $2a$10$A6db028bqFS8JDrqyVuecOrB2Xq4qgGJgKi.wGhRVgLCSYSVa0jeS \N \N b5fe693c8643381f1bf66e71ba5990e21d870001b638f6b46a5b853b 2023-01-19 14:41:00.382393+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.372818+00 2023-01-19 14:41:00.761849+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 9beabeb7-b51b-416c-9d3b-d23badeb7c5c authenticated authenticated adonis_lemke@gmail.com $2a$10$R5M4FJIYUkuycpYnHdj.oOKulZ2qx1ckeIwvk/.DQ3sFJjFVr7Ox6 \N \N fbbaf841ffa9496051531ca30065e4ff9b74fb8680fd03dccd07961c 2023-01-19 14:40:59.817341+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.813319+00 2023-01-19 14:41:00.560604+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 7dff3d1f-c92e-45d8-ad4f-47976249728f authenticated authenticated heather.corwin32@hotmail.com $2a$10$xwYuDq7WxW6XS3Y6QrRaDu041AzLwqQSc6E/dvlbpIz4U8MvVXsbe \N \N 3d48dacf155e6d9559b3db695c39306b78a39db07fbf6d016a497279 2023-01-19 14:41:00.734371+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.671941+00 2023-01-19 14:41:01.017625+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 3298ca3a-400a-459e-b0a7-426fd6e9b716 authenticated authenticated buddy_hintz@gmail.com $2a$10$wfmwKnT/D3XfYNZo0kljv.wf5GkuUoDZuPOnC7gfc1mRlxtAxPW.i \N \N 9778ff31bdb0115f7448a51f8d3465e0d2bc27372c1785f22bd173f5 2023-01-19 14:40:59.889694+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.885268+00 2023-01-19 14:41:00.590039+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 88e9b920-6bc9-4242-a245-2c2164c01092 authenticated authenticated princess24@gmail.com $2a$10$MKA4HJHa65fZszstcmJ/aOwrV1E.ZbzX4PmIvCi8LKClVgBvYtE4O \N \N eca97274e1ff99f1c5492710315e4e6e00733bd7a47a37eb46d7e585 2023-01-19 14:41:00.729372+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.725169+00 2023-01-19 14:41:01.098846+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 26889fa5-94d3-4150-8b17-d7413e682652 authenticated authenticated francis_lockman21@yahoo.com $2a$10$SzpahifmcMr6M21Hj50C1OQdxNZVDhR2K8uI0uvORHSMkSUQz5dN6 \N \N 1cfa2c89ec0760892cd8b5c8e87bc869c5fc23bd3d85267b7f127d11 2023-01-19 14:40:59.810331+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:40:59.804253+00 2023-01-19 14:41:00.622202+00 \N \N \N 0 \N \N f \N
+00000000-0000-0000-0000-000000000000 ec352166-6475-453f-825b-01bee04214d9 authenticated authenticated jamarcus94@hotmail.com $2a$10$7s5QCZDmZR2hBQim6SvCcuXfKFgSRczFq0HhDaKAgPd2005YfzGuG \N \N 11b9173d4ef911208f3a14d042c6dcd504d14026ef2654799ad53e5e 2023-01-19 14:41:00.802744+00 \N \N \N {"provider": "email", "providers": ["email"]} {} \N 2023-01-19 14:41:00.798465+00 2023-01-19 14:41:01.173877+00 \N \N \N 0 \N \N f \N
+\.
+
+
+--
+-- Data for Name: key; Type: TABLE DATA; Schema: pgsodium; Owner: supabase_admin
+--
+
+COPY pgsodium.key (id, status, created, expires, key_type, key_id, key_context, name, associated_data, raw_key, raw_key_nonce, parent_key, comment, user_data) FROM stdin;
+ed81f770-2c2e-4e89-a64b-a6c7b1dfac1b default 2022-08-22 07:44:16.9012+00 \N \N 1 \\x7067736f6469756d \N associated \N \N \N This is the default key used for vault.secrets \N
+\.
+
+
+--
+-- Data for Name: test; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.test (id, int2, int4, int8, float4, float8, "numeric", json, jsonb, text, "varchar", uuid, date, timetz, "timestamp", timestamptz, bool, boolarr) FROM stdin;
+1 1 2 3 4.14 4.1239 100 {"hello":"world"} {"hello": "world"} {hello,world} {hello,world} 2469ffd8-067a-47e1-b5fc-a9ac41a5fd45 2023-03-28 \N 2023-03-28 07:23:57.205926 2023-03-28 07:23:57.205926+00 t {t,t}
+\.
+
+
+--
+-- Data for Name: test2; Type: TABLE DATA; Schema: public; Owner: postgres
+--
+
+COPY public.test2 (id, created_at, int4, int5, int8, float4, float8, "numeric", json, jsonb, text, "varchar", uuid, date, "time", timetz, "timestamp", timestamptz, bool) FROM stdin;
+1 2023-03-28 07:20:26.831742+00 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N
+\.
+
+
+--
+-- Data for Name: buckets; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
+--
+
+COPY storage.buckets (id, name, owner, created_at, updated_at, public, avif_autodetection, file_size_limit, allowed_mime_types) FROM stdin;
+Test Bucket 1 Test Bucket 1 \N 2023-04-26 03:40:34.087782+00 2023-04-26 03:40:34.087782+00 f f \N \N
+\.
+
+
+--
+-- Data for Name: migrations; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
+--
+
+COPY storage.migrations (id, name, hash, executed_at) FROM stdin;
+0 create-migrations-table e18db593bcde2aca2a408c4d1100f6abba2195df 2022-08-30 09:34:04.331172
+1 initialmigration 6ab16121fbaa08bbd11b712d05f358f9b555d777 2022-08-30 09:34:04.339817
+2 pathtoken-column 49756be03be4c17bb85fe70d4a861f27de7e49ad 2022-08-30 09:34:04.345119
+3 add-migrations-rls bb5d124c53d68635a883e399426c6a5a25fc893d 2022-08-30 09:34:04.373099
+4 add-size-functions 6d79007d04f5acd288c9c250c42d2d5fd286c54d 2022-08-30 09:34:04.392693
+5 change-column-name-in-get-size fd65688505d2ffa9fbdc58a944348dd8604d688c 2022-08-30 09:34:04.399423
+6 add-rls-to-buckets 63e2bab75a2040fee8e3fb3f15a0d26f3380e9b6 2022-08-30 09:34:04.408055
+7 add-public-to-buckets 82568934f8a4d9e0a85f126f6fb483ad8214c418 2022-08-30 09:34:04.414918
+8 fix-search-function 1a43a40eddb525f2e2f26efd709e6c06e58e059c 2022-08-30 09:34:04.421464
+9 search-files-search-function 34c096597eb8b9d077fdfdde9878c88501b2fafc 2022-08-30 09:34:04.427454
+10 add-trigger-to-auto-update-updated_at-column 37d6bb964a70a822e6d37f22f457b9bca7885928 2022-08-30 09:34:04.434434
+11 add-automatic-avif-detection-flag bd76c53a9c564c80d98d119c1b3a28e16c8152db 2023-04-04 10:26:55.90276
+12 add-bucket-custom-limits cbe0a4c32a0e891554a21020433b7a4423c07ee7 2023-04-04 10:26:55.941199
+13 use-bytes-for-max-size 7a158ebce8a0c2801c9c65b7e9b2f98f68b3874e 2023-04-04 10:26:55.950159
+14 add-can-insert-object-function 273193826bca7e0990b458d1ba72f8aa27c0d825 2023-04-04 10:26:56.159325
+15 add-version e821a779d26612899b8c2dfe20245f904a327c4f 2023-04-04 10:26:56.173019
+\.
+
+
+--
+-- Data for Name: objects; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
+--
+
+COPY storage.objects (id, bucket_id, name, owner, created_at, updated_at, last_accessed_at, metadata, version) FROM stdin;
+2693082f-39c6-4750-8ed4-47e11269ae25 Test Bucket 1 25MiB.bin \N 2023-04-26 05:36:24.101743+00 2023-04-26 05:36:26.52988+00 2023-04-26 05:36:24.101743+00 {"eTag": "\\"eeb74bf4aa3e578d69f97e8053b34ede-6\\"", "size": 26214400, "mimetype": "application/macbinary", "cacheControl": "max-age=3600", "lastModified": "2023-04-26T05:36:26.000Z", "contentLength": 26214400, "httpStatusCode": 200} \N
+808135d7-ee5b-4b7b-a5be-cfd007ae157d Test Bucket 1 tulips.png \N 2023-05-22 05:33:26.676802+00 2023-05-22 05:33:27.307468+00 2023-05-22 05:33:26.676802+00 {"eTag": "\\"2e57bf7a8a9bc49b3eacca90c921a4ae\\"", "size": 679233, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2023-05-22T05:33:28.000Z", "contentLength": 679233, "httpStatusCode": 200} \N
+6684d39c-723f-446e-b8f2-195defc2b132 Test Bucket 1 pictures/tulips.png \N 2023-05-22 05:33:41.44723+00 2023-05-22 05:33:41.619794+00 2023-05-22 05:33:41.44723+00 {"eTag": "\\"2e57bf7a8a9bc49b3eacca90c921a4ae\\"", "size": 679233, "mimetype": "image/png", "cacheControl": "max-age=3600", "lastModified": "2023-05-22T05:33:42.000Z", "contentLength": 679233, "httpStatusCode": 200} \N
+\.
+
+
+--
+-- Data for Name: secrets; Type: TABLE DATA; Schema: vault; Owner: supabase_admin
+--
+
+COPY vault.secrets (id, name, description, secret, key_id, nonce, created_at, updated_at) FROM stdin;
+\.
+
+
+--
+-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin
+--
+
+SELECT pg_catalog.setval('auth.refresh_tokens_id_seq', 5, true);
+
+
+--
+-- Name: key_key_id_seq; Type: SEQUENCE SET; Schema: pgsodium; Owner: supabase_admin
+--
+
+SELECT pg_catalog.setval('pgsodium.key_key_id_seq', 1, false);
+
+
+--
+-- Name: test2_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('public.test2_id_seq', 1, false);
+
+
+--
+-- Name: test_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
+--
+
+SELECT pg_catalog.setval('public.test_id_seq', 1, true);
+
+
+--
+-- Name: mfa_amr_claims amr_id_pk; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_amr_claims
+ ADD CONSTRAINT amr_id_pk PRIMARY KEY (id);
+
+
+--
+-- Name: audit_log_entries audit_log_entries_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.audit_log_entries
+ ADD CONSTRAINT audit_log_entries_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: flow_state flow_state_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.flow_state
+ ADD CONSTRAINT flow_state_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.identities
+ ADD CONSTRAINT identities_pkey PRIMARY KEY (provider, id);
+
+
+--
+-- Name: instances instances_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.instances
+ ADD CONSTRAINT instances_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: mfa_amr_claims mfa_amr_claims_session_id_authentication_method_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_amr_claims
+ ADD CONSTRAINT mfa_amr_claims_session_id_authentication_method_pkey UNIQUE (session_id, authentication_method);
+
+
+--
+-- Name: mfa_challenges mfa_challenges_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_challenges
+ ADD CONSTRAINT mfa_challenges_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: mfa_factors mfa_factors_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_factors
+ ADD CONSTRAINT mfa_factors_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: refresh_tokens refresh_tokens_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens
+ ADD CONSTRAINT refresh_tokens_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: refresh_tokens refresh_tokens_token_unique; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens
+ ADD CONSTRAINT refresh_tokens_token_unique UNIQUE (token);
+
+
+--
+-- Name: saml_providers saml_providers_entity_id_key; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.saml_providers
+ ADD CONSTRAINT saml_providers_entity_id_key UNIQUE (entity_id);
+
+
+--
+-- Name: saml_providers saml_providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.saml_providers
+ ADD CONSTRAINT saml_providers_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: saml_relay_states saml_relay_states_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.saml_relay_states
+ ADD CONSTRAINT saml_relay_states_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.schema_migrations
+ ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
+
+
+--
+-- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.sessions
+ ADD CONSTRAINT sessions_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: sso_domains sso_domains_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.sso_domains
+ ADD CONSTRAINT sso_domains_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: sso_providers sso_providers_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.sso_providers
+ ADD CONSTRAINT sso_providers_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: users users_phone_key; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT users_phone_key UNIQUE (phone);
+
+
+--
+-- Name: users users_pkey; Type: CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.users
+ ADD CONSTRAINT users_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: test2 test2_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.test2
+ ADD CONSTRAINT test2_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: test test_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
+--
+
+ALTER TABLE ONLY public.test
+ ADD CONSTRAINT test_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: buckets buckets_pkey; Type: CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.buckets
+ ADD CONSTRAINT buckets_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: migrations migrations_name_key; Type: CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.migrations
+ ADD CONSTRAINT migrations_name_key UNIQUE (name);
+
+
+--
+-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.migrations
+ ADD CONSTRAINT migrations_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: objects objects_pkey; Type: CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.objects
+ ADD CONSTRAINT objects_pkey PRIMARY KEY (id);
+
+
+--
+-- Name: audit_logs_instance_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id);
+
+
+--
+-- Name: confirmation_token_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX confirmation_token_idx ON auth.users USING btree (confirmation_token) WHERE ((confirmation_token)::text !~ '^[0-9 ]*$'::text);
+
+
+--
+-- Name: email_change_token_current_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX email_change_token_current_idx ON auth.users USING btree (email_change_token_current) WHERE ((email_change_token_current)::text !~ '^[0-9 ]*$'::text);
+
+
+--
+-- Name: email_change_token_new_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX email_change_token_new_idx ON auth.users USING btree (email_change_token_new) WHERE ((email_change_token_new)::text !~ '^[0-9 ]*$'::text);
+
+
+--
+-- Name: factor_id_created_at_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX factor_id_created_at_idx ON auth.mfa_factors USING btree (user_id, created_at);
+
+
+--
+-- Name: identities_email_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX identities_email_idx ON auth.identities USING btree (email text_pattern_ops);
+
+
+--
+-- Name: INDEX identities_email_idx; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON INDEX auth.identities_email_idx IS 'Auth: Ensures indexed queries on the email column';
+
+
+--
+-- Name: identities_user_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX identities_user_id_idx ON auth.identities USING btree (user_id);
+
+
+--
+-- Name: idx_auth_code; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX idx_auth_code ON auth.flow_state USING btree (auth_code);
+
+
+--
+-- Name: idx_user_id_auth_method; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX idx_user_id_auth_method ON auth.flow_state USING btree (user_id, authentication_method);
+
+
+--
+-- Name: mfa_factors_user_friendly_name_unique; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX mfa_factors_user_friendly_name_unique ON auth.mfa_factors USING btree (friendly_name, user_id) WHERE (TRIM(BOTH FROM friendly_name) <> ''::text);
+
+
+--
+-- Name: reauthentication_token_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX reauthentication_token_idx ON auth.users USING btree (reauthentication_token) WHERE ((reauthentication_token)::text !~ '^[0-9 ]*$'::text);
+
+
+--
+-- Name: recovery_token_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX recovery_token_idx ON auth.users USING btree (recovery_token) WHERE ((recovery_token)::text !~ '^[0-9 ]*$'::text);
+
+
+--
+-- Name: refresh_tokens_instance_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id);
+
+
+--
+-- Name: refresh_tokens_instance_id_user_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id);
+
+
+--
+-- Name: refresh_tokens_parent_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX refresh_tokens_parent_idx ON auth.refresh_tokens USING btree (parent);
+
+
+--
+-- Name: refresh_tokens_session_id_revoked_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX refresh_tokens_session_id_revoked_idx ON auth.refresh_tokens USING btree (session_id, revoked);
+
+
+--
+-- Name: saml_providers_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX saml_providers_sso_provider_id_idx ON auth.saml_providers USING btree (sso_provider_id);
+
+
+--
+-- Name: saml_relay_states_for_email_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX saml_relay_states_for_email_idx ON auth.saml_relay_states USING btree (for_email);
+
+
+--
+-- Name: saml_relay_states_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX saml_relay_states_sso_provider_id_idx ON auth.saml_relay_states USING btree (sso_provider_id);
+
+
+--
+-- Name: sessions_user_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX sessions_user_id_idx ON auth.sessions USING btree (user_id);
+
+
+--
+-- Name: sso_domains_domain_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX sso_domains_domain_idx ON auth.sso_domains USING btree (lower(domain));
+
+
+--
+-- Name: sso_domains_sso_provider_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX sso_domains_sso_provider_id_idx ON auth.sso_domains USING btree (sso_provider_id);
+
+
+--
+-- Name: sso_providers_resource_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX sso_providers_resource_id_idx ON auth.sso_providers USING btree (lower(resource_id));
+
+
+--
+-- Name: user_id_created_at_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX user_id_created_at_idx ON auth.sessions USING btree (user_id, created_at);
+
+
+--
+-- Name: users_email_partial_key; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE UNIQUE INDEX users_email_partial_key ON auth.users USING btree (email) WHERE (is_sso_user = false);
+
+
+--
+-- Name: INDEX users_email_partial_key; Type: COMMENT; Schema: auth; Owner: supabase_auth_admin
+--
+
+COMMENT ON INDEX auth.users_email_partial_key IS 'Auth: A partial unique index that applies only when is_sso_user is false';
+
+
+--
+-- Name: users_instance_id_email_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, lower((email)::text));
+
+
+--
+-- Name: users_instance_id_idx; Type: INDEX; Schema: auth; Owner: supabase_auth_admin
+--
+
+CREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id);
+
+
+--
+-- Name: bname; Type: INDEX; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE UNIQUE INDEX bname ON storage.buckets USING btree (name);
+
+
+--
+-- Name: bucketid_objname; Type: INDEX; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE UNIQUE INDEX bucketid_objname ON storage.objects USING btree (bucket_id, name);
+
+
+--
+-- Name: name_prefix_search; Type: INDEX; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE INDEX name_prefix_search ON storage.objects USING btree (name text_pattern_ops);
+
+
+--
+-- Name: objects update_objects_updated_at; Type: TRIGGER; Schema: storage; Owner: supabase_storage_admin
+--
+
+CREATE TRIGGER update_objects_updated_at BEFORE UPDATE ON storage.objects FOR EACH ROW EXECUTE FUNCTION storage.update_updated_at_column();
+
+
+--
+-- Name: identities identities_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.identities
+ ADD CONSTRAINT identities_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
+
+
+--
+-- Name: mfa_amr_claims mfa_amr_claims_session_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_amr_claims
+ ADD CONSTRAINT mfa_amr_claims_session_id_fkey FOREIGN KEY (session_id) REFERENCES auth.sessions(id) ON DELETE CASCADE;
+
+
+--
+-- Name: mfa_challenges mfa_challenges_auth_factor_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_challenges
+ ADD CONSTRAINT mfa_challenges_auth_factor_id_fkey FOREIGN KEY (factor_id) REFERENCES auth.mfa_factors(id) ON DELETE CASCADE;
+
+
+--
+-- Name: mfa_factors mfa_factors_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.mfa_factors
+ ADD CONSTRAINT mfa_factors_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
+
+
+--
+-- Name: refresh_tokens refresh_tokens_session_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.refresh_tokens
+ ADD CONSTRAINT refresh_tokens_session_id_fkey FOREIGN KEY (session_id) REFERENCES auth.sessions(id) ON DELETE CASCADE;
+
+
+--
+-- Name: saml_providers saml_providers_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.saml_providers
+ ADD CONSTRAINT saml_providers_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE;
+
+
+--
+-- Name: saml_relay_states saml_relay_states_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.saml_relay_states
+ ADD CONSTRAINT saml_relay_states_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE;
+
+
+--
+-- Name: sessions sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.sessions
+ ADD CONSTRAINT sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
+
+
+--
+-- Name: sso_domains sso_domains_sso_provider_id_fkey; Type: FK CONSTRAINT; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER TABLE ONLY auth.sso_domains
+ ADD CONSTRAINT sso_domains_sso_provider_id_fkey FOREIGN KEY (sso_provider_id) REFERENCES auth.sso_providers(id) ON DELETE CASCADE;
+
+
+--
+-- Name: buckets buckets_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.buckets
+ ADD CONSTRAINT buckets_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);
+
+
+--
+-- Name: objects objects_bucketId_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.objects
+ ADD CONSTRAINT "objects_bucketId_fkey" FOREIGN KEY (bucket_id) REFERENCES storage.buckets(id);
+
+
+--
+-- Name: objects objects_owner_fkey; Type: FK CONSTRAINT; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE ONLY storage.objects
+ ADD CONSTRAINT objects_owner_fkey FOREIGN KEY (owner) REFERENCES auth.users(id);
+
+
+--
+-- Name: test; Type: ROW SECURITY; Schema: public; Owner: postgres
+--
+
+ALTER TABLE public.test ENABLE ROW LEVEL SECURITY;
+
+--
+-- Name: test2; Type: ROW SECURITY; Schema: public; Owner: postgres
+--
+
+ALTER TABLE public.test2 ENABLE ROW LEVEL SECURITY;
+
+--
+-- Name: buckets; Type: ROW SECURITY; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE storage.buckets ENABLE ROW LEVEL SECURITY;
+
+--
+-- Name: migrations; Type: ROW SECURITY; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE storage.migrations ENABLE ROW LEVEL SECURITY;
+
+--
+-- Name: objects; Type: ROW SECURITY; Schema: storage; Owner: supabase_storage_admin
+--
+
+ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY;
+
+--
+-- Name: supabase_realtime; Type: PUBLICATION; Schema: -; Owner: postgres
+--
+
+CREATE PUBLICATION supabase_realtime WITH (publish = 'insert, update, delete, truncate');
+
+
+ALTER PUBLICATION supabase_realtime OWNER TO postgres;
+
+--
+-- Name: SCHEMA auth; Type: ACL; Schema: -; Owner: supabase_admin
+--
+
+GRANT USAGE ON SCHEMA auth TO anon;
+GRANT USAGE ON SCHEMA auth TO authenticated;
+GRANT USAGE ON SCHEMA auth TO service_role;
+GRANT ALL ON SCHEMA auth TO supabase_auth_admin;
+GRANT ALL ON SCHEMA auth TO dashboard_user;
+GRANT ALL ON SCHEMA auth TO postgres;
+
+
+--
+-- Name: SCHEMA extensions; Type: ACL; Schema: -; Owner: postgres
+--
+
+GRANT USAGE ON SCHEMA extensions TO anon;
+GRANT USAGE ON SCHEMA extensions TO authenticated;
+GRANT USAGE ON SCHEMA extensions TO service_role;
+GRANT ALL ON SCHEMA extensions TO dashboard_user;
+
+
+--
+-- Name: SCHEMA graphql_public; Type: ACL; Schema: -; Owner: supabase_admin
+--
+
+GRANT USAGE ON SCHEMA graphql_public TO postgres;
+GRANT USAGE ON SCHEMA graphql_public TO anon;
+GRANT USAGE ON SCHEMA graphql_public TO authenticated;
+GRANT USAGE ON SCHEMA graphql_public TO service_role;
+
+
+--
+-- Name: SCHEMA pgsodium_masks; Type: ACL; Schema: -; Owner: supabase_admin
+--
+
+REVOKE ALL ON SCHEMA pgsodium_masks FROM supabase_admin;
+GRANT ALL ON SCHEMA pgsodium_masks TO postgres;
+
+
+--
+-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE USAGE ON SCHEMA public FROM PUBLIC;
+GRANT USAGE ON SCHEMA public TO anon;
+GRANT USAGE ON SCHEMA public TO authenticated;
+GRANT USAGE ON SCHEMA public TO service_role;
+
+
+--
+-- Name: SCHEMA realtime; Type: ACL; Schema: -; Owner: supabase_admin
+--
+
+GRANT USAGE ON SCHEMA realtime TO postgres;
+
+
+--
+-- Name: SCHEMA storage; Type: ACL; Schema: -; Owner: supabase_admin
+--
+
+GRANT ALL ON SCHEMA storage TO postgres;
+GRANT USAGE ON SCHEMA storage TO anon;
+GRANT USAGE ON SCHEMA storage TO authenticated;
+GRANT USAGE ON SCHEMA storage TO service_role;
+GRANT ALL ON SCHEMA storage TO supabase_storage_admin;
+GRANT ALL ON SCHEMA storage TO dashboard_user;
+
+
+--
+-- Name: FUNCTION email(); Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON FUNCTION auth.email() TO dashboard_user;
+GRANT ALL ON FUNCTION auth.email() TO postgres;
+
+
+--
+-- Name: FUNCTION jwt(); Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON FUNCTION auth.jwt() TO postgres;
+GRANT ALL ON FUNCTION auth.jwt() TO dashboard_user;
+
+
+--
+-- Name: FUNCTION role(); Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON FUNCTION auth.role() TO dashboard_user;
+GRANT ALL ON FUNCTION auth.role() TO postgres;
+
+
+--
+-- Name: FUNCTION uid(); Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON FUNCTION auth.uid() TO dashboard_user;
+GRANT ALL ON FUNCTION auth.uid() TO postgres;
+
+
+--
+-- Name: FUNCTION algorithm_sign(signables text, secret text, algorithm text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.algorithm_sign(signables text, secret text, algorithm text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.algorithm_sign(signables text, secret text, algorithm text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION armor(bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.armor(bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.armor(bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION armor(bytea, text[], text[]); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.armor(bytea, text[], text[]) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.armor(bytea, text[], text[]) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION crypt(text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.crypt(text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.crypt(text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION dearmor(text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.dearmor(text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.dearmor(text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION decrypt(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.decrypt(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.decrypt(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION decrypt_iv(bytea, bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.decrypt_iv(bytea, bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.decrypt_iv(bytea, bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION digest(bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.digest(bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.digest(bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION digest(text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.digest(text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.digest(text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION encrypt(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.encrypt(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.encrypt(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION encrypt_iv(bytea, bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.encrypt_iv(bytea, bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.encrypt_iv(bytea, bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION gen_random_bytes(integer); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.gen_random_bytes(integer) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.gen_random_bytes(integer) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION gen_random_uuid(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.gen_random_uuid() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.gen_random_uuid() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION gen_salt(text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.gen_salt(text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.gen_salt(text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION gen_salt(text, integer); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.gen_salt(text, integer) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.gen_salt(text, integer) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION grant_pg_cron_access(); Type: ACL; Schema: extensions; Owner: postgres
+--
+
+REVOKE ALL ON FUNCTION extensions.grant_pg_cron_access() FROM postgres;
+GRANT ALL ON FUNCTION extensions.grant_pg_cron_access() TO postgres WITH GRANT OPTION;
+GRANT ALL ON FUNCTION extensions.grant_pg_cron_access() TO dashboard_user;
+
+
+--
+-- Name: FUNCTION grant_pg_graphql_access(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.grant_pg_graphql_access() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION grant_pg_net_access(); Type: ACL; Schema: extensions; Owner: postgres
+--
+
+REVOKE ALL ON FUNCTION extensions.grant_pg_net_access() FROM postgres;
+GRANT ALL ON FUNCTION extensions.grant_pg_net_access() TO postgres WITH GRANT OPTION;
+GRANT ALL ON FUNCTION extensions.grant_pg_net_access() TO dashboard_user;
+
+
+--
+-- Name: FUNCTION hmac(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.hmac(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.hmac(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION hmac(text, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.hmac(text, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.hmac(text, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pg_stat_statements(showtext boolean, OUT userid oid, OUT dbid oid, OUT toplevel boolean, OUT queryid bigint, OUT query text, OUT plans bigint, OUT total_plan_time double precision, OUT min_plan_time double precision, OUT max_plan_time double precision, OUT mean_plan_time double precision, OUT stddev_plan_time double precision, OUT calls bigint, OUT total_exec_time double precision, OUT min_exec_time double precision, OUT max_exec_time double precision, OUT mean_exec_time double precision, OUT stddev_exec_time double precision, OUT rows bigint, OUT shared_blks_hit bigint, OUT shared_blks_read bigint, OUT shared_blks_dirtied bigint, OUT shared_blks_written bigint, OUT local_blks_hit bigint, OUT local_blks_read bigint, OUT local_blks_dirtied bigint, OUT local_blks_written bigint, OUT temp_blks_read bigint, OUT temp_blks_written bigint, OUT blk_read_time double precision, OUT blk_write_time double precision, OUT temp_blk_read_time double precision, OUT temp_blk_write_time double precision, OUT wal_records bigint, OUT wal_fpi bigint, OUT wal_bytes numeric, OUT jit_functions bigint, OUT jit_generation_time double precision, OUT jit_inlining_count bigint, OUT jit_inlining_time double precision, OUT jit_optimization_count bigint, OUT jit_optimization_time double precision, OUT jit_emission_count bigint, OUT jit_emission_time double precision); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pg_stat_statements(showtext boolean, OUT userid oid, OUT dbid oid, OUT toplevel boolean, OUT queryid bigint, OUT query text, OUT plans bigint, OUT total_plan_time double precision, OUT min_plan_time double precision, OUT max_plan_time double precision, OUT mean_plan_time double precision, OUT stddev_plan_time double precision, OUT calls bigint, OUT total_exec_time double precision, OUT min_exec_time double precision, OUT max_exec_time double precision, OUT mean_exec_time double precision, OUT stddev_exec_time double precision, OUT rows bigint, OUT shared_blks_hit bigint, OUT shared_blks_read bigint, OUT shared_blks_dirtied bigint, OUT shared_blks_written bigint, OUT local_blks_hit bigint, OUT local_blks_read bigint, OUT local_blks_dirtied bigint, OUT local_blks_written bigint, OUT temp_blks_read bigint, OUT temp_blks_written bigint, OUT blk_read_time double precision, OUT blk_write_time double precision, OUT temp_blk_read_time double precision, OUT temp_blk_write_time double precision, OUT wal_records bigint, OUT wal_fpi bigint, OUT wal_bytes numeric, OUT jit_functions bigint, OUT jit_generation_time double precision, OUT jit_inlining_count bigint, OUT jit_inlining_time double precision, OUT jit_optimization_count bigint, OUT jit_optimization_time double precision, OUT jit_emission_count bigint, OUT jit_emission_time double precision) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pg_stat_statements(showtext boolean, OUT userid oid, OUT dbid oid, OUT toplevel boolean, OUT queryid bigint, OUT query text, OUT plans bigint, OUT total_plan_time double precision, OUT min_plan_time double precision, OUT max_plan_time double precision, OUT mean_plan_time double precision, OUT stddev_plan_time double precision, OUT calls bigint, OUT total_exec_time double precision, OUT min_exec_time double precision, OUT max_exec_time double precision, OUT mean_exec_time double precision, OUT stddev_exec_time double precision, OUT rows bigint, OUT shared_blks_hit bigint, OUT shared_blks_read bigint, OUT shared_blks_dirtied bigint, OUT shared_blks_written bigint, OUT local_blks_hit bigint, OUT local_blks_read bigint, OUT local_blks_dirtied bigint, OUT local_blks_written bigint, OUT temp_blks_read bigint, OUT temp_blks_written bigint, OUT blk_read_time double precision, OUT blk_write_time double precision, OUT temp_blk_read_time double precision, OUT temp_blk_write_time double precision, OUT wal_records bigint, OUT wal_fpi bigint, OUT wal_bytes numeric, OUT jit_functions bigint, OUT jit_generation_time double precision, OUT jit_inlining_count bigint, OUT jit_inlining_time double precision, OUT jit_optimization_count bigint, OUT jit_optimization_time double precision, OUT jit_emission_count bigint, OUT jit_emission_time double precision) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pg_stat_statements_info(OUT dealloc bigint, OUT stats_reset timestamp with time zone); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pg_stat_statements_info(OUT dealloc bigint, OUT stats_reset timestamp with time zone) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pg_stat_statements_info(OUT dealloc bigint, OUT stats_reset timestamp with time zone) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pg_stat_statements_reset(userid oid, dbid oid, queryid bigint); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pg_stat_statements_reset(userid oid, dbid oid, queryid bigint) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pg_stat_statements_reset(userid oid, dbid oid, queryid bigint) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_armor_headers(text, OUT key text, OUT value text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_armor_headers(text, OUT key text, OUT value text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_armor_headers(text, OUT key text, OUT value text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_key_id(bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_key_id(bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_key_id(bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt(bytea, bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt(bytea, bytea, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt(bytea, bytea, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt_bytea(bytea, bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_decrypt_bytea(bytea, bytea, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_decrypt_bytea(bytea, bytea, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_encrypt(text, bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt(text, bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt(text, bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_encrypt(text, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt(text, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt(text, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_encrypt_bytea(bytea, bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt_bytea(bytea, bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt_bytea(bytea, bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_pub_encrypt_bytea(bytea, bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt_bytea(bytea, bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_pub_encrypt_bytea(bytea, bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_decrypt(bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt(bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt(bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_decrypt(bytea, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt(bytea, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt(bytea, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_decrypt_bytea(bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt_bytea(bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt_bytea(bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_decrypt_bytea(bytea, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt_bytea(bytea, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_decrypt_bytea(bytea, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_encrypt(text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt(text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt(text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_encrypt(text, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt(text, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt(text, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_encrypt_bytea(bytea, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt_bytea(bytea, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt_bytea(bytea, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgp_sym_encrypt_bytea(bytea, text, text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt_bytea(bytea, text, text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.pgp_sym_encrypt_bytea(bytea, text, text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgrst_ddl_watch(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgrst_ddl_watch() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION pgrst_drop_watch(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.pgrst_drop_watch() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION set_graphql_placeholder(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.set_graphql_placeholder() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION sign(payload json, secret text, algorithm text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.sign(payload json, secret text, algorithm text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.sign(payload json, secret text, algorithm text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION try_cast_double(inp text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.try_cast_double(inp text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.try_cast_double(inp text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION url_decode(data text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.url_decode(data text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.url_decode(data text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION url_encode(data bytea); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.url_encode(data bytea) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.url_encode(data bytea) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_generate_v1(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_generate_v1() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_generate_v1() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_generate_v1mc(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_generate_v1mc() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_generate_v1mc() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_generate_v3(namespace uuid, name text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_generate_v3(namespace uuid, name text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_generate_v3(namespace uuid, name text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_generate_v4(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_generate_v4() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_generate_v4() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_generate_v5(namespace uuid, name text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_generate_v5(namespace uuid, name text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_generate_v5(namespace uuid, name text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_nil(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_nil() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_nil() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_ns_dns(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_ns_dns() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_ns_dns() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_ns_oid(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_ns_oid() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_ns_oid() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_ns_url(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_ns_url() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_ns_url() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION uuid_ns_x500(); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.uuid_ns_x500() TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.uuid_ns_x500() TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION verify(token text, secret text, algorithm text); Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION extensions.verify(token text, secret text, algorithm text) TO dashboard_user;
+GRANT ALL ON FUNCTION extensions.verify(token text, secret text, algorithm text) TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: FUNCTION comment_directive(comment_ text); Type: ACL; Schema: graphql; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION graphql.comment_directive(comment_ text) TO postgres;
+GRANT ALL ON FUNCTION graphql.comment_directive(comment_ text) TO anon;
+GRANT ALL ON FUNCTION graphql.comment_directive(comment_ text) TO authenticated;
+GRANT ALL ON FUNCTION graphql.comment_directive(comment_ text) TO service_role;
+
+
+--
+-- Name: FUNCTION exception(message text); Type: ACL; Schema: graphql; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION graphql.exception(message text) TO postgres;
+GRANT ALL ON FUNCTION graphql.exception(message text) TO anon;
+GRANT ALL ON FUNCTION graphql.exception(message text) TO authenticated;
+GRANT ALL ON FUNCTION graphql.exception(message text) TO service_role;
+
+
+--
+-- Name: FUNCTION get_schema_version(); Type: ACL; Schema: graphql; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION graphql.get_schema_version() TO postgres;
+GRANT ALL ON FUNCTION graphql.get_schema_version() TO anon;
+GRANT ALL ON FUNCTION graphql.get_schema_version() TO authenticated;
+GRANT ALL ON FUNCTION graphql.get_schema_version() TO service_role;
+
+
+--
+-- Name: FUNCTION increment_schema_version(); Type: ACL; Schema: graphql; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION graphql.increment_schema_version() TO postgres;
+GRANT ALL ON FUNCTION graphql.increment_schema_version() TO anon;
+GRANT ALL ON FUNCTION graphql.increment_schema_version() TO authenticated;
+GRANT ALL ON FUNCTION graphql.increment_schema_version() TO service_role;
+
+
+--
+-- Name: FUNCTION graphql("operationName" text, query text, variables jsonb, extensions jsonb); Type: ACL; Schema: graphql_public; Owner: supabase_admin
+--
+
+GRANT ALL ON FUNCTION graphql_public.graphql("operationName" text, query text, variables jsonb, extensions jsonb) TO postgres;
+GRANT ALL ON FUNCTION graphql_public.graphql("operationName" text, query text, variables jsonb, extensions jsonb) TO anon;
+GRANT ALL ON FUNCTION graphql_public.graphql("operationName" text, query text, variables jsonb, extensions jsonb) TO authenticated;
+GRANT ALL ON FUNCTION graphql_public.graphql("operationName" text, query text, variables jsonb, extensions jsonb) TO service_role;
+
+
+--
+-- Name: FUNCTION get_auth(p_usename text); Type: ACL; Schema: pgbouncer; Owner: postgres
+--
+
+REVOKE ALL ON FUNCTION pgbouncer.get_auth(p_usename text) FROM PUBLIC;
+GRANT ALL ON FUNCTION pgbouncer.get_auth(p_usename text) TO pgbouncer;
+
+
+--
+-- Name: TABLE key; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON TABLE pgsodium.key FROM supabase_admin;
+GRANT ALL ON TABLE pgsodium.key TO postgres;
+
+
+--
+-- Name: TABLE valid_key; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON TABLE pgsodium.valid_key FROM supabase_admin;
+REVOKE SELECT ON TABLE pgsodium.valid_key FROM pgsodium_keyiduser;
+GRANT ALL ON TABLE pgsodium.valid_key TO postgres;
+GRANT ALL ON TABLE pgsodium.valid_key TO pgsodium_keyiduser;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_decrypt(ciphertext bytea, additional bytea, key bytea, nonce bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(ciphertext bytea, additional bytea, key bytea, nonce bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(ciphertext bytea, additional bytea, key bytea, nonce bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_decrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea); Type: ACL; Schema: pgsodium; Owner: pgsodium_keymaker
+--
+
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea) TO service_role;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_decrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_decrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_encrypt(message bytea, additional bytea, key bytea, nonce bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key bytea, nonce bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key bytea, nonce bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_encrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea); Type: ACL; Schema: pgsodium; Owner: pgsodium_keymaker
+--
+
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_uuid uuid, nonce bytea) TO service_role;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_encrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_encrypt(message bytea, additional bytea, key_id bigint, context bytea, nonce bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_keygen() TO service_role;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_det_noncegen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_det_noncegen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_det_noncegen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_decrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_encrypt(message bytea, additional bytea, nonce bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_aead_ietf_noncegen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_aead_ietf_noncegen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_aead_ietf_noncegen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth(message bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth(message bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth(message bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth(message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth(message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth(message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha256(message bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha256(message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256(message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha256_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha256_verify(hash bytea, message bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha256_verify(hash bytea, message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha256_verify(hash bytea, message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha512(message bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha512(message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512(message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha512_verify(hash bytea, message bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_hmacsha512_verify(hash bytea, message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_hmacsha512_verify(hash bytea, message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_verify(mac bytea, message bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_auth_verify(mac bytea, message bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_auth_verify(mac bytea, message bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_box(message bytea, nonce bytea, public bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_box(message bytea, nonce bytea, public bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_box(message bytea, nonce bytea, public bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_box_new_keypair(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_box_new_keypair() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_box_new_keypair() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_box_noncegen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_box_noncegen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_box_noncegen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_box_open(ciphertext bytea, nonce bytea, public bytea, secret bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_box_open(ciphertext bytea, nonce bytea, public bytea, secret bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_box_open(ciphertext bytea, nonce bytea, public bytea, secret bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_box_seed_new_keypair(seed bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_box_seed_new_keypair(seed bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_box_seed_new_keypair(seed bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_generichash(message bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_generichash(message bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_generichash(message bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_generichash_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_generichash_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_generichash_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_kdf_derive_from_key(subkey_size bigint, subkey_id bigint, context bytea, primary_key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_kdf_derive_from_key(subkey_size bigint, subkey_id bigint, context bytea, primary_key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_kdf_derive_from_key(subkey_size bigint, subkey_id bigint, context bytea, primary_key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_kdf_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_kdf_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_kdf_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_kx_new_keypair(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_kx_new_keypair() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_kx_new_keypair() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_kx_new_seed(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_kx_new_seed() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_kx_new_seed() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_kx_seed_new_keypair(seed bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_kx_seed_new_keypair(seed bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_kx_seed_new_keypair(seed bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox(message bytea, nonce bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox(message bytea, nonce bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox(message bytea, nonce bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox_noncegen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_noncegen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox_noncegen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox_open(ciphertext bytea, nonce bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_open(ciphertext bytea, nonce bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox_open(ciphertext bytea, nonce bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_secretbox_open(message bytea, nonce bytea, key_id bigint, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_secretbox_open(message bytea, nonce bytea, key_id bigint, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_secretbox_open(message bytea, nonce bytea, key_id bigint, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_shorthash(message bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_shorthash(message bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_shorthash(message bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_shorthash_keygen(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_shorthash_keygen() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_shorthash_keygen() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_final_create(state bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_final_create(state bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_final_create(state bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_final_verify(state bytea, signature bytea, key bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_final_verify(state bytea, signature bytea, key bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_final_verify(state bytea, signature bytea, key bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_init(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_init() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_init() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_new_keypair(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_new_keypair() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_new_keypair() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_update(state bytea, message bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update(state bytea, message bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_update(state bytea, message bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_update_agg1(state bytea, message bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update_agg1(state bytea, message bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_update_agg1(state bytea, message bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_sign_update_agg2(cur_state bytea, initial_state bytea, message bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_sign_update_agg2(cur_state bytea, initial_state bytea, message bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_sign_update_agg2(cur_state bytea, initial_state bytea, message bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_new_keypair(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_new_keypair() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_new_keypair() TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_sign_after(state bytea, sender_sk bytea, ciphertext bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_after(state bytea, sender_sk bytea, ciphertext bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_after(state bytea, sender_sk bytea, ciphertext bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_sign_before(sender bytea, recipient bytea, sender_sk bytea, recipient_pk bytea, additional bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_before(sender bytea, recipient bytea, sender_sk bytea, recipient_pk bytea, additional bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_sign_before(sender bytea, recipient bytea, sender_sk bytea, recipient_pk bytea, additional bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_verify_after(state bytea, signature bytea, sender_pk bytea, ciphertext bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_after(state bytea, signature bytea, sender_pk bytea, ciphertext bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_after(state bytea, signature bytea, sender_pk bytea, ciphertext bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_verify_before(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, recipient_sk bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_before(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, recipient_sk bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_before(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, recipient_sk bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION crypto_signcrypt_verify_public(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, ciphertext bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_public(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, ciphertext bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.crypto_signcrypt_verify_public(signature bytea, sender bytea, recipient bytea, additional bytea, sender_pk bytea, ciphertext bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION derive_key(key_id bigint, key_len integer, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.derive_key(key_id bigint, key_len integer, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.derive_key(key_id bigint, key_len integer, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION pgsodium_derive(key_id bigint, key_len integer, context bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.pgsodium_derive(key_id bigint, key_len integer, context bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.pgsodium_derive(key_id bigint, key_len integer, context bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION randombytes_buf(size integer); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.randombytes_buf(size integer) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.randombytes_buf(size integer) TO postgres;
+
+
+--
+-- Name: FUNCTION randombytes_buf_deterministic(size integer, seed bytea); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.randombytes_buf_deterministic(size integer, seed bytea) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.randombytes_buf_deterministic(size integer, seed bytea) TO postgres;
+
+
+--
+-- Name: FUNCTION randombytes_new_seed(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.randombytes_new_seed() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.randombytes_new_seed() TO postgres;
+
+
+--
+-- Name: FUNCTION randombytes_random(); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.randombytes_random() FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.randombytes_random() TO postgres;
+
+
+--
+-- Name: FUNCTION randombytes_uniform(upper_bound integer); Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON FUNCTION pgsodium.randombytes_uniform(upper_bound integer) FROM supabase_admin;
+GRANT ALL ON FUNCTION pgsodium.randombytes_uniform(upper_bound integer) TO postgres;
+
+
+--
+-- Name: FUNCTION can_insert_object(bucketid text, name text, owner uuid, metadata jsonb); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.can_insert_object(bucketid text, name text, owner uuid, metadata jsonb) TO postgres;
+
+
+--
+-- Name: FUNCTION extension(name text); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.extension(name text) TO anon;
+GRANT ALL ON FUNCTION storage.extension(name text) TO authenticated;
+GRANT ALL ON FUNCTION storage.extension(name text) TO service_role;
+GRANT ALL ON FUNCTION storage.extension(name text) TO dashboard_user;
+GRANT ALL ON FUNCTION storage.extension(name text) TO postgres;
+
+
+--
+-- Name: FUNCTION filename(name text); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.filename(name text) TO anon;
+GRANT ALL ON FUNCTION storage.filename(name text) TO authenticated;
+GRANT ALL ON FUNCTION storage.filename(name text) TO service_role;
+GRANT ALL ON FUNCTION storage.filename(name text) TO dashboard_user;
+GRANT ALL ON FUNCTION storage.filename(name text) TO postgres;
+
+
+--
+-- Name: FUNCTION foldername(name text); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.foldername(name text) TO anon;
+GRANT ALL ON FUNCTION storage.foldername(name text) TO authenticated;
+GRANT ALL ON FUNCTION storage.foldername(name text) TO service_role;
+GRANT ALL ON FUNCTION storage.foldername(name text) TO dashboard_user;
+GRANT ALL ON FUNCTION storage.foldername(name text) TO postgres;
+
+
+--
+-- Name: FUNCTION get_size_by_bucket(); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.get_size_by_bucket() TO postgres;
+
+
+--
+-- Name: FUNCTION search(prefix text, bucketname text, limits integer, levels integer, offsets integer, search text, sortcolumn text, sortorder text); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.search(prefix text, bucketname text, limits integer, levels integer, offsets integer, search text, sortcolumn text, sortorder text) TO postgres;
+
+
+--
+-- Name: FUNCTION update_updated_at_column(); Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON FUNCTION storage.update_updated_at_column() TO postgres;
+
+
+--
+-- Name: TABLE audit_log_entries; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.audit_log_entries TO dashboard_user;
+GRANT ALL ON TABLE auth.audit_log_entries TO postgres;
+
+
+--
+-- Name: TABLE flow_state; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.flow_state TO postgres;
+GRANT ALL ON TABLE auth.flow_state TO dashboard_user;
+
+
+--
+-- Name: TABLE identities; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.identities TO postgres;
+GRANT ALL ON TABLE auth.identities TO dashboard_user;
+
+
+--
+-- Name: TABLE instances; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.instances TO dashboard_user;
+GRANT ALL ON TABLE auth.instances TO postgres;
+
+
+--
+-- Name: TABLE mfa_amr_claims; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.mfa_amr_claims TO postgres;
+GRANT ALL ON TABLE auth.mfa_amr_claims TO dashboard_user;
+
+
+--
+-- Name: TABLE mfa_challenges; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.mfa_challenges TO postgres;
+GRANT ALL ON TABLE auth.mfa_challenges TO dashboard_user;
+
+
+--
+-- Name: TABLE mfa_factors; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.mfa_factors TO postgres;
+GRANT ALL ON TABLE auth.mfa_factors TO dashboard_user;
+
+
+--
+-- Name: TABLE refresh_tokens; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.refresh_tokens TO dashboard_user;
+GRANT ALL ON TABLE auth.refresh_tokens TO postgres;
+
+
+--
+-- Name: SEQUENCE refresh_tokens_id_seq; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON SEQUENCE auth.refresh_tokens_id_seq TO dashboard_user;
+GRANT ALL ON SEQUENCE auth.refresh_tokens_id_seq TO postgres;
+
+
+--
+-- Name: TABLE saml_providers; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.saml_providers TO postgres;
+GRANT ALL ON TABLE auth.saml_providers TO dashboard_user;
+
+
+--
+-- Name: TABLE saml_relay_states; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.saml_relay_states TO postgres;
+GRANT ALL ON TABLE auth.saml_relay_states TO dashboard_user;
+
+
+--
+-- Name: TABLE schema_migrations; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.schema_migrations TO dashboard_user;
+GRANT ALL ON TABLE auth.schema_migrations TO postgres;
+
+
+--
+-- Name: TABLE sessions; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.sessions TO postgres;
+GRANT ALL ON TABLE auth.sessions TO dashboard_user;
+
+
+--
+-- Name: TABLE sso_domains; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.sso_domains TO postgres;
+GRANT ALL ON TABLE auth.sso_domains TO dashboard_user;
+
+
+--
+-- Name: TABLE sso_providers; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.sso_providers TO postgres;
+GRANT ALL ON TABLE auth.sso_providers TO dashboard_user;
+
+
+--
+-- Name: TABLE users; Type: ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+GRANT ALL ON TABLE auth.users TO dashboard_user;
+GRANT ALL ON TABLE auth.users TO postgres;
+
+
+--
+-- Name: TABLE pg_stat_statements; Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE extensions.pg_stat_statements TO dashboard_user;
+GRANT ALL ON TABLE extensions.pg_stat_statements TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: TABLE pg_stat_statements_info; Type: ACL; Schema: extensions; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE extensions.pg_stat_statements_info TO dashboard_user;
+GRANT ALL ON TABLE extensions.pg_stat_statements_info TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: SEQUENCE seq_schema_version; Type: ACL; Schema: graphql; Owner: supabase_admin
+--
+
+GRANT ALL ON SEQUENCE graphql.seq_schema_version TO postgres;
+GRANT ALL ON SEQUENCE graphql.seq_schema_version TO anon;
+GRANT ALL ON SEQUENCE graphql.seq_schema_version TO authenticated;
+GRANT ALL ON SEQUENCE graphql.seq_schema_version TO service_role;
+
+
+--
+-- Name: TABLE decrypted_key; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE pgsodium.decrypted_key TO pgsodium_keyholder;
+
+
+--
+-- Name: SEQUENCE key_key_id_seq; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+REVOKE ALL ON SEQUENCE pgsodium.key_key_id_seq FROM supabase_admin;
+GRANT ALL ON SEQUENCE pgsodium.key_key_id_seq TO postgres;
+GRANT ALL ON SEQUENCE pgsodium.key_key_id_seq TO pgsodium_keyiduser;
+
+
+--
+-- Name: TABLE masking_rule; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE pgsodium.masking_rule TO pgsodium_keyholder;
+
+
+--
+-- Name: TABLE mask_columns; Type: ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE pgsodium.mask_columns TO pgsodium_keyholder;
+
+
+--
+-- Name: TABLE test; Type: ACL; Schema: public; Owner: postgres
+--
+
+GRANT ALL ON TABLE public.test TO anon;
+GRANT ALL ON TABLE public.test TO authenticated;
+GRANT ALL ON TABLE public.test TO service_role;
+
+
+--
+-- Name: TABLE test2; Type: ACL; Schema: public; Owner: postgres
+--
+
+GRANT ALL ON TABLE public.test2 TO anon;
+GRANT ALL ON TABLE public.test2 TO authenticated;
+GRANT ALL ON TABLE public.test2 TO service_role;
+
+
+--
+-- Name: SEQUENCE test2_id_seq; Type: ACL; Schema: public; Owner: postgres
+--
+
+GRANT ALL ON SEQUENCE public.test2_id_seq TO anon;
+GRANT ALL ON SEQUENCE public.test2_id_seq TO authenticated;
+GRANT ALL ON SEQUENCE public.test2_id_seq TO service_role;
+
+
+--
+-- Name: SEQUENCE test_id_seq; Type: ACL; Schema: public; Owner: postgres
+--
+
+GRANT ALL ON SEQUENCE public.test_id_seq TO anon;
+GRANT ALL ON SEQUENCE public.test_id_seq TO authenticated;
+GRANT ALL ON SEQUENCE public.test_id_seq TO service_role;
+
+
+--
+-- Name: TABLE buckets; Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON TABLE storage.buckets TO anon;
+GRANT ALL ON TABLE storage.buckets TO authenticated;
+GRANT ALL ON TABLE storage.buckets TO service_role;
+GRANT ALL ON TABLE storage.buckets TO postgres;
+
+
+--
+-- Name: TABLE migrations; Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON TABLE storage.migrations TO anon;
+GRANT ALL ON TABLE storage.migrations TO authenticated;
+GRANT ALL ON TABLE storage.migrations TO service_role;
+GRANT ALL ON TABLE storage.migrations TO postgres;
+
+
+--
+-- Name: TABLE objects; Type: ACL; Schema: storage; Owner: supabase_storage_admin
+--
+
+GRANT ALL ON TABLE storage.objects TO anon;
+GRANT ALL ON TABLE storage.objects TO authenticated;
+GRANT ALL ON TABLE storage.objects TO service_role;
+GRANT ALL ON TABLE storage.objects TO postgres;
+
+
+--
+-- Name: TABLE decrypted_secrets; Type: ACL; Schema: vault; Owner: supabase_admin
+--
+
+GRANT ALL ON TABLE vault.decrypted_secrets TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON SEQUENCES TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON FUNCTIONS TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: auth; Owner: supabase_auth_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_auth_admin IN SCHEMA auth GRANT ALL ON TABLES TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: extensions; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA extensions GRANT ALL ON SEQUENCES TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: extensions; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA extensions GRANT ALL ON FUNCTIONS TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: extensions; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA extensions GRANT ALL ON TABLES TO postgres WITH GRANT OPTION;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: graphql; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON SEQUENCES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON SEQUENCES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON SEQUENCES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: graphql; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON FUNCTIONS TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON FUNCTIONS TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON FUNCTIONS TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: graphql; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON TABLES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON TABLES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql GRANT ALL ON TABLES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: graphql_public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON SEQUENCES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON SEQUENCES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON SEQUENCES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: graphql_public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON FUNCTIONS TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON FUNCTIONS TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON FUNCTIONS TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: graphql_public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON TABLES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON TABLES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA graphql_public GRANT ALL ON TABLES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA pgsodium GRANT ALL ON SEQUENCES TO pgsodium_keyholder;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: pgsodium; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA pgsodium GRANT ALL ON SEQUENCES TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: pgsodium; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA pgsodium GRANT ALL ON TABLES TO pgsodium_keyholder;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: pgsodium; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA pgsodium GRANT ALL ON TABLES TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: pgsodium_masks; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA pgsodium_masks GRANT ALL ON SEQUENCES TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: pgsodium_masks; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA pgsodium_masks GRANT ALL ON FUNCTIONS TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: pgsodium_masks; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA pgsodium_masks GRANT ALL ON TABLES TO pgsodium_keyiduser;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: public; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON SEQUENCES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: public; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON FUNCTIONS TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: public; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA public GRANT ALL ON TABLES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: public; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT ALL ON TABLES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: realtime; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON SEQUENCES TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: realtime; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON FUNCTIONS TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: realtime; Owner: supabase_admin
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA realtime GRANT ALL ON TABLES TO dashboard_user;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: storage; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON SEQUENCES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON SEQUENCES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON SEQUENCES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON SEQUENCES TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: storage; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON FUNCTIONS TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON FUNCTIONS TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON FUNCTIONS TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON FUNCTIONS TO service_role;
+
+
+--
+-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: storage; Owner: postgres
+--
+
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON TABLES TO postgres;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON TABLES TO anon;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON TABLES TO authenticated;
+ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA storage GRANT ALL ON TABLES TO service_role;
+
+
+--
+-- Name: issue_graphql_placeholder; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER issue_graphql_placeholder ON sql_drop
+ WHEN TAG IN ('DROP EXTENSION')
+ EXECUTE FUNCTION extensions.set_graphql_placeholder();
+
+
+ALTER EVENT TRIGGER issue_graphql_placeholder OWNER TO supabase_admin;
+
+--
+-- Name: issue_pg_cron_access; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end
+ WHEN TAG IN ('CREATE SCHEMA')
+ EXECUTE FUNCTION extensions.grant_pg_cron_access();
+
+
+ALTER EVENT TRIGGER issue_pg_cron_access OWNER TO supabase_admin;
+
+--
+-- Name: issue_pg_graphql_access; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER issue_pg_graphql_access ON ddl_command_end
+ WHEN TAG IN ('CREATE FUNCTION')
+ EXECUTE FUNCTION extensions.grant_pg_graphql_access();
+
+
+ALTER EVENT TRIGGER issue_pg_graphql_access OWNER TO supabase_admin;
+
+--
+-- Name: issue_pg_net_access; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end
+ WHEN TAG IN ('CREATE EXTENSION')
+ EXECUTE FUNCTION extensions.grant_pg_net_access();
+
+
+ALTER EVENT TRIGGER issue_pg_net_access OWNER TO supabase_admin;
+
+--
+-- Name: pgrst_ddl_watch; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER pgrst_ddl_watch ON ddl_command_end
+ EXECUTE FUNCTION extensions.pgrst_ddl_watch();
+
+
+ALTER EVENT TRIGGER pgrst_ddl_watch OWNER TO supabase_admin;
+
+--
+-- Name: pgrst_drop_watch; Type: EVENT TRIGGER; Schema: -; Owner: supabase_admin
+--
+
+CREATE EVENT TRIGGER pgrst_drop_watch ON sql_drop
+ EXECUTE FUNCTION extensions.pgrst_drop_watch();
+
+
+ALTER EVENT TRIGGER pgrst_drop_watch OWNER TO supabase_admin;
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/tests/Transfer/resources/updateBackups.sh b/tests/Transfer/resources/updateBackups.sh
new file mode 100755
index 00000000..feabfeba
--- /dev/null
+++ b/tests/Transfer/resources/updateBackups.sh
@@ -0,0 +1,15 @@
+# This script uses your .env file and updates the backups.tar for NHost and Supabase.
+
+source ../../.env
+
+echo "Updating Supabase Backup..."
+export PGPASSWORD=$SUPABASE_TEST_PASSWORD
+pg_dump -U $SUPABASE_TEST_USERNAME -h $SUPABASE_TEST_HOST -p 5432 $SUPABASE_TEST_DATABASE > supabase/backup.tar
+unset PGPASSWORD
+echo "Done"
+
+echo "Updating NHost Backup..."
+export PGPASSWORD=$NHOST_TEST_PASSWORD
+pg_dump -U $NHOST_TEST_USERNAME -h $NHOST_TEST_SUBDOMAIN.db.$NHOST_TEST_REGION.nhost.run -p 5432 $NHOST_TEST_DATABASE > nhost/backup.tar
+unset PGPASSWORD
+echo "Done"
diff --git a/tests/e2e/adapters/Mock.php b/tests/e2e/adapters/Mock.php
new file mode 100644
index 00000000..3c6c5540
--- /dev/null
+++ b/tests/e2e/adapters/Mock.php
@@ -0,0 +1,77 @@
+