Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/filesystem/googledrive/googledrive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,38 @@ describe("GoogleDriveFileSystem", () => {

await expect(fs.delete("missing.txt")).resolves.toBeUndefined();
});

it("ensureDirExists should create missing nested directories and return final id", async () => {
const fs = new GoogleDriveFileSystem("/", "token");
const findSpy = vi.spyOn(fs, "findFolderByName").mockResolvedValue(null);
const createSpy = vi
.spyOn(fs, "createFolder")
.mockResolvedValueOnce({ id: "id-A", name: "A" })
.mockResolvedValueOnce({ id: "id-B", name: "B" });

await expect(fs.ensureDirExists("/A/B")).resolves.toBe("id-B");

expect(findSpy.mock.calls).toEqual([
["A", "appDataFolder"],
["B", "id-A"],
]);
expect(createSpy.mock.calls).toEqual([
["A", "appDataFolder"],
["B", "id-A"],
]);
});

it("writer should ensure directory from root when filesystem is opened in subdir", async () => {
const fs = new GoogleDriveFileSystem("/Base", "token");
const writer = await fs.create("file.txt");
const ensureSpy = vi.spyOn(fs, "ensureDirExists").mockResolvedValue("base-id");
const findSpy = vi.spyOn(fs, "findFileInDirectory").mockResolvedValue(null);
const requestSpy = vi.spyOn(fs, "request").mockResolvedValue({});

await expect(writer.write("content")).resolves.toBeUndefined();

expect(ensureSpy).toHaveBeenCalledWith("/Base");
expect(findSpy).toHaveBeenCalledWith("file.txt", "base-id");
expect(requestSpy).toHaveBeenCalledTimes(1);
});
});
30 changes: 10 additions & 20 deletions packages/filesystem/googledrive/googledrive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ export default class GoogleDriveFileSystem implements FileSystem {
}

const fullPath = joinPath(this.path, dir);
await this.ensureDirPath(fullPath);
}

private async ensureDirPath(fullPath: string): Promise<string> {
if (fullPath === "/" || fullPath === "") {
return "appDataFolder";
}

const dirs = fullPath.split("/").filter(Boolean);

// 从根目录开始逐级创建目录
Expand Down Expand Up @@ -69,7 +77,7 @@ export default class GoogleDriveFileSystem implements FileSystem {
parentId = folderId;
}

return Promise.resolve();
return parentId;
}
async findFolderByName(name: string, parentId: string): Promise<{ id: string; name: string } | null> {
const query = `name='${name}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents and trashed=false`;
Expand Down Expand Up @@ -315,24 +323,6 @@ export default class GoogleDriveFileSystem implements FileSystem {

// 确保目录存在并返回目录ID,优化Writer避免重复获取
async ensureDirExists(dirPath: string): Promise<string> {
if (dirPath === "/" || dirPath === "") {
return "appDataFolder";
}

// 先检查缓存
const cachedId = this.pathToIdCache.get(dirPath);
if (cachedId) {
return cachedId;
}

// 如果没有缓存,使用getFileId方法
const foundId = await this.getFileId(dirPath);
if (!foundId) {
throw new Error(`Failed to create or find directory: ${dirPath}`);
}

// 缓存结果
this.pathToIdCache.set(dirPath, foundId);
return foundId;
return this.ensureDirPath(dirPath);
}
}
Loading