Skip to content

Commit

Permalink
feat: copyFile/copyFolder methods
Browse files Browse the repository at this point in the history
  • Loading branch information
nzakas committed Jun 20, 2024
1 parent c3b1a8b commit a8b7ee8
Show file tree
Hide file tree
Showing 3 changed files with 406 additions and 3 deletions.
87 changes: 87 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,50 @@ console.log(file);

**Note:** When `parentId` is omitted, the root folder is used.

### Copying Files

```js
const store = new ObjectStore();
const file = store.createFile("foo.txt", { content: "Foo", parentId: "folder_id" });
const copiedFile = store.copyFile(file.id, { parentId: "some_other_folder_id", name: "bar.txt"});
console.log(copiedFile);
/*
{
id: "copy-file-id",
name: "bar.txt",
type: "file",
parent_id: "some_other_folder_id",
created_at: "2022-10-20T12:00:00Z",
modified_at: "2022-10-20T12:00:00Z"
}
*/
```

**Note:** `name` is optional. When `parentId` is not specified, the ID of the original's parent is used.

### Moving/Renaming Files

```js
const store = new ObjectStore();
const file = store.createFile("foo.txt", { content: "Foo", parentId: "folder_id" });
const updatedFile = store.updateFile(file.id, { parentId: "some_other_folder_id", name: "bar.txt"});
console.log(updatedFile);
/*
{
id: "file-id",
name: "bar.txt",
type: "file",
parent_id: "some_other_folder_id",
created_at: "2022-10-20T12:00:00Z",
modified_at: "2022-10-20T12:00:00Z"
}
*/
```

**Note:** Both `name` and `parentId` are optional.



### Retrieving Files

```js
Expand Down Expand Up @@ -139,6 +183,7 @@ store.deleteFile(file.id);
```

### Creating Folders

```js
const store = new ObjectStore();
const folder = store.createFolder("my-folder", { parentId: "parent_folder_id" });
Expand All @@ -158,6 +203,48 @@ console.log(folder);

**Note:** When `parentId` is omitted, the root folder is used.

### Copying Folders

```js
const store = new ObjectStore();
const folder = store.createFolder("my-folder", { parentId: "parent_folder_id" });
const copiedFolder = store.copyFolder(folder.id, { parentId: "some_other_folder_id", name: "my-folder-copy"});
console.log(copiedFolder);
/*
{
id: "folder_copy_id",
name: "my-folder-copy",
type: "folder",
parent_id: "some_other_folder_id",
created_at: "2022-10-20T12:00:00Z",
modified_at: "2022-10-20T12:00:00Z",
entries: []
}
*/
```

**Note:** `name` is optional. When `parentId` is not specified, the ID of the original's parent is used.

### Moving/Renaming Folders

```js
const store = new ObjectStore();
const folder = store.createFolder("my-folder", { parentId: "parent_folder_id" });
const updatedFolder = store.updateFolder(file.id, { parentId: "some_other_folder_id", name: "my-new-name"});
console.log(updatedFolder);
/*
{
id: "folder_id",
name: "my-new-name",
type: "folder",
parent_id: "some_other_folder_id",
created_at: "2022-10-20T12:00:00Z",
modified_at: "2022-10-20T12:00:00Z",
entries: []
}
*/
```

### Deleting Folders

```js
Expand Down
107 changes: 104 additions & 3 deletions src/object-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ class Entry {
this.modifiedAt = new Date();
}

/**
* The parent folder of the entry.
* @type {Folder|undefined}
*/
get parent() {
return this.store.getParent(this.id);
}

/**
* Converts the entry to a JSON object.
* @returns {Object} The JSON object representing the entry.
Expand All @@ -99,7 +107,7 @@ class Entry {
id: this.id,
name: this.name,
type: this.type,
parent_id: this.store.getParent(this.id)?.id,
parent_id: this.parent?.id,
created_at: this.createdAt.toISOString(),
modified_at: this.modifiedAt.toISOString(),
};
Expand Down Expand Up @@ -331,7 +339,7 @@ export class ObjectStore {
* @param {Object} [options] Additional options.
* @param {string} [options.parentId] The ID of the parent folder.
* @param {string|ArrayBuffer|undefined} [options.content] The content of the file.
* @returns {string} The ID of the file.
* @returns {Object} The file object.
* @throws {Error} If the parent is not found or is not a folder.
*/
createFile(name, { parentId = this.#root.id, content } = {}) {
Expand All @@ -352,6 +360,45 @@ export class ObjectStore {
return file.toJSON();
}

/**
* Copies a file to a new location, optionally renaming it.
* @param {string} id The ID of the file to copy.
* @param {Object} options The options to copy the file.
* @param {string} [options.name] The new name of the file.
* @param {string} [options.parentId] The ID of the new parent folder.
* @returns {Object} The file object.
* @throws {Error} If the file is not found.
* @throws {Error} If the file is not a file.
* @throws {Error} If the parent is not found or is not a folder.
*/
copyFile(id, { name, parentId } = {}) {
const file = this.#objects.get(id);

if (!file) {
throw new TypeError(`File "${id}" not found.`);
}

if (file.type !== "file") {
throw new TypeError("Not a file.");
}

const parent = this.#objects.get(parentId ?? file.parent.id);

if (!parent) {
throw new TypeError("Parent not found.");
}

if (parent.type !== "folder") {
throw new TypeError("Parent is not a folder.");
}

const content = /** @type {File} */ (file).content;
return this.createFile(name ?? file.name, {
parentId: parent.id,
content,
});
}

/**
* Gets the file record.
* @param {string} id The ID of the file.
Expand Down Expand Up @@ -472,7 +519,7 @@ export class ObjectStore {
* @param {string} name The name of the folder.
* @param {Object} [options] Additional options.
* @param {string} [options.parentId] The ID of the parent folder.
* @returns {string} The ID of the folder.
* @returns {Object} The folder object.
* @throws {Error} If the parent is not found or is not a folder.
*/
createFolder(name, { parentId = this.#root.id } = {}) {
Expand All @@ -493,6 +540,60 @@ export class ObjectStore {
return folder.toJSON();
}

/**
* Copies a folder to a new location, optionally renaming it.
* @param {string} id The ID of the folder to copy.
* @param {Object} options The options to copy the folder.
* @param {string} [options.name] The new name of the folder.
* @param {string} [options.parentId] The ID of the new parent folder.
* @returns {Object} The folder object.
* @throws {Error} If the folder is not found.
* @throws {Error} If the folder is not a folder.
* @throws {Error} If the parent is not found or is not a folder.
* @throws {Error} If the parent is the same as the folder.
*/
copyFolder(id, { name, parentId } = {}) {
const folder = /** @type {Folder} */ (this.#objects.get(id));

if (!folder) {
throw new TypeError(`Folder "${id}" not found.`);
}

if (folder.type !== "folder") {
throw new TypeError("Not a folder.");
}

const parent = this.#objects.get(parentId ?? folder.parent.id);

if (!parent) {
throw new TypeError("Parent not found.");
}

if (parent.type !== "folder") {
throw new TypeError("Parent is not a folder.");
}

if (folder.id === parent.id) {
throw new TypeError("Cannot copy a folder into itself.");
}

// first create the folder copy
const newFolder = this.createFolder(name ?? folder.name, {
parentId: parent.id,
});

// then copy all the entries
for (const entry of folder.entries()) {
if (entry.type === "folder") {
this.copyFolder(entry.id, { parentId: newFolder.id });
} else {
this.copyFile(entry.id, { parentId: newFolder.id });
}
}

return this.getFolder(newFolder.id);
}

/**
* Gets the folder record.
* @param {string} id The ID of the folder.
Expand Down
Loading

0 comments on commit a8b7ee8

Please sign in to comment.