4
convex/_generated/api.d.ts
vendored
4
convex/_generated/api.d.ts
vendored
@@ -15,7 +15,7 @@ import type {
|
||||
} from "convex/server";
|
||||
import type * as files from "../files.js";
|
||||
import type * as model_directories from "../model/directories.js";
|
||||
import type * as model_files from "../model/files.js";
|
||||
import type * as model_error from "../model/error.js";
|
||||
import type * as users from "../users.js";
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ import type * as users from "../users.js";
|
||||
declare const fullApi: ApiFromModules<{
|
||||
files: typeof files;
|
||||
"model/directories": typeof model_directories;
|
||||
"model/files": typeof model_files;
|
||||
"model/error": typeof model_error;
|
||||
users: typeof users;
|
||||
}>;
|
||||
export declare const api: FilterApi<
|
||||
|
@@ -65,12 +65,24 @@ export const saveFile = mutation({
|
||||
|
||||
export const moveToTrash = mutation({
|
||||
args: {
|
||||
kind: v.union(v.literal("file"), v.literal("directory")),
|
||||
itemId: v.union(v.id("files"), v.id("directories")),
|
||||
},
|
||||
handler: async (ctx, { itemId }) => {
|
||||
await ctx.db.patch(itemId, {
|
||||
deletedAt: new Date().toISOString(),
|
||||
})
|
||||
handler: async (ctx, { itemId, kind }) => {
|
||||
switch (kind) {
|
||||
case "file":
|
||||
await ctx.db.patch(itemId, {
|
||||
deletedAt: new Date().toISOString(),
|
||||
})
|
||||
break
|
||||
case "directory":
|
||||
await Directories.moveToTrashRecursive(
|
||||
ctx,
|
||||
itemId as Id<"directories">,
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
return itemId
|
||||
},
|
||||
})
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import type { Doc, Id } from "@convex/_generated/dataModel"
|
||||
import type { MutationCtx, QueryCtx } from "@convex/_generated/server"
|
||||
import * as Err from "./error"
|
||||
|
||||
type Directory = {
|
||||
kind: "directory"
|
||||
@@ -28,6 +29,7 @@ export async function fetchContent(
|
||||
ctx.db
|
||||
.query("directories")
|
||||
.withIndex("byParentId", (q) => q.eq("parentId", directoryId))
|
||||
.filter((q) => q.eq(q.field("deletedAt"), undefined))
|
||||
.collect(),
|
||||
])
|
||||
|
||||
@@ -46,6 +48,20 @@ export async function create(
|
||||
ctx: MutationCtx,
|
||||
{ name, parentId }: { name: string; parentId?: Id<"directories"> },
|
||||
): Promise<Id<"directories">> {
|
||||
const existing = await ctx.db
|
||||
.query("directories")
|
||||
.withIndex("uniqueDirectoryInDirectory", (q) =>
|
||||
q.eq("parentId", parentId).eq("name", name),
|
||||
)
|
||||
.first()
|
||||
|
||||
if (existing) {
|
||||
throw Err.create(
|
||||
Err.Code.DirectoryExists,
|
||||
`Directory with name ${name} already exists in ${parentId ? `directory ${parentId}` : "root"}`,
|
||||
)
|
||||
}
|
||||
|
||||
const now = new Date().toISOString()
|
||||
return await ctx.db.insert("directories", {
|
||||
name,
|
||||
@@ -54,3 +70,54 @@ export async function create(
|
||||
updatedAt: now,
|
||||
})
|
||||
}
|
||||
|
||||
export async function moveToTrashRecursive(
|
||||
ctx: MutationCtx,
|
||||
directoryId: Id<"directories">,
|
||||
): Promise<void> {
|
||||
const now = new Date().toISOString()
|
||||
|
||||
const filesToDelete: Id<"files">[] = []
|
||||
const directoriesToDelete: Id<"directories">[] = []
|
||||
|
||||
const directoryQueue: Id<"directories">[] = [directoryId]
|
||||
|
||||
while (directoryQueue.length > 0) {
|
||||
const currentDirectoryId = directoryQueue.shift()!
|
||||
directoriesToDelete.push(currentDirectoryId)
|
||||
|
||||
const files = await ctx.db
|
||||
.query("files")
|
||||
.withIndex("byDirectoryId", (q) =>
|
||||
q
|
||||
.eq("directoryId", currentDirectoryId)
|
||||
.eq("deletedAt", undefined),
|
||||
)
|
||||
.collect()
|
||||
|
||||
for (const file of files) {
|
||||
filesToDelete.push(file._id)
|
||||
}
|
||||
|
||||
const subdirectories = await ctx.db
|
||||
.query("directories")
|
||||
.withIndex("byParentId", (q) =>
|
||||
q.eq("parentId", currentDirectoryId).eq("deletedAt", undefined),
|
||||
)
|
||||
.collect()
|
||||
|
||||
for (const subdirectory of subdirectories) {
|
||||
directoryQueue.push(subdirectory._id)
|
||||
}
|
||||
}
|
||||
|
||||
const filePatches = filesToDelete.map((fileId) =>
|
||||
ctx.db.patch(fileId, { deletedAt: now }),
|
||||
)
|
||||
|
||||
const directoryPatches = directoriesToDelete.map((dirId) =>
|
||||
ctx.db.patch(dirId, { deletedAt: now }),
|
||||
)
|
||||
|
||||
await Promise.all([...filePatches, ...directoryPatches])
|
||||
}
|
||||
|
24
convex/model/error.ts
Normal file
24
convex/model/error.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ConvexError } from "convex/values"
|
||||
|
||||
export enum Code {
|
||||
DirectoryExists = "DirectoryExists",
|
||||
FileExists = "FileExists",
|
||||
Internal = "Internal",
|
||||
}
|
||||
|
||||
export type ApplicationError = ConvexError<{ code: Code; message: string }>
|
||||
|
||||
export function isApplicationError(error: unknown): error is ApplicationError {
|
||||
return (
|
||||
error instanceof ConvexError &&
|
||||
"code" in error.data &&
|
||||
"message" in error.data
|
||||
)
|
||||
}
|
||||
|
||||
export function create(code: Code, message: string = "unknown error") {
|
||||
return new ConvexError({
|
||||
code,
|
||||
message,
|
||||
})
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
import { v } from "convex/values"
|
||||
import { mutation } from "../_generated/server"
|
||||
|
||||
export const moveToTrash = mutation({
|
||||
args: {
|
||||
fileId: v.id("files"),
|
||||
},
|
||||
handler: async (ctx, { fileId }) => {
|
||||
await ctx.db.patch(fileId, {
|
||||
deletedAt: new Date().toISOString(),
|
||||
})
|
||||
},
|
||||
})
|
@@ -19,13 +19,17 @@ const schema = defineSchema({
|
||||
deletedAt: v.optional(v.string()),
|
||||
})
|
||||
.index("byDirectoryId", ["directoryId", "deletedAt"])
|
||||
.index("byDeletedAt", ["deletedAt"]),
|
||||
.index("byDeletedAt", ["deletedAt"])
|
||||
.index("uniqueFileInDirectory", ["directoryId", "name", "deletedAt"]),
|
||||
directories: defineTable({
|
||||
name: v.string(),
|
||||
parentId: v.optional(v.id("directories")),
|
||||
createdAt: v.string(),
|
||||
updatedAt: v.string(),
|
||||
}).index("byParentId", ["parentId"]),
|
||||
deletedAt: v.optional(v.string()),
|
||||
})
|
||||
.index("byParentId", ["parentId", "deletedAt"])
|
||||
.index("uniqueDirectoryInDirectory", ["parentId", "name", "deletedAt"]),
|
||||
})
|
||||
|
||||
export default schema
|
||||
|
Reference in New Issue
Block a user