-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
file-storage: List or remove multiple files with a common prefix #32
Comments
I've considered adding a |
For my R2 implementation of FileStorage and ended up extending it to add this I also thought that instead of returning that promise, it could return an AsyncIterator, I ended up using a Promise instead because usually you just get one page at the time, and not the whole list. |
|
|
You need to return not only the keys, but a cursor to let you start pagination from where you left. Unless you're showing all keys at once to users you don't want to list all of them at once and you will most likely need to resume pagination from where you left off. CF R2 gives you this cursor to let you keep asking for more keys. |
Would this API be sufficient, @sergiodxa ? interface FileStorage {
keys(cursor?: string): Promise<{ cursor?: string; keys: string[] }>
} In the return value, if you have a A function that reads all keys could look like: async function readKeys(storage: FileStorage): Promise<string[]> {
let keys: string[] = []
let result = await storage.keys();
keys.push(...result.keys);
while (result.cursor != null) {
result = await storage.keys(result.cursor);
keys.push(...result.keys);
}
return keys
} |
Yes, that's similar to what I did myself, I also sent a |
I wonder what type the cursor should be in storages whose structures are completely different from S3. Could it be number, bigint, or structure types, or should its type be a type parameter? The exposure of the cursor is not necessary for users, especially those of MemoryStorage and LocalFileStorage. You will be able to use https://github.com/tc39/proposal-async-iterator-helpers Lazy users can use The suggested API forces users to use the procedural manner (the while statement). Do MemoryStorage and LocalFileStorage prefer (Async)Iterator or AsyncIterator<Iterator> the most? |
Probably. I'd imagine interface FileStorage {
keys<T = string>(cursor?: T): Promise<{ cursor?: T; keys: string[] }>
}
I disagree. Imagine showing a web page with one page of keys, and a "Next page" button that will show the next page. In that case, users will need to have a cursor they can use to pass back in on the request for the next page of keys. |
I see. I think we might as well provide both kinds. |
If we want to keep the AsyncIterator interface there's an option to add a Symbol.asyncIterator property, that way the instance itself would be iterable. let fs = new MyFileStorage()
for await (let key of fs) {
// use key here
} So if you want to iterate the whole list you can use that instead, and if you need a paginated list of keys you can use |
There are some following cons, so it is not a good idea to force implementers to implement it, or to serve only the property without an additional equivalent function at least.
Naming suggestions:
AsyncIterator seems to be able to be calculated by objects with cursor, so now I think implementers have only to implement the function returning one with cursor. |
Once you accept multiple files at the same time as a draft, you can't clean up them without a database support in a draft preview page. You may want to clean up all files in stale drafts, too.
Common file systems can list or remove all files in a common group by
ls -R
orrm -rf
. Boto3 canlist_object
with a prefix up to 1000 at once. However, the current file-storage can't do it. You have to find out every name of the file you want to delete first before actually doing it.The text was updated successfully, but these errors were encountered: