mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-23 19:27:51 -04:00
chore: clean diagnostics and prepare for designer structural refactor (stub legacy useActiveStudy)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { randomUUID } from "crypto";
|
||||
import { and, asc, count, desc, eq, inArray } from "drizzle-orm";
|
||||
import { and, asc, count, desc, eq, inArray, sql } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
experimentStatusEnum,
|
||||
robots,
|
||||
steps,
|
||||
trials,
|
||||
stepTypeEnum,
|
||||
studyMembers,
|
||||
userSystemRoles,
|
||||
@@ -124,11 +125,64 @@ export const experimentsRouter = createTRPCRouter({
|
||||
orderBy: [desc(experiments.updatedAt)],
|
||||
});
|
||||
|
||||
return experimentsList.map((exp) => ({
|
||||
...exp,
|
||||
stepCount: exp.steps.length,
|
||||
trialCount: exp.trials.length,
|
||||
}));
|
||||
// Aggregate action counts & latest trial activity (single pass merges)
|
||||
const experimentIds = experimentsList.map((e) => e.id);
|
||||
|
||||
const actionCountMap = new Map<string, number>();
|
||||
const latestTrialActivityMap = new Map<string, Date>();
|
||||
|
||||
if (experimentIds.length > 0) {
|
||||
// Action counts (join actions -> steps -> experiments)
|
||||
const actionCounts = await ctx.db
|
||||
.select({
|
||||
experimentId: steps.experimentId,
|
||||
count: count(),
|
||||
})
|
||||
.from(actions)
|
||||
.innerJoin(steps, eq(actions.stepId, steps.id))
|
||||
.where(inArray(steps.experimentId, experimentIds))
|
||||
.groupBy(steps.experimentId);
|
||||
|
||||
actionCounts.forEach((row) =>
|
||||
actionCountMap.set(row.experimentId, Number(row.count) || 0),
|
||||
);
|
||||
|
||||
// Latest trial activity (max of trial started/completed/created timestamps)
|
||||
const trialActivity = await ctx.db
|
||||
.select({
|
||||
experimentId: trials.experimentId,
|
||||
latest: sql`max(GREATEST(
|
||||
COALESCE(${trials.completedAt}, 'epoch'::timestamptz),
|
||||
COALESCE(${trials.startedAt}, 'epoch'::timestamptz),
|
||||
COALESCE(${trials.createdAt}, 'epoch'::timestamptz)
|
||||
))`.as("latest"),
|
||||
})
|
||||
.from(trials)
|
||||
.where(inArray(trials.experimentId, experimentIds))
|
||||
.groupBy(trials.experimentId);
|
||||
|
||||
trialActivity.forEach((row) => {
|
||||
if (row.latest) {
|
||||
latestTrialActivityMap.set(row.experimentId, row.latest as Date);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return experimentsList.map((exp) => {
|
||||
const trialLatest = latestTrialActivityMap.get(exp.id);
|
||||
const latestActivityAt =
|
||||
trialLatest && trialLatest > exp.updatedAt
|
||||
? trialLatest
|
||||
: exp.updatedAt;
|
||||
|
||||
return {
|
||||
...exp,
|
||||
stepCount: exp.steps.length,
|
||||
trialCount: exp.trials.length,
|
||||
actionCount: actionCountMap.get(exp.id) ?? 0,
|
||||
latestActivityAt,
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
getUserExperiments: protectedProcedure
|
||||
|
||||
@@ -22,6 +22,8 @@ import {
|
||||
trials,
|
||||
trialStatusEnum,
|
||||
wizardInterventions,
|
||||
mediaCaptures,
|
||||
users,
|
||||
} from "~/server/db/schema";
|
||||
|
||||
// Helper function to check if user has access to trial
|
||||
@@ -113,6 +115,8 @@ export const trialsRouter = createTRPCRouter({
|
||||
participantId: trials.participantId,
|
||||
experimentId: trials.experimentId,
|
||||
status: trials.status,
|
||||
sessionNumber: trials.sessionNumber,
|
||||
scheduledAt: trials.scheduledAt,
|
||||
startedAt: trials.startedAt,
|
||||
completedAt: trials.completedAt,
|
||||
duration: trials.duration,
|
||||
@@ -128,11 +132,17 @@ export const trialsRouter = createTRPCRouter({
|
||||
id: participants.id,
|
||||
participantCode: participants.participantCode,
|
||||
},
|
||||
wizard: {
|
||||
id: users.id,
|
||||
name: users.name,
|
||||
email: users.email,
|
||||
},
|
||||
userRole: studyMembers.role,
|
||||
})
|
||||
.from(trials)
|
||||
.innerJoin(experiments, eq(trials.experimentId, experiments.id))
|
||||
.innerJoin(participants, eq(trials.participantId, participants.id))
|
||||
.leftJoin(users, eq(users.id, trials.wizardId))
|
||||
.innerJoin(studyMembers, eq(studyMembers.studyId, experiments.studyId))
|
||||
.where(and(eq(studyMembers.userId, userId), ...conditions))
|
||||
.orderBy(desc(trials.createdAt))
|
||||
@@ -141,9 +151,52 @@ export const trialsRouter = createTRPCRouter({
|
||||
|
||||
const results = await query;
|
||||
|
||||
// Add permission flags for each trial
|
||||
// Aggregate event & media counts (batched)
|
||||
const trialIds = results.map((r) => r.id);
|
||||
const eventCountMap = new Map<string, number>();
|
||||
const mediaCountMap = new Map<string, number>();
|
||||
const latestEventAtMap = new Map<string, Date>();
|
||||
// Hoisted map for latest event timestamps so it is in scope after aggregation block
|
||||
// (removed redeclaration of latestEventAtMap; now hoisted above)
|
||||
|
||||
if (trialIds.length > 0) {
|
||||
const eventCounts = await db
|
||||
.select({
|
||||
trialId: trialEvents.trialId,
|
||||
count: count(),
|
||||
latest: sql`max(${trialEvents.timestamp})`.as("latest"),
|
||||
})
|
||||
.from(trialEvents)
|
||||
.where(inArray(trialEvents.trialId, trialIds))
|
||||
.groupBy(trialEvents.trialId);
|
||||
|
||||
eventCounts.forEach((ec) => {
|
||||
eventCountMap.set(ec.trialId, Number(ec.count) || 0);
|
||||
if (ec.latest) {
|
||||
latestEventAtMap.set(ec.trialId, ec.latest as Date);
|
||||
}
|
||||
});
|
||||
|
||||
const mediaCounts = await db
|
||||
.select({
|
||||
trialId: mediaCaptures.trialId,
|
||||
count: count(),
|
||||
})
|
||||
.from(mediaCaptures)
|
||||
.where(inArray(mediaCaptures.trialId, trialIds))
|
||||
.groupBy(mediaCaptures.trialId);
|
||||
|
||||
mediaCounts.forEach((mc) => {
|
||||
mediaCountMap.set(mc.trialId, Number(mc.count) || 0);
|
||||
});
|
||||
}
|
||||
|
||||
// Add permission flags & counts
|
||||
return results.map((trial) => ({
|
||||
...trial,
|
||||
eventCount: eventCountMap.get(trial.id) ?? 0,
|
||||
mediaCount: mediaCountMap.get(trial.id) ?? 0,
|
||||
latestEventAt: latestEventAtMap.get(trial.id) ?? null,
|
||||
canAccess: ["owner", "researcher", "wizard"].includes(trial.userRole),
|
||||
}));
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user