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

Query refactor #152

Merged
merged 41 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8b374b0
fix useUserQuery
reyniersbram Apr 25, 2024
2740319
remove top level package lock
reyniersbram Apr 25, 2024
5a61ac5
add some documentation to user queries
reyniersbram Apr 25, 2024
886c149
useUserQuery now accepts either a ref or a raw value
reyniersbram Apr 25, 2024
ee6f579
run formatter
reyniersbram Apr 25, 2024
c04cc1e
changed enabled from computed to getter
reyniersbram Apr 25, 2024
dde750c
update Subject queries, fixes: #143
reyniersbram Apr 25, 2024
f22c40e
Merge branch 'dev' into query-refactor
reyniersbram May 2, 2024
3b35138
update mutation to register to subject
reyniersbram May 2, 2024
9c472c8
improved authorized_fetch
reyniersbram May 2, 2024
85fc313
show projects on homescreen, fixes: #134
reyniersbram May 2, 2024
75f9684
Merge branch 'dev' into query-refactor
reyniersbram May 7, 2024
dc05ff5
run formatter
reyniersbram May 7, 2024
e591b82
fix download_file util
reyniersbram May 10, 2024
b2d3fdd
Merge branch 'dev' into query-refactor
reyniersbram May 10, 2024
3e7b81e
clean up subject queries
reyniersbram May 10, 2024
0a08785
clean up user services
reyniersbram May 10, 2024
8004cfa
Merge branch 'dev' into query-refactor
reyniersbram May 10, 2024
7f1871b
clean up project queries and services
reyniersbram May 10, 2024
1027333
Merge branch 'dev' into query-refactor
reyniersbram May 12, 2024
815ef87
review group services
reyniersbram May 12, 2024
3b053a0
review submission services
reyniersbram May 12, 2024
07473d5
refactor submission queries
reyniersbram May 12, 2024
38f36fc
optimistic updates for group queries
reyniersbram May 13, 2024
46cd89e
fix views using group/submission queries
reyniersbram May 13, 2024
171bbaf
Merge branch 'dev' into query-refactor
reyniersbram May 13, 2024
60e00db
try to fix some tests
reyniersbram May 13, 2024
47d55ca
run formatter
reyniersbram May 13, 2024
4de0cbd
remove todo's
reyniersbram May 13, 2024
271d9af
frontend warnings fix
masinnae May 13, 2024
7c818d7
Merge remote-tracking branch 'origin/query-refactor' into query-refactor
masinnae May 13, 2024
bec85c2
fix subjects query
reyniersbram May 13, 2024
5baca93
run formatter
reyniersbram May 13, 2024
e4fe143
fix useProjectGroupsQuery
reyniersbram May 13, 2024
7e5e0a0
fix tests
reyniersbram May 13, 2024
1703906
fix delete group mutation
reyniersbram May 15, 2024
5acbe54
fix leave and join group mutations
reyniersbram May 15, 2024
bd68539
Merge branch 'dev' into query-refactor
reyniersbram May 15, 2024
601d23d
run formatter
reyniersbram May 15, 2024
e7bbe9b
Merge branch 'dev' into query-refactor
reyniersbram May 16, 2024
7595918
fix user groups query not refreshing
reyniersbram May 16, 2024
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
44 changes: 11 additions & 33 deletions frontend/src/components/home/cards/DeadlinesCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,15 @@
import HomeScreenCard from "@/components/home/cards/HomeScreenCard.vue";
import DeadlineItem from "@/components/home/listcontent/DeadlineItem.vue";
import { type Deadline } from "@/models/Project";
import { ref } from "vue";
const deadlines = ref<Deadline[]>([
{
project: {
id: 1,
name: "project A",
subject_id: 1,
deadline: new Date(2024, 4, 28, 23, 59),
description: "a description",
},
status: "none",
},
{
project: {
id: 2,
name: "project B",
subject_id: 2,
deadline: new Date(2024, 6, 2, 17, 0),
description: "another description",
},
status: "accepted",
},
{
project: {
id: 3,
name: "project C",
subject_id: 3,
deadline: new Date(2024, 5, 5, 22, 0),
description: "last description",
},
status: "rejected",
},
]);
import { useProjectsQuery } from "@/queries/Project";
import { computed } from "vue";

const { data: projects } = useProjectsQuery();
const deadlines = computed<Deadline[]>(
() =>
projects.value?.map((project) => ({
project,
status: "none",
reyniersbram marked this conversation as resolved.
Show resolved Hide resolved
})) || []
);
pieterjanin marked this conversation as resolved.
Show resolved Hide resolved
</script>
4 changes: 2 additions & 2 deletions frontend/src/composables/useIsAdmin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { computed } from "vue";
import { useUserQuery } from "@/queries/User";
import { useCurrentUserQuery } from "@/queries/User";

