refactor[db]: store time as unix ms

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2025-10-03 21:23:51 +00:00
parent 1d8a117b93
commit 0e686a1f85
11 changed files with 132 additions and 15 deletions

90
packages/convex/README.md Normal file
View File

@@ -0,0 +1,90 @@
# Welcome to your Convex functions directory!
Write your Convex functions here.
See https://docs.convex.dev/functions for more.
A query function that takes two arguments looks like:
```ts
// convex/myFunctions.ts
import { query } from "./_generated/server";
import { v } from "convex/values";
export const myQueryFunction = query({
// Validators for arguments.
args: {
first: v.number(),
second: v.string(),
},
// Function implementation.
handler: async (ctx, args) => {
// Read the database as many times as you need here.
// See https://docs.convex.dev/database/reading-data.
const documents = await ctx.db.query("tablename").collect();
// Arguments passed from the client are properties of the args object.
console.log(args.first, args.second);
// Write arbitrary JavaScript here: filter, aggregate, build derived data,
// remove non-public properties, or create new objects.
return documents;
},
});
```
Using this query function in a React component looks like:
```ts
const data = useQuery(api.myFunctions.myQueryFunction, {
first: 10,
second: "hello",
});
```
A mutation function looks like:
```ts
// convex/myFunctions.ts
import { mutation } from "./_generated/server";
import { v } from "convex/values";
export const myMutationFunction = mutation({
// Validators for arguments.
args: {
first: v.string(),
second: v.string(),
},
// Function implementation.
handler: async (ctx, args) => {
// Insert or modify documents in the database here.
// Mutations can also read from the database like queries.
// See https://docs.convex.dev/database/writing-data.
const message = { body: args.first, author: args.second };
const id = await ctx.db.insert("messages", message);
// Optionally, return a value from your mutation.
return await ctx.db.get(id);
},
});
```
Using this mutation function in a React component looks like:
```ts
const mutation = useMutation(api.myFunctions.myMutationFunction);
function handleButtonPress() {
// fire and forget, the most common way to use mutations
mutation({ first: "Hello!", second: "me" });
// OR
// use the result once the mutation has completed
mutation({ first: "Hello!", second: "me" }).then((result) =>
console.log(result),
);
}
```
Use the Convex CLI to push your functions to a deployment. See everything
the Convex CLI can do by running `npx convex -h` in your project root
directory. To learn more, launch the docs with `npx convex docs`.

View File

@@ -13,6 +13,7 @@ import type {
FilterApi,
FunctionReference,
} from "convex/server";
import type * as admin from "../admin.js";
import type * as files from "../files.js";
import type * as filesystem from "../filesystem.js";
import type * as functions from "../functions.js";
@@ -32,6 +33,7 @@ import type * as users from "../users.js";
* ```
*/
declare const fullApi: ApiFromModules<{
admin: typeof admin;
files: typeof files;
filesystem: typeof filesystem;
functions: typeof functions;

View File

@@ -81,7 +81,7 @@ export const saveFile = authenticatedMutation({
mimeType: v.optional(v.string()),
},
handler: async (ctx, { name, storageId, directoryId, size, mimeType }) => {
const now = new Date().toISOString()
const now = Date.now()
await ctx.db.insert("files", {
name,

View File

@@ -70,7 +70,7 @@ export const moveToTrash = authenticatedMutation({
case FileType.File:
return ctx.db
.patch(handle.id, {
deletedAt: new Date().toISOString(),
deletedAt: Date.now(),
})
.then(() => handle)
case FileType.Directory:

View File

@@ -144,7 +144,7 @@ export async function create(
)
}
const now = new Date().toISOString()
const now = Date.now()
return await ctx.db.insert("directories", {
name,
parentId,
@@ -216,7 +216,7 @@ export async function move(
ignoredHandles.add(handle)
} else {
promises.push(
ctx.db.patch(handle.id, { parentId: targetDirectory.id }),
ctx.db.patch(handle.id, { parentId: targetDirectory.id, updatedAt: Date.now() }),
)
}
}
@@ -239,7 +239,7 @@ export async function moveToTrashRecursive(
ctx: AuthenticatedMutationCtx,
handle: DirectoryHandle,
): Promise<void> {
const now = new Date().toISOString()
const now = Date.now()
const filesToDelete: Id<"files">[] = []
const directoriesToDelete: Id<"directories">[] = []

View File

@@ -33,7 +33,7 @@ export async function renameFile(
)
}
await ctx.db.patch(itemId, { name: newName })
await ctx.db.patch(itemId, { name: newName, updatedAt: Date.now() })
}
export async function move(
@@ -90,7 +90,7 @@ export async function move(
const results = await Promise.allSettled(
okFiles.map((handle) =>
ctx.db.patch(handle.id, { directoryId: targetDirectoryHandle.id }),
ctx.db.patch(handle.id, { directoryId: targetDirectoryHandle.id, updatedAt: Date.now() }),
),
)

View File

@@ -39,7 +39,7 @@ export async function userOrThrow(ctx: QueryCtx | MutationCtx) {
}
export async function register(ctx: AuthenticatedMutationCtx) {
const now = new Date().toISOString()
const now = Date.now()
await Promise.all([
ctx.db.insert("users", {
jwtSubject: ctx.identity.subject,

View File

@@ -12,9 +12,9 @@ const schema = defineSchema({
name: v.string(),
size: v.number(),
mimeType: v.optional(v.string()),
createdAt: v.string(),
updatedAt: v.string(),
deletedAt: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
deletedAt: v.optional(v.number()),
})
.index("byDirectoryId", ["userId", "directoryId", "deletedAt"])
.index("byUserId", ["userId", "deletedAt"])
@@ -29,9 +29,9 @@ const schema = defineSchema({
name: v.string(),
userId: v.id("users"),
parentId: v.optional(v.id("directories")),
createdAt: v.string(),
updatedAt: v.string(),
deletedAt: v.optional(v.string()),
createdAt: v.number(),
updatedAt: v.number(),
deletedAt: v.optional(v.number()),
})
.index("byUserId", ["userId", "deletedAt"])
.index("byParentId", ["userId", "parentId", "deletedAt"])

View File

@@ -0,0 +1,25 @@
{
/* This TypeScript project config describes the environment that
* Convex functions run in and is used to typecheck them.
* You can modify it, but some settings are required to use Convex.
*/
"compilerOptions": {
/* These settings are not required by Convex and can be modified. */
"allowJs": true,
"strict": true,
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
/* These compiler options are required by Convex */
"target": "ESNext",
"lib": ["ES2021", "dom"],
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"isolatedModules": true,
"noEmit": true
},
"include": ["./**/*"],
"exclude": ["./_generated"]
}

View File

@@ -19,7 +19,6 @@ function RouteComponent() {
useEffect(() => {
if (!isLoadingConvexAuth && isAuthenticated && !isSyncingUser) {
console.log({ isLoadingConvexAuth, isAuthenticated, isSyncingUser })
syncUser(undefined, {
onSuccess: () => {
navigate({