Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Caching #446

Merged
merged 10 commits into from
Feb 17, 2025
Merged
18 changes: 12 additions & 6 deletions components/stats/Picklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {
const SHOW_PICKLISTS_ON_TEAM_CARDS = false;
const SHOW_CARD_IDS = false;

const api = new ClientApi();

function TeamCard(props: {
entry: PicklistEntry;
draggable: boolean;
Expand Down Expand Up @@ -297,8 +299,6 @@ export function TeamList(props: {
);
}

const api = new ClientApi();

export default function PicklistScreen(props: {
teams: number[];
reports: Report[];
Expand All @@ -321,10 +321,16 @@ export default function PicklistScreen(props: {
const teams = props.teams.map((team) => ({ number: team }));

// Save picklists
useEffect(
() => savePicklistGroup(props.picklist._id, picklists, strikethroughs, api),
[props.picklist._id, picklists, strikethroughs],
);
useEffect(() => {
if (loadingPicklists !== LoadState.Loaded) return;
savePicklistGroup(props.picklist._id, picklists, strikethroughs, api);
}, [
props.picklist._id,
picklists,
strikethroughs,
LoadState.Loaded,
loadingPicklists,
]);

const updatePicklist = useCallback(
(picklist: Picklist) => {
Expand Down
8 changes: 6 additions & 2 deletions lib/MongoDB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import DbInterface, {
WithStringOrObjectIdId,
} from "./client/dbinterfaces/DbInterface";
import { default as BaseMongoDbInterface } from "mongo-anywhere/MongoDbInterface";
import CachedDbInterface from "./client/dbinterfaces/CachedDbInterface";

if (!process.env.MONGODB_URI) {
// Necessary to allow connections from files running outside of Next
Expand All @@ -28,10 +29,13 @@ clientPromise = global.clientPromise;

export { clientPromise };

export async function getDatabase(): Promise<MongoDBInterface> {
export async function getDatabase(): Promise<DbInterface> {
if (!global.interface) {
await clientPromise;
const dbInterface = new MongoDBInterface(clientPromise);
const dbInterface = new CachedDbInterface(
new MongoDBInterface(clientPromise),
{ stdTTL: 120, useClones: false },
);
await dbInterface.init();
global.interface = dbInterface;

Expand Down
18 changes: 11 additions & 7 deletions lib/ResendUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Resend } from "resend";
import { getDatabase } from "./MongoDB";
import { User } from "./Types";
import CollectionId from "./client/CollectionId";
import { ObjectId } from "bson";

const resend = new Resend(process.env.SMTP_PASSWORD);

Expand Down Expand Up @@ -41,13 +42,16 @@ export class ResendUtils implements ResendInterface {
}

const db = await getDatabase();
// Going around our own interface is a red flag, but it's 11 PM and I'm tired -Renato
db.db
?.collection(CollectionId.Users)
.updateOne(
{ email: user.email },
{ $set: { resendContactId: res.data.id } },
);
const id = (await db.findObject(CollectionId.Users, { email: user.email }))
?._id;
if (!id) {
console.error("User not found in database", user.email);
return;
}

db.updateObjectById(CollectionId.Users, new ObjectId(id), {
resendContactId: res.data.id,
});
}

async emailDevelopers(subject: string, message: string) {
Expand Down
3 changes: 2 additions & 1 deletion lib/TheBlueAlliance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { NotLinkedToTba } from "./client/ClientUtils";
import { GameId, defaultGameId } from "./client/GameId";
import { games } from "./games";
import DbInterface from "./client/dbinterfaces/DbInterface";

export namespace TheBlueAlliance {
export interface SimpleTeam {
Expand Down Expand Up @@ -209,7 +210,7 @@ export namespace TheBlueAlliance {

export class Interface {
req: Request;
db: Promise<MongoDBInterface>;
db: Promise<DbInterface>;

competitionPairings: CompetitonNameIdPair[] = [];

Expand Down
28 changes: 28 additions & 0 deletions lib/api/ClientApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2303,4 +2303,32 @@ export default class ClientApi extends NextApiTemplate<ApiDependencies> {
res.status(200).send(responseObj);
},
});

getCacheStats = createNextRoute<
[],
object | undefined,
ApiDependencies,
void
>({
isAuthorized: AccessLevels.IfDeveloper,
handler: async (req, res, {}, authData, args) => {
if (!global.cache) return res.status(200).send(undefined);
const stats = global.cache.getStats();
return res.status(200).send(stats);
},
});

getCachedValue = createNextRoute<
[string],
object | undefined,
ApiDependencies,
void
>({
isAuthorized: AccessLevels.IfDeveloper,
handler: async (req, res, {}, authData, [key]) => {
if (!global.cache) return res.status(500).send({ error: "No cache" });
const val = global.cache.get(key) as object | undefined;
return res.status(200).send(val);
},
});
}
54 changes: 54 additions & 0 deletions lib/client/dbinterfaces/CachedDbInterface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ObjectId } from "bson";
import CollectionId, { CollectionIdToType } from "@/lib/client/CollectionId";
import DbInterface, {
WithStringOrObjectIdId,
} from "@/lib/client/dbinterfaces/DbInterface";
import { default as BaseCachedDbInterface } from "mongo-anywhere/CachedDbInterface";

export default class CachedDbInterface
extends BaseCachedDbInterface<CollectionId, CollectionIdToType<CollectionId>>
implements DbInterface
{
init(): Promise<void> {
return super.init(Object.values(CollectionId));
}
addObject<TId extends CollectionId, TObj extends CollectionIdToType<TId>>(
collection: TId,
object: WithStringOrObjectIdId<TObj>,
): Promise<TObj> {
return super.addObject(collection, object);
}
deleteObjectById(collection: CollectionId, id: ObjectId): Promise<void> {
return super.deleteObjectById(collection, id);
}
updateObjectById<
TId extends CollectionId,
TObj extends CollectionIdToType<TId>,
>(collection: TId, id: ObjectId, newValues: Partial<TObj>): Promise<void> {
return super.updateObjectById(collection, id, newValues);
}
findObjectById<
TId extends CollectionId,
TObj extends CollectionIdToType<TId>,
>(collection: TId, id: ObjectId): Promise<TObj | undefined> {
return super.findObjectById(collection, id);
}
findObject<TId extends CollectionId, TObj extends CollectionIdToType<TId>>(
collection: TId,
query: object,
): Promise<TObj | undefined> {
return super.findObject(collection, query);
}
findObjects<TId extends CollectionId, TObj extends CollectionIdToType<TId>>(
collection: TId,
query: object,
): Promise<TObj[]> {
return super.findObjects(collection, query);
}
countObjects(
collection: CollectionId,
query: object,
): Promise<number | undefined> {
return super.countObjects(collection, query);
}
}
34 changes: 27 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sj3",
"version": "1.2.1",
"version": "1.2.2",
"private": true,
"repository": "https://github.com/Decatur-Robotics/Gearbox",
"license": "CC BY-NC-SA 4.0",
Expand Down Expand Up @@ -35,7 +35,7 @@
"jose": "^5.9.6",
"levenary": "^1.1.1",
"minimongo": "^6.19.0",
"mongo-anywhere": "^1.0.21",
"mongo-anywhere": "^1.1.2",
"mongodb": "^5.0.0",
"next": "^15.1.6",
"next-auth": "^4.24.11",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {

return {
props: {
pitReport: SerializeDatabaseObject(pitreport),
pitReport: makeObjSerializeable(SerializeDatabaseObject(pitreport)),
layout: makeObjSerializeable(game.pitReportLayout),
teamNumber: resolved.team?.number,
compName: resolved.competition?.name,
Expand Down
13 changes: 9 additions & 4 deletions pages/[teamSlug]/[seasonSlug]/[competitonSlug]/scouters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function Scouters(props: {
const team = props.team;
const comp = props.competition;

const { session, status } = useCurrentSession();
const { session } = useCurrentSession();
const isManager = session?.user?._id
? team?.owners.includes(session.user?._id)
: false;
Expand Down Expand Up @@ -141,9 +141,9 @@ export default function Scouters(props: {
setReports((reports) => {
if (!reports) return reports;

const { _id, ...updated } = reports[comment.dbId];
const { _id, ...old } = reports[comment.dbId];
promise = api.updateReport(
{ data: { ...updated.data, comments: "" } },
{ data: { ...old.data, comments: "" } },
comment.dbId,
);

Expand All @@ -154,7 +154,12 @@ export default function Scouters(props: {
}

function removePitComment(comment: Comment) {
return api.updatePitreport(comment.dbId, { comments: "" });
const { _id, ...old } = data.pitReports.find(
(r) => r._id === comment.dbId,
)!;
return api.updatePitreport(comment.dbId, {
data: { ...old.data, comments: "" },
});
}

function removeSubjectiveComment(comment: Comment) {
Expand Down
11 changes: 8 additions & 3 deletions pages/[teamSlug]/[seasonSlug]/[competitonSlug]/stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,13 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
submitted: true,
});

const pitReports = await db.findObjects(CollectionId.PitReports, {
_id: { $in: resolved.competition?.pitReports },
});
const pitReports = !resolved.competition
? []
: await db.findObjects(CollectionId.PitReports, {
_id: {
$in: resolved.competition.pitReports.map((id) => new ObjectId(id)),
},
});

const subjectiveReports = await db.findObjects(
CollectionId.SubjectiveReports,
Expand All @@ -208,6 +212,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
CollectionId.Picklists,
new ObjectId(resolved.competition?.picklist),
);
console.log("Picklists", picklists);

return {
props: {
Expand Down
Loading
Loading