Skip to content

Commit 6e84b32

Browse files
authored
Feature - issue 21 (#26)
* feat: implement partially method copy * test: increment unit test * chore: implement supabase stack * chore: automate release with release-please * feat: format class * feat: add find method * feat: implement method find * test: improve unit tests * feat: uncomment duplex options * refactor: rename method to info
1 parent e8ff5c6 commit 6e84b32

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-2
lines changed

Storage/FileObjectV2.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Newtonsoft.Json;
4+
5+
namespace Supabase.Storage
6+
{
7+
public class FileObjectV2
8+
{
9+
10+
[JsonProperty("id")]
11+
public string Id { get; set; }
12+
13+
[JsonProperty("version")]
14+
public string Version { get; set; }
15+
16+
[JsonProperty("name")]
17+
public string? Name { get; set; }
18+
19+
[JsonProperty("bucket_id")]
20+
public string? BucketId { get; set; }
21+
22+
[JsonProperty("updated_at")]
23+
public DateTime? UpdatedAt { get; set; }
24+
25+
[JsonProperty("created_at")]
26+
public DateTime? CreatedAt { get; set; }
27+
28+
[JsonProperty("last_accessed_at")]
29+
public DateTime? LastAccessedAt { get; set; }
30+
31+
[JsonProperty("size")]
32+
public int? Size { get; set; }
33+
34+
[JsonProperty("cache_control")]
35+
public string? CacheControl { get; set; }
36+
37+
[JsonProperty("content_type")]
38+
public string? ContentType { get; set; }
39+
40+
[JsonProperty("etag")]
41+
public string? Etag { get; set; }
42+
43+
[JsonProperty("last_modified")]
44+
public DateTime? LastModified { get; set; }
45+
46+
[JsonProperty("metadata")]
47+
public Dictionary<string, string>? Metadata { get; set; }
48+
}
49+
}

Storage/FileOptions.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Newtonsoft.Json;
1+
using System.Collections.Generic;
2+
using Newtonsoft.Json;
23

34
namespace Supabase.Storage
45
{
@@ -12,5 +13,14 @@ public class FileOptions
1213

1314
[JsonProperty("upsert")]
1415
public bool Upsert { get; set; }
16+
17+
[JsonProperty("duplex")]
18+
public string? Duplex { get; set; }
19+
20+
[JsonProperty("metadata")]
21+
public Dictionary<string, string>? Metadata { get; set; }
22+
23+
[JsonProperty("headers")]
24+
public Dictionary<string, string>? Headers { get; set; }
1525
}
1626
}

Storage/Interfaces/IStorageFileApi.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public interface IStorageFileApi<TFileObject>
1818
Task<string> DownloadPublicFile(string supabasePath, string localPath, TransformOptions? transformOptions = null, EventHandler<float>? onProgress = null);
1919
string GetPublicUrl(string path, TransformOptions? transformOptions = null, DownloadOptions? options = null);
2020
Task<List<TFileObject>?> List(string path = "", SearchOptions? options = null);
21+
Task<FileObjectV2?> Info(string path);
2122
Task<bool> Move(string fromPath, string toPath, DestinationOptions? options = null);
2223
Task<bool> Copy(string fromPath, string toPath, DestinationOptions? options = null);
2324
Task<TFileObject?> Remove(string path);

Storage/StorageFileApi.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,19 @@ await Helpers.MakeRequest<List<FileObject>>(HttpMethod.Post, $"{Url}/object/list
148148

149149
return response;
150150
}
151+
152+
/// <summary>
153+
/// Retrieves the details of an existing file.
154+
/// </summary>
155+
/// <param name="path"></param>
156+
/// <returns></returns>
157+
public async Task<FileObjectV2?> Info(string path)
158+
{
159+
var response =
160+
await Helpers.MakeRequest<FileObjectV2>(HttpMethod.Get, $"{Url}/object/info/{BucketId}/{path}", null, Headers);
161+
162+
return response;
163+
}
151164

152165
/// <summary>
153166
/// Uploads a file to an existing bucket.
@@ -480,6 +493,14 @@ private async Task<string> UploadOrUpdate(string localPath, string supabasePath,
480493
if (options.Upsert)
481494
headers.Add("x-upsert", options.Upsert.ToString().ToLower());
482495

496+
if (options.Metadata != null)
497+
headers.Add("x-metadata", ParseMetadata(options.Metadata));
498+
499+
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));
500+
501+
if (options.Duplex != null)
502+
headers.Add("x-duplex", options.Duplex.ToLower());
503+
483504
var progress = new Progress<float>();
484505

485506
if (onProgress != null)
@@ -490,6 +511,14 @@ private async Task<string> UploadOrUpdate(string localPath, string supabasePath,
490511
return GetFinalPath(supabasePath);
491512
}
492513

514+
private static string ParseMetadata(Dictionary<string, string> metadata)
515+
{
516+
var json = JsonConvert.SerializeObject(metadata);
517+
var base64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(json));
518+
519+
return base64;
520+
}
521+
493522
private async Task<string> UploadOrUpdate(byte[] data, string supabasePath, FileOptions options,
494523
EventHandler<float>? onProgress = null)
495524
{
@@ -504,6 +533,14 @@ private async Task<string> UploadOrUpdate(byte[] data, string supabasePath, File
504533
if (options.Upsert)
505534
headers.Add("x-upsert", options.Upsert.ToString().ToLower());
506535

536+
if (options.Metadata != null)
537+
headers.Add("x-metadata", ParseMetadata(options.Metadata));
538+
539+
options.Headers?.ToList().ForEach(x => headers.Add(x.Key, x.Value));
540+
541+
if (options.Duplex != null)
542+
headers.Add("x-duplex", options.Duplex.ToLower());
543+
507544
var progress = new Progress<float>();
508545

509546
if (onProgress != null)

StorageTests/StorageFileTests.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.VisualStudio.TestTools.UnitTesting;
88
using Supabase.Storage;
99
using Supabase.Storage.Interfaces;
10+
using FileOptions = Supabase.Storage.FileOptions;
1011

1112
namespace StorageTests;
1213

@@ -75,6 +76,51 @@ public async Task UploadFile()
7576

7677
await _bucket.Remove(new List<string> { name });
7778
}
79+
80+
[TestMethod("File: Upload File With FileOptions")]
81+
public async Task UploadFileWithFileOptions()
82+
{
83+
var didTriggerProgress = new TaskCompletionSource<bool>();
84+
85+
var asset = "supabase-csharp.png";
86+
var name = $"{Guid.NewGuid()}.png";
87+
var basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)?.Replace("file:", "");
88+
89+
Assert.IsNotNull(basePath);
90+
91+
var imagePath = Path.Combine(basePath, "Assets", asset);
92+
93+
var metadata = new Dictionary<string, string>
94+
{
95+
["custom"] = "metadata",
96+
["local_file"] = "local_file"
97+
};
98+
99+
var headers = new Dictionary<string, string>
100+
{
101+
["x-version"] = "123"
102+
};
103+
104+
var options = new FileOptions
105+
{
106+
Duplex = "duplex",
107+
Metadata = metadata,
108+
Headers = headers,
109+
};
110+
await _bucket.Upload(imagePath, name, options, (_, _) => { didTriggerProgress.TrySetResult(true); });
111+
112+
var item = await _bucket.Info(name);
113+
114+
Assert.IsNotNull(item);
115+
Assert.IsNotNull(item.Metadata);
116+
Assert.AreEqual(metadata["custom"], item.Metadata["custom"]);
117+
Assert.AreEqual(metadata["local_file"], item.Metadata["local_file"]);
118+
119+
var sentProgressEvent = await didTriggerProgress.Task;
120+
Assert.IsTrue(sentProgressEvent);
121+
122+
await _bucket.Remove([name]);
123+
}
78124

79125
[TestMethod("File: Upload Arbitrary Byte Array")]
80126
public async Task UploadArbitraryByteArray()
@@ -192,7 +238,7 @@ public async Task CopyToAnotherBucket()
192238
foreach (var file in copied)
193239
{
194240
if (file.Name is not null)
195-
await localBucket.Remove(new List<string> { file.Name });
241+
await localBucket.Remove([file.Name]);
196242
}
197243

198244
await Storage.DeleteBucket("copyfile");

0 commit comments

Comments
 (0)