added mappers, updated models

This commit is contained in:
lnn0q 2025-05-17 17:16:26 +03:00
parent 6ada519e06
commit a8375b99c2
11 changed files with 306 additions and 120 deletions

View file

@ -1,46 +0,0 @@
import { Box, Button, Stack, Text } from '@chakra-ui/react'
import { createFileRoute } from '@tanstack/react-router'
import { gql, useQuery } from '@apollo/client'
import { BooksManyQuery } from '@generated/types'
export const Route = createFileRoute('/example')({
component: Dashboard,
})
function Dashboard() {
const { data, refetch } = useQuery<BooksManyQuery>(getBooksQuery)
return (
<Stack>
<Text>Hello world!</Text>
<Text>This is my template!</Text>
<Stack>
{data && (
<>
{data.booksMany.map((book: any) => (
<Stack key={book.id}>
<Text>{book.title}</Text>
<Text>{book.author}</Text>
</Stack>
))}
</>
)}
<Box>
<Button onClick={async () => refetch()}>Refetch</Button>
</Box>
</Stack>
</Stack>
)
}
const getBooksQuery = gql`
query BooksMany {
booksMany {
id
author
title
}
}
`

View file

@ -32,16 +32,16 @@ function RouteComponent() {
return ( return (
<Stack justifyContent="center" alignItems="center"> <Stack justifyContent="center" alignItems="center">
<Stack width="90%"> <Stack width="90%">
<WorkingListSearch
value={workingSearchValue}
onSubmit={value => {
alert(value);
}}
onChange={value => setWorkingSearchValue(value)}
/>
{data != null ? ( {data != null ? (
<> <>
<WorkingListSearch
value={workingSearchValue}
onSubmit={value => {
alert(value);
}}
onChange={value => setWorkingSearchValue(value)}
/>
<WorkingList <WorkingList
workingsList={data.workingMany.items.map(item => ({ workingsList={data.workingMany.items.map(item => ({
...item, ...item,
@ -58,7 +58,15 @@ function RouteComponent() {
/> />
</> </>
) : ( ) : (
<Skeleton /> <>
<Stack direction="row" justifyContent="center" alignItems="center" gap={2}>
<Skeleton height={10} width="80%" />
<Skeleton height={10} width="calc(20% - 6px)" />
</Stack>
<Skeleton height={20} />
<Skeleton height={20} />
<Skeleton height={20} />
</>
)} )}
</Stack> </Stack>
</Stack> </Stack>
@ -70,21 +78,21 @@ const query = gql`
workingMany(input: $input) { workingMany(input: $input) {
items { items {
id id
type
title title
description description
author { author {
id id
username username
} }
progressStatus
updatedAt updatedAt
chapters { progressStatus
total
}
wordsTotal
ratingTotal ratingTotal
reviews { reviewsTotal
total book {
id
chaptersTotal
wordsTotal
} }
} }
total total

View file

@ -17,6 +17,7 @@ export const Query: QueryResolvers = {
bookOne: BookOneResolver, bookOne: BookOneResolver,
identity: IdentityResolver, identity: IdentityResolver,
userOne: UserOneResolver userOne: UserOneResolver
// workingMany:
}; };
export const Mutation: MutationResolvers = { export const Mutation: MutationResolvers = {

View file

@ -1,13 +0,0 @@
import { IdentityContext } from '@app/server/identity';
import { Book, QueryBookOneArgs } from '@generated/types';
import { books } from './booksManyResolver';
export async function BookOneResolver(
_: any,
{ id }: QueryBookOneArgs,
{ identity }: IdentityContext
): Promise<Book> {
const book = books.filter(item => item.id === id)[0];
return book;
}

View file

@ -1,25 +0,0 @@
import { IdentityContext } from '@app/server/identity';
import { Book } from '@generated/types';
export const books = [
{
id: '1',
title: 'some-title-1',
author: 'someone'
},
{
id: '2',
title: 'some-title-1',
author: 'someone'
}
];
export async function BooksManyResolver(
_: any,
__: any,
{ req, res, identity }: IdentityContext
): Promise<Book[]> {
if (identity == null) throw new Error('Unauthorized');
return books;
}

View file

@ -0,0 +1,23 @@
import { call } from '@app/common';
import { prisma } from '@app/server/prisma/client';
import { BookChapter as BookChapterSchema } from '@generated/types';
import { BookChapter } from '@prisma/client';
export async function toBookChapterMapping(model: BookChapter): Promise<BookChapterSchema> {
return {
id: model.id,
title: model.title,
createdAt: model.createdAt.toISOString(),
updatedAt: model.createdAt.toISOString(),
foreword: model.foreword,
footnote: model.footnote,
reviewsTotal: await call(async () => {
const reviewsCount = await prisma.review.count({
where: {
bookChapterId: model.id
}
});
return reviewsCount;
})
};
}

View file

@ -0,0 +1,22 @@
import { call } from '@app/common';
import { prisma } from '@app/server/prisma/client';
import { Book as BookSchema } from '@generated/types';
import { Book } from '@prisma/client';
export async function toBookSchema(model: Book): Promise<BookSchema> {
return {
id: model.id,
workingId: model.workingId,
createdAt: model.createdAt.toISOString(),
updatedAt: model.updatedAt.toISOString(),
wordsTotal: model.wordsTotal,
chaptersTotal: await call(async () => {
const chaptersCount = await prisma.bookChapter.count({
where: {
bookId: model.id
}
});
return chaptersCount;
})
};
}

View file

@ -0,0 +1,24 @@
import { Review } from '@prisma/client';
import { Review as ReviewSchema } from '@generated/types';
import { toUserSchema } from './userMapper';
import { call } from '@app/common';
import { prisma } from '@app/server/prisma/client';
export async function toReviewSchema(model: Review): Promise<ReviewSchema> {
return {
id: model.id,
author: await call(async () => {
const userModel = await prisma.user.findUniqueOrThrow({
where: {
id: model.userId
}
});
return toUserSchema(userModel);
}),
text: model.text,
//todo: ratings implementation
ratingTotal: await call(async () => {
return 0;
})
};
}

View file

@ -0,0 +1,65 @@
import { assertUnreachable } from '@app/client/helpers';
import { call } from '@app/common';
import { prisma } from '@app/server/prisma/client';
import {
WorkingProgressStatus as WorkingProgressStatusSchema,
Working as WorkingSchema,
WorkingType as WorkingTypeSchema
} from '@generated/types';
import { Working, WorkingProgressStatus, WorkingType } from '@prisma/client';
import { toUserSchema } from './userMapper';
export async function toWorkingSchema(model: Working): Promise<WorkingSchema> {
return {
id: model.id,
title: model.title,
description: model.description,
author: await call(async () => {
const userModel = await prisma.user.findUniqueOrThrow({ where: { id: model.authorId } });
return toUserSchema(userModel);
}),
createdAt: model.createdAt.toISOString(),
updatedAt: model.updatedAt.toISOString(),
type: call(() => {
ensureWorkingType(model.type);
return model.type;
}),
progressStatus: call(() => {
ensureWorkingProgressStatus(model.progressStatus);
return model.progressStatus;
}),
//todo: ratings implementation
//todo: book/notes implementation
ratingTotal: await call(async () => {
const ratingsCount = await prisma.rating.count({
where: {
workingId: model.id
}
});
return ratingsCount;
}),
reviewsTotal: await call(async () => {
const reviewsCount = await prisma.review.count({
where: {
workingId: model.id
}
});
return reviewsCount;
})
};
}
function ensureWorkingType(value: WorkingType): asserts value is WorkingTypeSchema {
if (value == WorkingType.book) return;
if (value == WorkingType.notepad) return;
assertUnreachable(value);
}
function ensureWorkingProgressStatus(
value: WorkingProgressStatus
): asserts value is WorkingProgressStatusSchema {
if (value == WorkingProgressStatus.inProgress) return;
if (value == WorkingProgressStatus.frozen) return;
if (value == WorkingProgressStatus.complete) return;
assertUnreachable(value);
}

View file

@ -1,8 +1,6 @@
scalar Void scalar Void
type Query { type Query {
booksMany: [Book!]!
bookOne(id: ID!): Book!
identity: Identity! identity: Identity!
userOne(id: ID!): User! userOne(id: ID!): User!
workingMany(input: WorkingManyInput!): WorkingManyOutput! workingMany(input: WorkingManyInput!): WorkingManyOutput!
@ -44,14 +42,6 @@ type User {
updatedAt: String! updatedAt: String!
} }
type Book {
id: ID!
title: String!
author: String!
}
input Working
input PaginationFilterInput { input PaginationFilterInput {
terms: String terms: String
offset: Int offset: Int
@ -60,12 +50,18 @@ input PaginationFilterInput {
input WorkingManyInput { input WorkingManyInput {
filter: PaginationFilterInput! filter: PaginationFilterInput!
type: WorkingType!
}
enum WorkingType {
book
notepad
} }
enum WorkingProgressStatus { enum WorkingProgressStatus {
inProgress inProgress
frozen frozen
finished complete
} }
type WorkingManyOutput { type WorkingManyOutput {
@ -80,35 +76,58 @@ type Working {
author: User! author: User!
createdAt: String! createdAt: String!
updatedAt: String! updatedAt: String!
type: WorkingType!
book: Book
notepad: Notepad
progressStatus: WorkingProgressStatus! progressStatus: WorkingProgressStatus!
wordsTotal: Int!
ratingTotal: Int! ratingTotal: Int!
chapters: ChapterManyOutput! reviewsTotal: Int!
reviews: ReviewManyOutput!
} }
type ChapterManyOutput { type Book {
items: [Chapter!]! id: ID!
total: Int! workingId: ID!
createdAt: String!
updatedAt: String!
wordsTotal: Int!
chaptersTotal: Int!
} }
type Chapter { type BookChapter {
id: ID! id: ID!
title: String! title: String!
createdAt: String! createdAt: String!
updatedAt: String! updatedAt: String!
foreword: String! foreword: String!
footnote: String! footnote: String!
reviewsTotal: Int!
} }
type ReviewManyOutput { input BookChapterManyInput {
items: [Review!]! filter: PaginationFilterInput!
}
type BookChapterManyOutput {
items: [BookChapter!]!
total: Int! total: Int!
} }
type Notepad {
id: ID!
}
type Review { type Review {
id: ID! id: ID!
author: User! author: User!
text: String! text: String!
ratingTotal: Int! ratingTotal: Int!
} }
input ReviewManyInput {
filter: PaginationFilterInput!
}
type ReviewManyOutput {
items: [Review!]!
total: Int!
}

View file

@ -20,4 +20,112 @@ model User {
refreshToken String? @unique @db.VarChar(255) refreshToken String? @unique @db.VarChar(255)
isDarkMode Boolean @default(true) isDarkMode Boolean @default(true)
workings Working[]
reviews Review[]
ratings Rating[]
}
model Working {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
description String @db.MediumText
progressStatus WorkingProgressStatus @default(inProgress)
type WorkingType
author User @relation(fields: [authorId], references: [id])
authorId String
book Book?
reviews Review[]
ratings Rating[]
}
enum WorkingType {
book
notepad
}
enum WorkingProgressStatus {
inProgress
frozen
complete
}
model Book {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
wordsTotal Int @default(0)
working Working @relation(fields: [workingId], references: [id])
workingId String @unique @db.VarChar(255)
chapters BookChapter[]
}
model BookChapter {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String @db.VarChar(255)
foreword String @db.MediumText
footnote String @db.MediumText
book Book @relation(fields: [bookId], references: [id])
bookId String @db.VarChar(255)
reviews Review[]
ratings Rating[]
}
model Review {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
text String @db.MediumText
user User @relation(fields: [userId], references: [id])
userId String @db.VarChar(255)
working Working? @relation(fields: [workingId], references: [id])
workingId String? @db.VarChar(255)
bookChapter BookChapter? @relation(fields: [bookChapterId], references: [id])
bookChapterId String? @db.VarChar(255)
}
enum RatingType {
up
down
}
model Rating {
id String @id
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type RatingType
user User @relation(fields: [userId], references: [id])
userId String @db.VarChar(255)
working Working? @relation(fields: [workingId], references: [id])
workingId String? @db.VarChar(255)
bookChapter BookChapter? @relation(fields: [bookChapterId], references: [id])
bookChapterId String? @db.VarChar(255)
} }