Skip to content

Commit

Permalink
feat(storage_client): Support copy/move to different bucket (#1043)
Browse files Browse the repository at this point in the history
* ci: update infra to state of storage-js

* feat(storage_client): support copy/move to different bucket
  • Loading branch information
Vinzent03 authored Sep 25, 2024
1 parent 8f473f1 commit e095c14
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 18 deletions.
20 changes: 19 additions & 1 deletion infra/storage_client/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ services:
FILE_STORAGE_BACKEND_PATH: /tmp/storage
ENABLE_IMAGE_TRANSFORMATION: "true"
IMGPROXY_URL: http://imgproxy:8080
DEBUG: "knex:*"

volumes:
- assets-volume:/tmp/storage
healthcheck:
test: ['CMD-SHELL', 'curl -f -LI http://localhost:5000/status']
interval: 2s

db:
build:
context: ./postgres
Expand All @@ -62,6 +66,20 @@ services:
timeout: 5s
retries: 5

dummy_data:
build:
context: ./postgres
depends_on:
storage:
condition: service_healthy
volumes:
- ./postgres:/sql
command:
- psql
- "postgresql://postgres:postgres@db:5432/postgres"
- -f
- /sql/dummy-data.sql

imgproxy:
image: darthsim/imgproxy
ports:
Expand All @@ -73,4 +91,4 @@ services:
- IMGPROXY_USE_ETAG=true
- IMGPROXY_ENABLE_WEBP_DETECTION=true
volumes:
assets-volume:
assets-volume:
3 changes: 1 addition & 2 deletions infra/storage_client/postgres/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ FROM supabase/postgres:0.13.0
COPY 00-initial-schema.sql /docker-entrypoint-initdb.d/00-initial-schema.sql
COPY auth-schema.sql /docker-entrypoint-initdb.d/01-auth-schema.sql
COPY storage-schema.sql /docker-entrypoint-initdb.d/02-storage-schema.sql
COPY dummy-data.sql /docker-entrypoint-initdb.d/03-dummy-data.sql

# Build time defaults
ARG build_POSTGRES_DB=postgres
Expand All @@ -17,4 +16,4 @@ ENV POSTGRES_USER=$build_POSTGRES_USER
ENV POSTGRES_PASSWORD=$build_POSTGRES_PASSWORD
ENV POSTGRES_PORT=$build_POSTGRES_PORT

EXPOSE 5432
EXPOSE 5432
18 changes: 7 additions & 11 deletions infra/storage_client/postgres/storage-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ CREATE TABLE "storage"."objects" (
"last_accessed_at" timestamptz DEFAULT now(),
"metadata" jsonb,
CONSTRAINT "objects_bucketId_fkey" FOREIGN KEY ("bucket_id") REFERENCES "storage"."buckets"("id"),
CONSTRAINT "objects_owner_fkey" FOREIGN KEY ("owner") REFERENCES "auth"."users"("id"),
PRIMARY KEY ("id")
);
CREATE UNIQUE INDEX "bucketid_objname" ON "storage"."objects" USING BTREE ("bucket_id","name");
Expand Down Expand Up @@ -85,27 +84,24 @@ CREATE OR REPLACE FUNCTION storage.search(prefix text, bucketname text, limits i
)
LANGUAGE plpgsql
AS $function$
DECLARE
_bucketId text;
BEGIN
select buckets."id" from buckets where buckets.name=bucketname limit 1 into _bucketId;
return query
return query
with files_folders as (
select ((string_to_array(objects.name, '/'))[levels]) as folder
from objects
where objects.name ilike prefix || '%'
and bucket_id = _bucketId
and bucket_id = bucketname
GROUP by folder
limit limits
offset offsets
)
select files_folders.folder as name, objects.id, objects.updated_at, objects.created_at, objects.last_accessed_at, objects.metadata from files_folders
)
select files_folders.folder as name, objects.id, objects.updated_at, objects.created_at, objects.last_accessed_at, objects.metadata from files_folders
left join objects
on prefix || files_folders.folder = objects.name
where objects.id is null or objects.bucket_id=_bucketId;
on prefix || files_folders.folder = objects.name and objects.bucket_id=bucketname;
END
$function$;

GRANT ALL PRIVILEGES ON SCHEMA storage TO postgres;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA storage TO postgres;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA storage TO postgres;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA storage TO postgres;

4 changes: 2 additions & 2 deletions infra/storage_client/storage/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM supabase/storage-api:v0.35.1
FROM supabase/storage-api:v1.8.2

RUN apk add curl --no-cache
RUN apk add curl --no-cache
18 changes: 16 additions & 2 deletions packages/storage_client/lib/src/storage_file_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,21 @@ class StorageFileApi {
/// example `folder/image.png`.
/// [toPath] is the new file path, including the new file name. For example
/// `folder/image-new.png`.
Future<String> move(String fromPath, String toPath) async {
///
/// When copying to a different bucket, you have to specify the [destinationBucket].
Future<String> move(
String fromPath,
String toPath, {
String? destinationBucket,
}) async {
final options = FetchOptions(headers: headers);
final response = await _storageFetch.post(
'$url/object/move',
{
'bucketId': bucketId,
'sourceKey': fromPath,
'destinationKey': toPath,
if (destinationBucket != null) 'destinationBucket': destinationBucket,
},
options: options,
);
Expand All @@ -297,14 +304,21 @@ class StorageFileApi {
///
/// [toPath] is the new file path, including the new file name. For example
/// `folder/image-copy.png`.
Future<String> copy(String fromPath, String toPath) async {
///
/// When copying to a different bucket, you have to specify the [destinationBucket].
Future<String> copy(
String fromPath,
String toPath, {
String? destinationBucket,
}) async {
final options = FetchOptions(headers: headers);
final response = await _storageFetch.post(
'$url/object/copy',
{
'bucketId': bucketId,
'sourceKey': fromPath,
'destinationKey': toPath,
if (destinationBucket != null) 'destinationBucket': destinationBucket,
},
options: options,
);
Expand Down
46 changes: 46 additions & 0 deletions packages/storage_client/test/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -388,5 +388,51 @@ void main() {

await storage.from(newBucketName).copy(uploadPath, "$uploadPath 2");
});

test('copy to different bucket', () async {
final storage = SupabaseStorageClient(
storageUrl, {'Authorization': 'Bearer $storageKey'});

try {
await storage.from('bucket2').download(uploadPath);
fail('File that does not exist was found');
} on StorageException catch (error) {
expect(error.error, 'not_found');
}
await storage
.from(newBucketName)
.copy(uploadPath, uploadPath, destinationBucket: 'bucket2');
try {
await storage.from('bucket2').download(uploadPath);
} catch (error) {
fail('File that was copied was not found');
}
});

test('move to different bucket', () async {
final storage = SupabaseStorageClient(
storageUrl, {'Authorization': 'Bearer $storageKey'});

try {
await storage.from('bucket2').download('$uploadPath 3');
fail('File that does not exist was found');
} on StorageException catch (error) {
expect(error.error, 'not_found');
}
await storage
.from(newBucketName)
.move(uploadPath, '$uploadPath 3', destinationBucket: 'bucket2');
try {
await storage.from('bucket2').download('$uploadPath 3');
} catch (error) {
fail('File that was moved was not found');
}
try {
await storage.from(newBucketName).download(uploadPath);
fail('File that was moved was found');
} on StorageException catch (error) {
expect(error.error, 'not_found');
}
});
});
}

0 comments on commit e095c14

Please sign in to comment.