Skip to content

Commit

Permalink
test(storage): integration tests (#371)
Browse files Browse the repository at this point in the history
feat(storage): move objects between buckets

feat(storage): copy objects between buckets
  • Loading branch information
grdsdev committed May 9, 2024
1 parent 4b01556 commit 69d05ef
Show file tree
Hide file tree
Showing 18 changed files with 546 additions and 199 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

SUPABASE_URL=https://mysupabasereference.supabase.co
SUPABASE_ANON_KEY=my.supabase.anon.key
SUPABASE_SERVICE_ROLE_KEY=my.supabase.service.role.key
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ jobs:
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
SUPABASE_SERVICE_KEY: ${{ secrets.SUPABASE_SERVICE_KEY }}
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ define SECRETS
enum DotEnv {
static let SUPABASE_URL = "$(SUPABASE_URL)"
static let SUPABASE_ANON_KEY = "$(SUPABASE_ANON_KEY)"
static let SUPABASE_SERVICE_ROLE_KEY = "$(SUPABASE_SERVICE_ROLE_KEY)"
}
endef

Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ let package = Package(
"TestHelpers",
"PostgREST",
"Realtime",
"Storage",
]
),
.target(
Expand Down
2 changes: 1 addition & 1 deletion Sources/PostgREST/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public struct PostgrestResponse<T: Sendable>: Sendable {
self.count = count
self.value = value
}

/// Returns the response converting the returned Data into Unicode characters using a given encoding.
public func string(encoding: String.Encoding = .utf8) -> String? {
String(data: data, encoding: encoding)
Expand Down
4 changes: 2 additions & 2 deletions Sources/Storage/BucketOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import Foundation

public struct BucketOptions: Sendable {
public let `public`: Bool
public let fileSizeLimit: Int?
public let fileSizeLimit: String?
public let allowedMimeTypes: [String]?

public init(public: Bool = false, fileSizeLimit: Int? = nil, allowedMimeTypes: [String]? = nil) {
public init(public: Bool = false, fileSizeLimit: String? = nil, allowedMimeTypes: [String]? = nil) {
self.public = `public`
self.fileSizeLimit = fileSizeLimit
self.allowedMimeTypes = allowedMimeTypes
Expand Down
36 changes: 36 additions & 0 deletions Sources/Storage/Deprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,39 @@ extension StorageClientConfiguration {
)
}
}

extension StorageFileApi {
@_disfavoredOverload
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
@discardableResult
public func upload(
path: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
try await upload(path: path, file: file, options: options).fullPath
}

@_disfavoredOverload
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
@discardableResult
public func update(
path: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
try await update(path: path, file: file, options: options).fullPath
}

@_disfavoredOverload
@available(*, deprecated, message: "Please use method that returns FileUploadResponse.")
@discardableResult
public func uploadToSignedURL(
path: String,
token: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
try await uploadToSignedURL(path: path, token: token, file: file, options: options).fullPath
}
}
2 changes: 1 addition & 1 deletion Sources/Storage/StorageBucketApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class StorageBucketApi: StorageApi {
var id: String
var name: String
var `public`: Bool
var fileSizeLimit: Int?
var fileSizeLimit: String?
var allowedMimeTypes: [String]?
}

Expand Down
80 changes: 58 additions & 22 deletions Sources/Storage/StorageFileApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ public class StorageFileApi: StorageApi {
super.init(configuration: configuration)
}

private struct UploadResponse: Decodable {
let Key: String
}

private struct MoveResponse: Decodable {
let message: String
}
Expand All @@ -41,7 +37,7 @@ public class StorageFileApi: StorageApi {
path: String,
file: Data,
options: FileOptions
) async throws -> String {
) async throws -> FileUploadResponse {
let contentType = options.contentType
var headers = HTTPHeaders([
"x-upsert": "\(options.upsert)",
Expand All @@ -56,7 +52,12 @@ public class StorageFileApi: StorageApi {
file: File(name: fileName, data: file, fileName: fileName, contentType: contentType)
)

return try await execute(
struct UploadResponse: Decodable {
let Key: String
let Id: String
}

let response = try await execute(
HTTPRequest(
url: configuration.url.appendingPathComponent("object/\(bucketId)/\(path)"),
method: method,
Expand All @@ -66,7 +67,13 @@ public class StorageFileApi: StorageApi {
headers: headers
)
)
.decoded(as: UploadResponse.self, decoder: configuration.decoder).Key
.decoded(as: UploadResponse.self, decoder: configuration.decoder)

return FileUploadResponse(
id: response.Id,
path: path,
fullPath: response.Key
)
}

/// Uploads a file to an existing bucket.
Expand All @@ -80,7 +87,7 @@ public class StorageFileApi: StorageApi {
path: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
) async throws -> FileUploadResponse {
try await uploadOrUpdate(method: .post, path: path, file: file, options: options)
}

Expand All @@ -95,16 +102,20 @@ public class StorageFileApi: StorageApi {
path: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
) async throws -> FileUploadResponse {
try await uploadOrUpdate(method: .put, path: path, file: file, options: options)
}

/// Moves an existing file, optionally renaming it at the same time.
/// - Parameters:
/// - from: The original file path, including the current file name. For example
/// `folder/image.png`.
/// - to: The new file path, including the new file name. For example `folder/image-copy.png`.
public func move(from source: String, to destination: String) async throws {
/// - source: The original file path, including the current file name. For example `folder/image.png`.
/// - destination: The new file path, including the new file name. For example `folder/image-copy.png`.
/// - options: The destination options.
public func move(
from source: String,
to destination: String,
options: DestinationOptions? = nil
) async throws {
try await execute(
HTTPRequest(
url: configuration.url.appendingPathComponent("object/move"),
Expand All @@ -114,6 +125,7 @@ public class StorageFileApi: StorageApi {
"bucketId": bucketId,
"sourceKey": source,
"destinationKey": destination,
"destinationBucket": options?.destinationBucket
]
)
)
Expand All @@ -122,12 +134,20 @@ public class StorageFileApi: StorageApi {

/// Copies an existing file to a new path in the same bucket.
/// - Parameters:
/// - from: The original file path, including the current file name. For example
/// `folder/image.png`.
/// - to: The new file path, including the new file name. For example `folder/image-copy.png`.
/// - source: The original file path, including the current file name. For example `folder/image.png`.
/// - destination: The new file path, including the new file name. For example `folder/image-copy.png`.
/// - options: The destination options.
@discardableResult
public func copy(from source: String, to destination: String) async throws -> String {
try await execute(
public func copy(
from source: String,
to destination: String,
options: DestinationOptions? = nil
) async throws -> String {
struct UploadResponse: Decodable {
let Key: String
}

return try await execute(
HTTPRequest(
url: configuration.url.appendingPathComponent("object/copy"),
method: .post,
Expand All @@ -136,6 +156,7 @@ public class StorageFileApi: StorageApi {
"bucketId": bucketId,
"sourceKey": source,
"destinationKey": destination,
"destinationBucket": options?.destinationBucket
]
)
)
Expand Down Expand Up @@ -393,15 +414,24 @@ public class StorageFileApi: StorageApi {
///
/// - Note: Signed upload URLs can be used to upload files to the bucket without further
/// authentication. They are valid for 2 hours.
public func createSignedUploadURL(path: String) async throws -> SignedUploadURL {
public func createSignedUploadURL(
path: String,
options: CreateSignedUploadURLOptions? = nil
) async throws -> SignedUploadURL {
struct Response: Decodable {
let url: URL
}

var headers = HTTPHeaders()
if let upsert = options?.upsert, upsert {
headers["x-upsert"] = "true"
}

let response = try await execute(
HTTPRequest(
url: configuration.url.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
method: .post
method: .post,
headers: headers
)
)
.decoded(as: Response.self, decoder: configuration.decoder)
Expand Down Expand Up @@ -441,7 +471,7 @@ public class StorageFileApi: StorageApi {
token: String,
file: Data,
options: FileOptions = FileOptions()
) async throws -> String {
) async throws -> SignedURLUploadResponse {
let contentType = options.contentType
var headers = HTTPHeaders([
"x-upsert": "\(options.upsert)",
Expand All @@ -458,7 +488,11 @@ public class StorageFileApi: StorageApi {
contentType: contentType
))

return try await execute(
struct UploadResponse: Decodable {
let Key: String
}

let fullPath = try await execute(
HTTPRequest(
url: configuration.url
.appendingPathComponent("object/upload/sign/\(bucketId)/\(path)"),
Expand All @@ -471,6 +505,8 @@ public class StorageFileApi: StorageApi {
)
.decoded(as: UploadResponse.self, decoder: configuration.decoder)
.Key

return SignedURLUploadResponse(path: path, fullPath: fullPath)
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/Storage/TransformOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ public struct TransformOptions: Encodable, Sendable {
public init(
width: Int? = nil,
height: Int? = nil,
resize: String? = "cover",
resize: String? = nil,
quality: Int? = 80,
format: String? = "origin"
format: String? = nil
) {
self.width = width
self.height = height
Expand Down
27 changes: 27 additions & 0 deletions Sources/Storage/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,30 @@ public struct SignedUploadURL: Sendable {
public let path: String
public let token: String
}

public struct FileUploadResponse: Sendable {
public let id: String
public let path: String
public let fullPath: String
}

public struct SignedURLUploadResponse: Sendable {
public let path: String
public let fullPath: String
}

public struct CreateSignedUploadURLOptions: Sendable {
public var upsert: Bool

public init(upsert: Bool) {
self.upsert = upsert
}
}

public struct DestinationOptions: Sendable {
public var destinationBucket: String?

public init(destinationBucket: String? = nil) {
self.destinationBucket = destinationBucket
}
}
2 changes: 1 addition & 1 deletion Tests/FunctionsTests/FunctionsClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class FunctionsClientTests: XCTestCase {
let http = HTTPClientMock().any { _ in try .stub(body: Empty()) }

let sut = FunctionsClient(
url: self.url,
url: url,
headers: ["Apikey": apiKey],
region: nil,
http: http
Expand Down
1 change: 1 addition & 0 deletions Tests/IntegrationTests/Fixtures/Upload/file-2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
supabase txt file 2
Binary file added Tests/IntegrationTests/Fixtures/Upload/sadcat.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 69d05ef

Please sign in to comment.