Skip to content

Commit 69d05ef

Browse files
authored
test(storage): integration tests (#371)
feat(storage): move objects between buckets feat(storage): copy objects between buckets
1 parent 4b01556 commit 69d05ef

18 files changed

+546
-199
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
SUPABASE_URL=https://mysupabasereference.supabase.co
44
SUPABASE_ANON_KEY=my.supabase.anon.key
5+
SUPABASE_SERVICE_ROLE_KEY=my.supabase.service.role.key

.github/workflows/integration-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
env:
2727
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
2828
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
29-
SUPABASE_SERVICE_KEY: ${{ secrets.SUPABASE_SERVICE_KEY }}
29+
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ define SECRETS
1212
enum DotEnv {
1313
static let SUPABASE_URL = "$(SUPABASE_URL)"
1414
static let SUPABASE_ANON_KEY = "$(SUPABASE_ANON_KEY)"
15+
static let SUPABASE_SERVICE_ROLE_KEY = "$(SUPABASE_SERVICE_ROLE_KEY)"
1516
}
1617
endef
1718

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ let package = Package(
8484
"TestHelpers",
8585
"PostgREST",
8686
"Realtime",
87+
"Storage",
8788
]
8889
),
8990
.target(

Sources/PostgREST/Types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public struct PostgrestResponse<T: Sendable>: Sendable {
3232
self.count = count
3333
self.value = value
3434
}
35-
35+
3636
/// Returns the response converting the returned Data into Unicode characters using a given encoding.
3737
public func string(encoding: String.Encoding = .utf8) -> String? {
3838
String(data: data, encoding: encoding)

Sources/Storage/BucketOptions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import Foundation
22

33
public struct BucketOptions: Sendable {
44
public let `public`: Bool
5-
public let fileSizeLimit: Int?
5+
public let fileSizeLimit: String?
66
public let allowedMimeTypes: [String]?
77

8-
public init(public: Bool = false, fileSizeLimit: Int? = nil, allowedMimeTypes: [String]? = nil) {
8+
public init(public: Bool = false, fileSizeLimit: String? = nil, allowedMimeTypes: [String]? = nil) {
99
self.public = `public`
1010
self.fileSizeLimit = fileSizeLimit
1111
self.allowedMimeTypes = allowedMimeTypes

Sources/Storage/Deprecated.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,39 @@ extension StorageClientConfiguration {
3030
)
3131
}
3232
}
33+
34+
extension StorageFileApi {
35+
@_disfavoredOverload
36+
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
37+
@discardableResult
38+
public func upload(
39+
path: String,
40+
file: Data,
41+
options: FileOptions = FileOptions()
42+
) async throws -> String {
43+
try await upload(path: path, file: file, options: options).fullPath
44+
}
45+
46+
@_disfavoredOverload
47+
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
48+
@discardableResult
49+
public func update(
50+
path: String,
51+
file: Data,
52+
options: FileOptions = FileOptions()
53+
) async throws -> String {
54+
try await update(path: path, file: file, options: options).fullPath
55+
}
56+
57+
@_disfavoredOverload
58+
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
59+
@discardableResult
60+
public func uploadToSignedURL(
61+
path: String,
62+
token: String,
63+
file: Data,
64+
options: FileOptions = FileOptions()
65+
) async throws -> String {
66+
try await uploadToSignedURL(path: path, token: token, file: file, options: options).fullPath
67+
}
68+
}

Sources/Storage/StorageBucketApi.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class StorageBucketApi: StorageApi {
3535
var id: String
3636
var name: String
3737
var `public`: Bool
38-
var fileSizeLimit: Int?
38+
var fileSizeLimit: String?
3939
var allowedMimeTypes: [String]?
4040
}
4141

Sources/Storage/StorageFileApi.swift

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ public class StorageFileApi: StorageApi {
2424
super.init(configuration: configuration)
2525
}
2626

27-
private struct UploadResponse: Decodable {
28-
let Key: String
29-
}
30-
3127
private struct MoveResponse: Decodable {
3228
let message: String
3329
}
@@ -41,7 +37,7 @@ public class StorageFileApi: StorageApi {
4137
path: String,
4238
file: Data,
4339
options: FileOptions
44-
) async throws -> String {
40+
) async throws -> FileUploadResponse {
4541
let contentType = options.contentType
4642
var headers = HTTPHeaders([
4743
"x-upsert": "\(options.upsert)",
@@ -56,7 +52,12 @@ public class StorageFileApi: StorageApi {
5652
file: File(name: fileName, data: file, fileName: fileName, contentType: contentType)
5753
)
5854

59-
return try await execute(
55+
struct UploadResponse: Decodable {
56+
let Key: String
57+
let Id: String
58+
}
59+
60+
let response = try await execute(
6061
HTTPRequest(
6162
url: configuration.url.appendingPathComponent("object/\(bucketId)/\(path)"),
6263
method: method,
@@ -66,7 +67,13 @@ public class StorageFileApi: StorageApi {
6667
headers: headers
6768
)
6869
)
69-
.decoded(as: UploadResponse.self, decoder: configuration.decoder).Key
70+
.decoded(as: UploadResponse.self, decoder: configuration.decoder)
71+
72+
return FileUploadResponse(
73+
id: response.Id,
74+
path: path,
75+
fullPath: response.Key
76+
)
7077
}
7178

7279
/// Uploads a file to an existing bucket.
@@ -80,7 +87,7 @@ public class StorageFileApi: StorageApi {
8087
path: String,
8188
file: Data,
8289
options: FileOptions = FileOptions()
83-
) async throws -> String {
90+
) async throws -> FileUploadResponse {
8491
try await uploadOrUpdate(method: .post, path: path, file: file, options: options)
8592
}
8693

@@ -95,16 +102,20 @@ public class StorageFileApi: StorageApi {
95102
path: String,
96103
file: Data,
97104
options: FileOptions = FileOptions()
98-
) async throws -> String {
105+
) async throws -> FileUploadResponse {
99106
try await uploadOrUpdate(method: .put, path: path, file: file, options: options)
100107
}
101108

102109
/// Moves an existing file, optionally renaming it at the same time.
103110
/// - Parameters:
104-
/// - from: The original file path, including the current file name. For example
105-
/// `folder/image.png`.
106-
/// - to: The new file path, including the new file name. For example `folder/image-copy.png`.
107-
public func move(from source: String, to destination: String) async throws {
111+
/// - source: The original file path, including the current file name. For example `folder/image.png`.
112+
/// - destination: The new file path, including the new file name. For example `folder/image-copy.png`.
113+
/// - options: The destination options.
114+
public func move(
115+
from source: String,
116+
to destination: String,
117+
options: DestinationOptions? = nil
118+
) async throws {
108119
try await execute(
109120
HTTPRequest(
110121
url: configuration.url.appendingPathComponent("object/move"),
@@ -114,6 +125,7 @@ public class StorageFileApi: StorageApi {
114125
"bucketId": bucketId,
115126
"sourceKey": source,
116127
"destinationKey": destination,
128+
"destinationBucket": options?.destinationBucket
117129
]
118130
)
119131
)
@@ -122,12 +134,20 @@ public class StorageFileApi: StorageApi {
122134

123135
/// Copies an existing file to a new path in the same bucket.
124136
/// - Parameters:
125-
/// - from: The original file path, including the current file name. For example
126-
/// `folder/image.png`.
127-
/// - to: The new file path, including the new file name. For example `folder/image-copy.png`.
137+
/// - source: The original file path, including the current file name. For example `folder/image.png`.
138+
/// - destination: The new file path, including the new file name. For example `folder/image-copy.png`.
139+
/// - options: The destination options.
128140
@discardableResult
129-
public func copy(from source: String, to destination: String) async throws -> String {
130-
try await execute(
141+
public func copy(
142+
from source: String,
143+
to destination: String,
144+
options: DestinationOptions? = nil
145+
) async throws -> String {
146+
struct UploadResponse: Decodable {
147+
let Key: String
148+
}
149+
150+
return try await execute(
131151
HTTPRequest(
132152
url: configuration.url.appendingPathComponent("object/copy"),
133153
method: .post,
@@ -136,6 +156,7 @@ public class StorageFileApi: StorageApi {
136156
"bucketId": bucketId,
137157
"sourceKey": source,
138158
"destinationKey": destination,
159+
"destinationBucket": options?.destinationBucket
139160
]
140161
)
141162
)
@@ -393,15 +414,24 @@ public class StorageFileApi: StorageApi {
393414
///
394415
/// - Note: Signed upload URLs can be used to upload files to the bucket without further
395416
/// authentication. They are valid for 2 hours.
396-
public func createSignedUploadURL(path: String) async throws -> SignedUploadURL {
417+
public func createSignedUploadURL(
418+
path: String,
419+
options: CreateSignedUploadURLOptions? = nil
420+
) async throws -> SignedUploadURL {
397421
struct Response: Decodable {
398422
let url: URL
399423
}
400424

425+
var headers = HTTPHeaders()
426+
if let upsert = options?.upsert, upsert {
427+
headers["x-upsert"] = "true"
428+
}
429+
401430
let response = try await execute(
402431
HTTPRequest(
403432
url: configuration.url.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
404-
method: .post
433+
method: .post,
434+
headers: headers
405435
)
406436
)
407437
.decoded(as: Response.self, decoder: configuration.decoder)
@@ -441,7 +471,7 @@ public class StorageFileApi: StorageApi {
441471
token: String,
442472
file: Data,
443473
options: FileOptions = FileOptions()
444-
) async throws -> String {
474+
) async throws -> SignedURLUploadResponse {
445475
let contentType = options.contentType
446476
var headers = HTTPHeaders([
447477
"x-upsert": "\(options.upsert)",
@@ -458,7 +488,11 @@ public class StorageFileApi: StorageApi {
458488
contentType: contentType
459489
))
460490

461-
return try await execute(
491+
struct UploadResponse: Decodable {
492+
let Key: String
493+
}
494+
495+
let fullPath = try await execute(
462496
HTTPRequest(
463497
url: configuration.url
464498
.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
@@ -471,6 +505,8 @@ public class StorageFileApi: StorageApi {
471505
)
472506
.decoded(as: UploadResponse.self, decoder: configuration.decoder)
473507
.Key
508+
509+
return SignedURLUploadResponse(path: path, fullPath: fullPath)
474510
}
475511
}
476512

Sources/Storage/TransformOptions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ public struct TransformOptions: Encodable, Sendable {
1010
public init(
1111
width: Int? = nil,
1212
height: Int? = nil,
13-
resize: String? = "cover",
13+
resize: String? = nil,
1414
quality: Int? = 80,
15-
format: String? = "origin"
15+
format: String? = nil
1616
) {
1717
self.width = width
1818
self.height = height

0 commit comments

Comments
 (0)