export default function useIsAdmin() {
const { data: user } = useUserQuery(null);
const { data: user } = useCurrentUserQuery();
const isAdmin = computed(() => user.value?.is_admin || false);
return { isAdmin };
}
4 changes: 2 additions & 2 deletions frontend/src/composables/useIsTeacher.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { computed } from "vue";
import { useUserQuery } from "@/queries/User";
import { useCurrentUserQuery } from "@/queries/User";

export default function useIsTeacher() {
const { data: user } = useUserQuery(null);
const { data: user } = useCurrentUserQuery();
const isTeacher = computed(() => user.value?.is_teacher || false);
return { isTeacher };
}
203 changes: 136 additions & 67 deletions frontend/src/queries/Subject.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { useQuery, type UseQueryReturnType } from "@tanstack/vue-query";
import { computed, toValue } from "vue";
import type { Ref, MaybeRefOrGetter, MaybeRef } from "vue";
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
import type { UseQueryReturnType, QueryStatus, UseMutationReturnType } from "@tanstack/vue-query";
import {
getSubject,
getSubjectInstructors,
Expand All @@ -8,105 +11,171 @@ import {
getSubjectByUuid,
registerToSubject,
} from "@/services/subject";
import { type Ref, computed } from "vue";
import type Subject from "@/models/Subject";
import type User from "@/models/User";
import type Subject from "@/models/Subject";
import type Project from "@/models/Project";
import type SubjectDetails from "@/models/SubjectDetails";

// Generalized function to create query keys based on subject details
function createSubjectQueryKey(
subjectId: number | string,
detail: string = ""
): (string | number)[] {
return ["subject", subjectId, detail].filter(Boolean);
function SUBJECT_QUERY_KEY(subjectId: number | string): (string | number)[] {
return ["subject", subjectId];
}

function SUBJECTS_QUERY_KEY(): (string | number)[] {
return ["subjects"];
}

function SUBJECT_INSTRUCTORS_QUERY_KEY(subjectId: number): (string | number)[] {
return ["subject", "instructors", subjectId];
}

function SUBJECT_STUDENTS_QUERY_KEY(subjectId: number): (string | number)[] {
return ["subject", "students", subjectId];
}

function SUBJECT_PROJECTS_QUERY_KEY(subjectId: number): (string | number)[] {
return ["subject", "projects", subjectId];
}

export function useSubjectQuery(
subjectId: Ref<number | undefined>
subjectId: MaybeRefOrGetter<number | undefined>
): UseQueryReturnType<Subject, Error> {
return useQuery<Subject, Error>({
queryKey: computed(() => SUBJECT_QUERY_KEY(toValue(subjectId)!)),
queryFn: () => getSubject(toValue(subjectId)!),
enabled: () => !!toValue(subjectId),
});
}

export function useSubjectUuidQuery(
subjectUuid: MaybeRefOrGetter<string | undefined>
): UseQueryReturnType<Subject, Error> {
return useQuery<Subject, Error>({
queryKey: computed(() => createSubjectQueryKey(subjectId.value!)),
queryFn: () => getSubject(subjectId.value!),
enabled: computed(() => subjectId.value !== undefined),
queryKey: computed(() => SUBJECT_QUERY_KEY(toValue(subjectUuid)!)),
queryFn: () => getSubjectByUuid(toValue(subjectUuid)!),
enabled: () => !!toValue(subjectUuid),
});
}

export function useSubjectsQuery(): UseQueryReturnType<Subject[], Error> {
return useQuery<Subject[], Error>({
queryKey: SUBJECTS_QUERY_KEY(),
queryFn: getSubjects,
});
}

export function useSubjectInstructorsQuery(
subjectId: Ref<number | undefined>
subjectId: MaybeRefOrGetter<number | undefined>
): UseQueryReturnType<User[], Error> {
return useQuery<User[], Error>({
queryKey: computed(() => createSubjectQueryKey(subjectId.value!, "instructors")),
queryFn: () => getSubjectInstructors(subjectId.value!),
enabled: () => subjectId.value !== undefined,
queryKey: computed(() => SUBJECT_INSTRUCTORS_QUERY_KEY(toValue(subjectId)!)),
queryFn: () => getSubjectInstructors(toValue(subjectId)!),
enabled: () => !!toValue(subjectId),
});
}

export function useSubjectStudentsQuery(
subjectId: Ref<number | undefined>
subjectId: MaybeRefOrGetter<number | undefined>
): UseQueryReturnType<User[], Error> {
return useQuery<User[], Error>({
queryKey: computed(() => createSubjectQueryKey(subjectId.value!, "students")),
queryFn: () => getSubjectStudents(subjectId.value!),
enabled: () => subjectId.value !== undefined,
queryKey: computed(() => SUBJECT_STUDENTS_QUERY_KEY(toValue(subjectId)!)),
queryFn: () => getSubjectStudents(toValue(subjectId)!),
enabled: () => !!toValue(subjectId),
});
}

export function useSubjectProjectsQuery(
subjectId: Ref<number | undefined>
subjectId: MaybeRefOrGetter<number | undefined>
): UseQueryReturnType<Project[], Error> {
return useQuery<Project[], Error>({
queryKey: computed(() => createSubjectQueryKey(subjectId.value!, "projects")),
queryFn: () => getSubjectProjects(subjectId.value!),
enabled: () => subjectId.value !== undefined,
queryKey: computed(() => SUBJECT_PROJECTS_QUERY_KEY(toValue(subjectId)!)),
queryFn: () => getSubjectProjects(toValue(subjectId)!),
enabled: () => !!toValue(subjectId),
});
}

export function useSubjectsQuery(): UseQueryReturnType<Subject[], Error> {
return useQuery<Subject[], Error>({
queryKey: createSubjectQueryKey("all"),
queryFn: getSubjects,
export function useSubjectDetailsQuery(subjectId: MaybeRefOrGetter<number | undefined>): {
data: Ref<SubjectDetails | undefined>;
status: Ref<QueryStatus>;
isSuccess: Ref<boolean>;
isError: Ref<boolean>;
isLoading: Ref<boolean>;
error: Ref<(Error | null)[]>;
} {
const {
data: subjectData,
status: subjectStatus,
isSuccess: subjectSuccess,
isLoading: subjectLoading,
error: subjectError,
} = useSubjectQuery(subjectId);
const {
data: instructorsData,
status: instructorsStatus,
isSuccess: instructorsSuccess,
isLoading: instructorsLoading,
error: instructorsError,
} = useSubjectInstructorsQuery(subjectId);
const {
data: studentsData,
status: studentsStatus,
isSuccess: studentsSuccess,
isLoading: studentsLoading,
error: studentsError,
} = useSubjectStudentsQuery(subjectId);
const {
data: projectsData,
status: projectsStatus,
isSuccess: projectsSuccess,
isLoading: projectsLoading,
error: projectsError,
} = useSubjectProjectsQuery(subjectId);
const data = computed<SubjectDetails | undefined>(() => {
if (
!subjectSuccess.value ||
!instructorsSuccess.value ||
!studentsSuccess.value ||
!projectsSuccess.value
)
return undefined;
return {
id: subjectData.value!.id,
name: subjectData.value!.name,
instructors: instructorsData.value!,
students: studentsData.value!,
projects: projectsData.value!,
};
});
}

export function useSubjectDetailsQuery(
subjectId: Ref<number | undefined>
): UseQueryReturnType<SubjectDetails, Error> {
return useQuery<SubjectDetails, Error>({
queryKey: computed(() => createSubjectQueryKey(subjectId.value!, "details")),
queryFn: async () => {
const [subject, instructors, students, projects] = (await Promise.all([
getSubject(subjectId.value!),
getSubjectInstructors(subjectId.value!),
getSubjectStudents(subjectId.value!),
getSubjectProjects(subjectId.value!),
])) as [Subject, User[], User[], Project[]];

return {
id: subject.id,
name: subject.name,
instructors,
students,
projects,
};
},
enabled: () => subjectId.value !== undefined,
});
}

export function useSubjectUuidQuery(subjectUuid: Ref<string>): UseQueryReturnType<Subject, Error> {
return useQuery<Subject, Error>({
queryKey: computed(() => createSubjectQueryKey(subjectUuid.value)),
queryFn: () => getSubjectByUuid(subjectUuid.value),
enabled: () => subjectUuid !== undefined,
retry: false,
const status = computed<QueryStatus>(() => {
const statuses = [subjectStatus, instructorsStatus, studentsStatus, projectsStatus];
if (statuses.every((status) => status.value === "success")) return "success";
if (statuses.some((status) => status.value === "error")) return "error";
return "pending";
});
const isSuccess = computed(() => status.value === "success");
const isError = computed(() => status.value === "error");
const isLoading = computed(() =>
[subjectLoading, instructorsLoading, studentsLoading, projectsLoading].some(
(loading) => loading.value
)
);
const error = computed<(Error | null)[]>(() =>
[subjectError, instructorsError, studentsError, projectsError].map((error) => error.value)
);
return { status, isSuccess, isError, isLoading, data, error };
}

export function registerSubjectQuery(uuid: Ref<string>): UseQueryReturnType<Subject, Error> {
return useQuery<Subject, Error>({
queryKey: computed(() => createSubjectQueryKey(uuid.value)),
queryFn: () => registerToSubject(uuid.value),
enabled: () => false,
export function useRegisterToSubjectMutation(): UseMutationReturnType<
Subject,
Error,
MaybeRef<string>,
{}
> {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (uuid) => await registerToSubject(toValue(uuid)),
// TODO: Add optimistic update
onSettled: () => {
queryClient.invalidateQueries({ queryKey: SUBJECTS_QUERY_KEY() });
},
});
}
Loading
Loading