added mappers, updated models
This commit is contained in:
parent
6ada519e06
commit
a8375b99c2
11 changed files with 306 additions and 120 deletions
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
@ -32,6 +32,8 @@ function RouteComponent() {
|
||||||
return (
|
return (
|
||||||
<Stack justifyContent="center" alignItems="center">
|
<Stack justifyContent="center" alignItems="center">
|
||||||
<Stack width="90%">
|
<Stack width="90%">
|
||||||
|
{data != null ? (
|
||||||
|
<>
|
||||||
<WorkingListSearch
|
<WorkingListSearch
|
||||||
value={workingSearchValue}
|
value={workingSearchValue}
|
||||||
onSubmit={value => {
|
onSubmit={value => {
|
||||||
|
|
@ -40,8 +42,6 @@ function RouteComponent() {
|
||||||
onChange={value => setWorkingSearchValue(value)}
|
onChange={value => setWorkingSearchValue(value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{data != null ? (
|
|
||||||
<>
|
|
||||||
<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
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
23
app/server/graphql/resolvers/mappers/bookChapterMapper.ts
Normal file
23
app/server/graphql/resolvers/mappers/bookChapterMapper.ts
Normal 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;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
22
app/server/graphql/resolvers/mappers/bookMapper.ts
Normal file
22
app/server/graphql/resolvers/mappers/bookMapper.ts
Normal 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;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
24
app/server/graphql/resolvers/mappers/reviewMapper.ts
Normal file
24
app/server/graphql/resolvers/mappers/reviewMapper.ts
Normal 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;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
65
app/server/graphql/resolvers/mappers/workingMapper.ts
Normal file
65
app/server/graphql/resolvers/mappers/workingMapper.ts
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -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!
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue