Skip to content

Commit

Permalink
Move upsert parameter to new FileOptionBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
jan-tennert committed Aug 26, 2024
1 parent 4ca681d commit b442961
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,91 +34,84 @@ sealed interface BucketApi {
* Uploads a file in [bucketId] under [path]
* @param path The path to upload the file to
* @param data The data to upload
* @param upsert Whether to overwrite an existing file
* @return the key to the uploaded file
* @throws IllegalArgumentException if data to upload is empty
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
*/
suspend fun upload(path: String, data: ByteArray, upsert: Boolean = false, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse {
suspend fun upload(path: String, data: ByteArray, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse {
require(data.isNotEmpty()) { "The data to upload should not be empty" }
return upload(path, UploadData(ByteReadChannel(data), data.size.toLong()), upsert, options)
return upload(path, UploadData(ByteReadChannel(data), data.size.toLong()), options)
}

/**
* Uploads a file in [bucketId] under [path]
* @param path The path to upload the file to
* @param data The data to upload
* @param upsert Whether to overwrite an existing file
* @return the key to the uploaded file
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
*/
suspend fun upload(path: String, data: UploadData, upsert: Boolean = false, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse
suspend fun upload(path: String, data: UploadData, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse

/**
* Uploads a file in [bucketId] under [path] using a presigned url
* @param path The path to upload the file to
* @param token The presigned url token
* @param token The pre-signed url token
* @param data The data to upload
* @param upsert Whether to overwrite an existing file
* @return the key of the uploaded file
* @throws IllegalArgumentException if data to upload is empty
*/
suspend fun uploadToSignedUrl(
path: String,
token: String,
data: ByteArray,
upsert: Boolean = false,
options: FileOptionBuilder.() -> Unit = {}
): FileUploadResponse {
require(data.isNotEmpty()) { "The data to upload should not be empty" }
return uploadToSignedUrl(path, token, UploadData(ByteReadChannel(data), data.size.toLong()), upsert, options)
return uploadToSignedUrl(path, token, UploadData(ByteReadChannel(data), data.size.toLong()), options)
}

/**
* Uploads a file in [bucketId] under [path] using a presigned url
* @param path The path to upload the file to
* @param token The presigned url token
* @param data The data to upload
* @param upsert Whether to overwrite an existing file
* @return the key of the uploaded file
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
* @throws HttpRequestException on network related issues
*/
suspend fun uploadToSignedUrl(path: String, token: String, data: UploadData, upsert: Boolean = false, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse
suspend fun uploadToSignedUrl(path: String, token: String, data: UploadData, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse

/**
* Updates a file in [bucketId] under [path]
* @param path The path to update the file to
* @param data The new data
* @param upsert Whether to overwrite an existing file
* @return the key to the updated file
* @throws IllegalArgumentException if data to upload is empty
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
*/
suspend fun update(path: String, data: ByteArray, upsert: Boolean = false, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse {
suspend fun update(path: String, data: ByteArray, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse {
require(data.isNotEmpty()) { "The data to upload should not be empty" }
return update(path, UploadData(ByteReadChannel(data), data.size.toLong()), upsert, options)
return update(path, UploadData(ByteReadChannel(data), data.size.toLong()), options)
}

/**
* Updates a file in [bucketId] under [path]
* @param path The path to update the file to
* @param data The new data
* @param upsert Whether to overwrite an existing file
* @return the key to the updated file
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
*/
suspend fun update(path: String, data: UploadData, upsert: Boolean = false, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse
suspend fun update(path: String, data: UploadData, options: FileOptionBuilder.() -> Unit = {}): FileUploadResponse

/**
* Deletes all files in [bucketId] with in [paths]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,19 @@ internal class BucketApiImpl(override val bucketId: String, val storage: Storage
override suspend fun update(
path: String,
data: UploadData,
upsert: Boolean,
options: FileOptionBuilder.() -> Unit
): FileUploadResponse =
uploadOrUpdate(
HttpMethod.Put, bucketId, path, data, upsert, options
HttpMethod.Put, bucketId, path, data, options
)

override suspend fun uploadToSignedUrl(
path: String,
token: String,
data: UploadData,
upsert: Boolean,
options: FileOptionBuilder.() -> Unit
): FileUploadResponse {
return uploadToSignedUrl(path, token, data, upsert, options) {}
return uploadToSignedUrl(path, token, data, options) {}
}

override suspend fun createSignedUploadUrl(path: String): UploadSignedUrl {
Expand All @@ -77,11 +75,10 @@ internal class BucketApiImpl(override val bucketId: String, val storage: Storage
override suspend fun upload(
path: String,
data: UploadData,
upsert: Boolean,
options: FileOptionBuilder.() -> Unit
): FileUploadResponse =
uploadOrUpdate(
HttpMethod.Post, bucketId, path, data, upsert, options
HttpMethod.Post, bucketId, path, data, options
)

override suspend fun delete(paths: Collection<String>) {
Expand Down Expand Up @@ -249,14 +246,13 @@ internal class BucketApiImpl(override val bucketId: String, val storage: Storage
bucket: String,
path: String,
data: UploadData,
upsert: Boolean,
options: FileOptionBuilder.() -> Unit,
extra: HttpRequestBuilder.() -> Unit = {}
): FileUploadResponse {
val optionBuilder = FileOptionBuilder(storage.serializer).apply(options)
val response = storage.api.request("object/$bucket/$path") {
this.method = method
defaultUploadRequest(path, data, upsert, optionBuilder, extra)
defaultUploadRequest(path, data, optionBuilder, extra)
}.body<JsonObject>()
val key = response["Key"]?.jsonPrimitive?.content
?: error("Expected a key in a upload response")
Expand All @@ -271,14 +267,13 @@ internal class BucketApiImpl(override val bucketId: String, val storage: Storage
path: String,
token: String,
data: UploadData,
upsert: Boolean,
options: FileOptionBuilder.() -> Unit,
extra: HttpRequestBuilder.() -> Unit = {}
): FileUploadResponse {
val optionBuilder = FileOptionBuilder(storage.serializer).apply(options)
val response = storage.api.put("object/upload/sign/$bucketId/$path") {
parameter("token", token)
defaultUploadRequest(path, data, upsert, optionBuilder, extra)
defaultUploadRequest(path, data, optionBuilder, extra)
}.body<JsonObject>()
val key = response["Key"]?.jsonPrimitive?.content
?: error("Expected a key in a upload response")
Expand All @@ -291,17 +286,16 @@ internal class BucketApiImpl(override val bucketId: String, val storage: Storage
private fun HttpRequestBuilder.defaultUploadRequest(
path: String,
data: UploadData,
upsert: Boolean,
optionBuilder: FileOptionBuilder,
extra: HttpRequestBuilder.() -> Unit
) {
setBody(object : OutgoingContent.ReadChannelContent() {
override val contentType: ContentType = ContentType.defaultForFilePath(path)
override val contentType: ContentType = optionBuilder.contentType ?: ContentType.defaultForFilePath(path)
override val contentLength: Long = data.size
override fun readFrom(): ByteReadChannel = data.stream
})
header(HttpHeaders.ContentType, ContentType.defaultForFilePath(path))
header(UPSERT_HEADER, upsert.toString())
header(HttpHeaders.ContentType, optionBuilder.contentType ?: ContentType.defaultForFilePath(path))
header(UPSERT_HEADER, optionBuilder.upsert.toString())
optionBuilder.userMetadata?.let {
header("x-metadata", Base64.Default.encode(it.toString().encodeToByteArray()).also((::println)))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.jan.supabase.storage

import io.github.jan.supabase.SupabaseSerializer
import io.github.jan.supabase.encodeToJsonElement
import io.ktor.http.ContentType
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonObjectBuilder
import kotlinx.serialization.json.buildJsonObject
Expand All @@ -11,10 +12,14 @@ import kotlinx.serialization.json.jsonObject
* Builder for uploading files with additional options
* @param serializer The serializer to use for encoding the metadata
* @param userMetadata The user metadata to upload with the file
* @param upsert Whether to update the file if it already exists
* @param contentType The content type of the file. If null, the content type will be inferred from the file extension
*/
class FileOptionBuilder(
@PublishedApi internal val serializer: SupabaseSerializer,
var userMetadata: JsonObject? = null,
var upsert: Boolean = false,
var contentType: ContentType? = null,
) {

/**
Expand Down
12 changes: 8 additions & 4 deletions Storage/src/commonTest/kotlin/BucketApiTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ class BucketApiTest {
)
},
request = { client, expectedPath, data, meta ->
client.storage[bucketId].upload(expectedPath, data, upsert = true) {
client.storage[bucketId].upload(expectedPath, data) {
userMetadata = meta
upsert = true
}
}
)
Expand All @@ -115,8 +116,9 @@ class BucketApiTest {
)
},
request = { client, expectedPath, data, meta ->
client.storage[bucketId].uploadToSignedUrl(path = expectedPath, token = expectedToken, data = data, upsert = false) {
client.storage[bucketId].uploadToSignedUrl(path = expectedPath, token = expectedToken, data = data) {
userMetadata = meta
upsert = false
}
}
)
Expand All @@ -141,8 +143,9 @@ class BucketApiTest {
)
},
request = { client, expectedPath, data, meta ->
client.storage[bucketId].uploadToSignedUrl(path = expectedPath, token = expectedToken, data = data, upsert = true) {
client.storage[bucketId].uploadToSignedUrl(path = expectedPath, token = expectedToken, data = data) {
userMetadata = meta
upsert = true
}
}
)
Expand Down Expand Up @@ -181,8 +184,9 @@ class BucketApiTest {
)
},
request = { client, expectedPath, data, meta ->
client.storage[bucketId].update(expectedPath, data, upsert = true) {
client.storage[bucketId].update(expectedPath, data) {
userMetadata = meta
upsert = true
}
}
)
Expand Down

0 comments on commit b442961

Please sign in to comment.