Skip to content

Commit 58ef375

Browse files
committed
feat(storage): add metadata, info and exists method
1 parent 42460a0 commit 58ef375

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

Sources/Storage/StorageApi.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ public class StorageApi: @unchecked Sendable {
3737
let response = try await http.send(request)
3838

3939
guard (200 ..< 300).contains(response.statusCode) else {
40-
if let error = try? configuration.decoder.decode(StorageError.self, from: response.data) {
40+
if let error = try? configuration.decoder.decode(
41+
StorageError.self,
42+
from: response.data
43+
) {
4144
throw error
4245
}
4346

Sources/Storage/StorageFileApi.swift

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ let DEFAULT_SEARCH_OPTIONS = SearchOptions(
1515
)
1616
)
1717

18+
private let defaultFileOptions = FileOptions(
19+
cacheControl: "3600",
20+
contentType: "text/plain;charset=UTF-8",
21+
upsert: false
22+
)
23+
1824
/// Supabase Storage File API
1925
public class StorageFileApi: StorageApi, @unchecked Sendable {
2026
/// The bucket id to operate on.
@@ -33,20 +39,37 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
3339
let signedURL: URL
3440
}
3541

42+
private func encodeMetadata(_ metadata: JSONObject) -> Data {
43+
let encoder = AnyJSON.encoder
44+
return (try? encoder.encode(metadata)) ?? "{}".data(using: .utf8)!
45+
}
46+
3647
func uploadOrUpdate(
3748
method: HTTPMethod,
3849
path: String,
3950
formData: MultipartFormData,
40-
options: FileOptions
51+
options: FileOptions?
4152
) async throws -> FileUploadResponse {
4253
var headers = HTTPHeaders()
4354

55+
let options = options ?? defaultFileOptions
56+
let metadata = options.metadata
57+
4458
if method == .post {
4559
headers.update(name: "x-upsert", value: "\(options.upsert)")
4660
}
4761

4862
headers["duplex"] = options.duplex
4963

64+
if let metadata {
65+
formData.append(encodeMetadata(metadata), withName: "metadata")
66+
}
67+
68+
formData.append(
69+
options.cacheControl.data(using: .utf8)!,
70+
withName: "cacheControl"
71+
)
72+
5073
struct UploadResponse: Decodable {
5174
let Key: String
5275
let Id: String
@@ -404,6 +427,27 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
404427
.decoded(decoder: configuration.decoder)
405428
}
406429

430+
/// Checks the existence of file.
431+
public func exists(path: String) async throws -> Bool {
432+
do {
433+
let response = try await execute(
434+
HTTPRequest(
435+
url: configuration.url.appendingPathComponent("object/\(bucketId)/\(path)"),
436+
method: .head
437+
)
438+
)
439+
return true
440+
} catch {
441+
if let error = error as? StorageError, let statusCode = error.statusCode,
442+
["400", "404"].contains(statusCode)
443+
{
444+
return false
445+
}
446+
447+
throw error
448+
}
449+
}
450+
407451
/// Returns a public url for an asset.
408452
/// - Parameters:
409453
/// - path: The file path to the asset. For example `folder/image.png`.
@@ -517,13 +561,13 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
517561
_ path: String,
518562
token: String,
519563
data: Data,
520-
options: FileOptions = FileOptions()
564+
options: FileOptions? = nil
521565
) async throws -> SignedURLUploadResponse {
522566
let formData = MultipartFormData()
523567
formData.append(
524568
data,
525569
withName: path.fileName,
526-
mimeType: options.contentType ?? mimeType(forPathExtension: path.pathExtension)
570+
mimeType: options?.contentType ?? mimeType(forPathExtension: path.pathExtension)
527571
)
528572
return try await _uploadToSignedURL(
529573
path: path,
@@ -545,7 +589,7 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
545589
_ path: String,
546590
token: String,
547591
fileURL: Data,
548-
options: FileOptions = FileOptions()
592+
options: FileOptions? = nil
549593
) async throws -> SignedURLUploadResponse {
550594
let formData = MultipartFormData()
551595
formData.append(fileURL, withName: path.fileName)
@@ -561,13 +605,20 @@ public class StorageFileApi: StorageApi, @unchecked Sendable {
561605
path: String,
562606
token: String,
563607
formData: MultipartFormData,
564-
options: FileOptions
608+
options: FileOptions?
565609
) async throws -> SignedURLUploadResponse {
610+
let options = options ?? defaultFileOptions
566611
var headers = HTTPHeaders([
567612
"x-upsert": "\(options.upsert)",
568613
])
569614
headers["duplex"] = options.duplex
570615

616+
if let metadata = options.metadata {
617+
formData.append(encodeMetadata(metadata), withName: "metadata")
618+
}
619+
620+
formData.append(options.cacheControl.data(using: .utf8)!, withName: "cacheControl")
621+
571622
struct UploadResponse: Decodable {
572623
let Key: String
573624
}

0 commit comments

Comments
 (0)