Create project schema and scaffold + some minor changes
This commit is contained in:
49
api/db/migrations/20240824001030_project/migration.sql
Normal file
49
api/db/migrations/20240824001030_project/migration.sql
Normal file
@ -0,0 +1,49 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Tag" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"tag" TEXT NOT NULL,
|
||||
"color" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Tag_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ProjectImage" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"fileId" TEXT NOT NULL,
|
||||
"projectId" INTEGER,
|
||||
|
||||
CONSTRAINT "ProjectImage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Project" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL DEFAULT 'No description provided',
|
||||
"date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"links" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
|
||||
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ProjectToTag" (
|
||||
"A" INTEGER NOT NULL,
|
||||
"B" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_ProjectToTag_AB_unique" ON "_ProjectToTag"("A", "B");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ProjectToTag_B_index" ON "_ProjectToTag"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ProjectImage" ADD CONSTRAINT "ProjectImage_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ProjectToTag" ADD CONSTRAINT "_ProjectToTag_A_fkey" FOREIGN KEY ("A") REFERENCES "Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ProjectToTag" ADD CONSTRAINT "_ProjectToTag_B_fkey" FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -48,3 +48,28 @@ model Portrait {
|
||||
id Int @id @default(autoincrement())
|
||||
fileId String
|
||||
}
|
||||
|
||||
model Tag {
|
||||
id Int @id @default(autoincrement())
|
||||
tag String
|
||||
color String
|
||||
projects Project[]
|
||||
}
|
||||
|
||||
model ProjectImage {
|
||||
id Int @id @default(autoincrement())
|
||||
fileId String
|
||||
|
||||
Project Project? @relation(fields: [projectId], references: [id])
|
||||
projectId Int?
|
||||
}
|
||||
|
||||
model Project {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
description String @default("No description provided")
|
||||
images ProjectImage[]
|
||||
date DateTime @default(now())
|
||||
links String[] @default([])
|
||||
tags Tag[]
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
"@redwoodjs/graphql-server": "7.7.4",
|
||||
"@tus/file-store": "^1.4.0",
|
||||
"@tus/server": "^1.7.0",
|
||||
"graphql-scalars": "^1.23.0",
|
||||
"nodemailer": "^6.9.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -2,6 +2,9 @@
|
||||
"globals": {
|
||||
"context": {
|
||||
"writable": false
|
||||
},
|
||||
"gql": {
|
||||
"writable": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { mockRedwoodDirective, getDirectiveName } from '@redwoodjs/testing/api'
|
||||
|
||||
import requireAuth from './requireAuth'
|
||||
|
||||
describe('requireAuth directive', () => {
|
||||
it('declares the directive sdl as schema, with the correct name', () => {
|
||||
expect(requireAuth.schema).toBeTruthy()
|
||||
expect(getDirectiveName(requireAuth.schema)).toBe('requireAuth')
|
||||
})
|
||||
|
||||
it('requireAuth has stub implementation. Should not throw when current user', () => {
|
||||
// If you want to set values in context, pass it through e.g.
|
||||
// mockRedwoodDirective(requireAuth, { context: { currentUser: { id: 1, name: 'Lebron McGretzky' } }})
|
||||
const mockExecution = mockRedwoodDirective(requireAuth, { context: {} })
|
||||
|
||||
expect(mockExecution).not.toThrowError()
|
||||
})
|
||||
})
|
@ -1,10 +0,0 @@
|
||||
import { getDirectiveName } from '@redwoodjs/testing/api'
|
||||
|
||||
import skipAuth from './skipAuth'
|
||||
|
||||
describe('skipAuth directive', () => {
|
||||
it('declares the directive sdl as schema, with the correct name', () => {
|
||||
expect(skipAuth.schema).toBeTruthy()
|
||||
expect(getDirectiveName(skipAuth.schema)).toBe('skipAuth')
|
||||
})
|
||||
})
|
@ -1,3 +1,5 @@
|
||||
import { URLTypeDefinition, URLResolver } from 'graphql-scalars'
|
||||
|
||||
import { createAuthDecoder } from '@redwoodjs/auth-dbauth-api'
|
||||
import { createGraphQLHandler } from '@redwoodjs/graphql-server'
|
||||
|
||||
@ -18,6 +20,12 @@ export const handler = createGraphQLHandler({
|
||||
directives,
|
||||
sdls,
|
||||
services,
|
||||
schemaOptions: {
|
||||
typeDefs: [URLTypeDefinition],
|
||||
resolvers: {
|
||||
URL: URLResolver,
|
||||
},
|
||||
},
|
||||
onException: () => {
|
||||
// Disconnect from your database with an unhandled exception.
|
||||
db.$disconnect()
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const schema = gql`
|
||||
type Portrait {
|
||||
id: Int!
|
||||
fileId: String!
|
||||
fileId: URL!
|
||||
}
|
||||
|
||||
type Query {
|
||||
@ -9,7 +9,7 @@ export const schema = gql`
|
||||
}
|
||||
|
||||
input CreatePortraitInput {
|
||||
fileId: String!
|
||||
fileId: URL!
|
||||
}
|
||||
|
||||
type Mutation {
|
33
api/src/graphql/projectImages.sdl.ts
Normal file
33
api/src/graphql/projectImages.sdl.ts
Normal file
@ -0,0 +1,33 @@
|
||||
export const schema = gql`
|
||||
type ProjectImage {
|
||||
id: Int!
|
||||
fileId: URL!
|
||||
Project: Project
|
||||
projectId: Int
|
||||
}
|
||||
|
||||
type Query {
|
||||
projectImages: [ProjectImage!]! @requireAuth
|
||||
projectImage(id: Int!): ProjectImage @requireAuth
|
||||
}
|
||||
|
||||
input CreateProjectImageInput {
|
||||
fileId: URL!
|
||||
projectId: Int
|
||||
}
|
||||
|
||||
input UpdateProjectImageInput {
|
||||
fileId: URL
|
||||
projectId: Int
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createProjectImage(input: CreateProjectImageInput!): ProjectImage!
|
||||
@requireAuth
|
||||
updateProjectImage(
|
||||
id: Int!
|
||||
input: UpdateProjectImageInput!
|
||||
): ProjectImage! @requireAuth
|
||||
deleteProjectImage(id: Int!): ProjectImage! @requireAuth
|
||||
}
|
||||
`
|
36
api/src/graphql/projects.sdl.ts
Normal file
36
api/src/graphql/projects.sdl.ts
Normal file
@ -0,0 +1,36 @@
|
||||
export const schema = gql`
|
||||
type Project {
|
||||
id: Int!
|
||||
title: String!
|
||||
description: String!
|
||||
images: [ProjectImage]!
|
||||
date: DateTime!
|
||||
links: [String]!
|
||||
tags: [Tag]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
projects: [Project!]! @requireAuth
|
||||
project(id: Int!): Project @requireAuth
|
||||
}
|
||||
|
||||
input CreateProjectInput {
|
||||
title: String!
|
||||
description: String!
|
||||
date: DateTime!
|
||||
links: [String]!
|
||||
}
|
||||
|
||||
input UpdateProjectInput {
|
||||
title: String
|
||||
description: String
|
||||
date: DateTime
|
||||
links: [String]!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createProject(input: CreateProjectInput!): Project! @requireAuth
|
||||
updateProject(id: Int!, input: UpdateProjectInput!): Project! @requireAuth
|
||||
deleteProject(id: Int!): Project! @requireAuth
|
||||
}
|
||||
`
|
3
api/src/graphql/scalars.sdl.ts
Normal file
3
api/src/graphql/scalars.sdl.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const schema = gql`
|
||||
scalar URL
|
||||
`
|
29
api/src/graphql/tags.sdl.ts
Normal file
29
api/src/graphql/tags.sdl.ts
Normal file
@ -0,0 +1,29 @@
|
||||
export const schema = gql`
|
||||
type Tag {
|
||||
id: Int!
|
||||
tag: String!
|
||||
color: String!
|
||||
projects: [Project]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
tags: [Tag!]! @requireAuth
|
||||
tag(id: Int!): Tag @requireAuth
|
||||
}
|
||||
|
||||
input CreateTagInput {
|
||||
tag: String!
|
||||
color: String!
|
||||
}
|
||||
|
||||
input UpdateTagInput {
|
||||
tag: String
|
||||
color: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createTag(input: CreateTagInput!): Tag! @requireAuth
|
||||
updateTag(id: Int!, input: UpdateTagInput!): Tag! @requireAuth
|
||||
deleteTag(id: Int!): Tag! @requireAuth
|
||||
}
|
||||
`
|
@ -6,7 +6,7 @@ import {
|
||||
ValidationError,
|
||||
} from '@redwoodjs/graphql-server'
|
||||
|
||||
import { db } from './db'
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
/**
|
||||
* The name of the cookie that dbAuth sets
|
||||
|
@ -5,7 +5,7 @@ import { PrismaClient } from '@prisma/client'
|
||||
|
||||
import { emitLogLevels, handlePrismaLogging } from '@redwoodjs/api/logger'
|
||||
|
||||
import { logger } from './logger'
|
||||
import { logger } from 'src/lib/logger'
|
||||
|
||||
/*
|
||||
* Instance of the Prisma Client
|
||||
|
@ -1,9 +1,14 @@
|
||||
import type { QueryResolvers, MutationResolvers } from 'types/graphql'
|
||||
|
||||
import { isProduction } from '@redwoodjs/api/dist/logger'
|
||||
import { ValidationError } from '@redwoodjs/graphql-server'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
const address = isProduction
|
||||
? process.env.ADDRESS_PROD
|
||||
: process.env.ADDRESS_DEV
|
||||
|
||||
export const portrait: QueryResolvers['portrait'] = async () => {
|
||||
const portrait = await db.portrait.findFirst()
|
||||
|
||||
@ -11,7 +16,7 @@ export const portrait: QueryResolvers['portrait'] = async () => {
|
||||
else
|
||||
return {
|
||||
id: -1,
|
||||
fileId: '/no_portrait.webp',
|
||||
fileId: `${address}/no_portrait.webp`,
|
||||
}
|
||||
}
|
||||
|
49
api/src/services/projectImages/projectImages.ts
Normal file
49
api/src/services/projectImages/projectImages.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import type {
|
||||
QueryResolvers,
|
||||
MutationResolvers,
|
||||
ProjectImageRelationResolvers,
|
||||
} from 'types/graphql'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
export const projectImages: QueryResolvers['projectImages'] = () => {
|
||||
return db.projectImage.findMany()
|
||||
}
|
||||
|
||||
export const projectImage: QueryResolvers['projectImage'] = ({ id }) => {
|
||||
return db.projectImage.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const createProjectImage: MutationResolvers['createProjectImage'] = ({
|
||||
input,
|
||||
}) => {
|
||||
return db.projectImage.create({
|
||||
data: input,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateProjectImage: MutationResolvers['updateProjectImage'] = ({
|
||||
id,
|
||||
input,
|
||||
}) => {
|
||||
return db.projectImage.update({
|
||||
data: input,
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteProjectImage: MutationResolvers['deleteProjectImage'] = ({
|
||||
id,
|
||||
}) => {
|
||||
return db.projectImage.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const ProjectImage: ProjectImageRelationResolvers = {
|
||||
Project: (_obj, { root }) => {
|
||||
return db.projectImage.findUnique({ where: { id: root?.id } }).Project()
|
||||
},
|
||||
}
|
50
api/src/services/projects/projects.ts
Normal file
50
api/src/services/projects/projects.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import type {
|
||||
QueryResolvers,
|
||||
MutationResolvers,
|
||||
ProjectRelationResolvers,
|
||||
} from 'types/graphql'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
export const projects: QueryResolvers['projects'] = () => {
|
||||
return db.project.findMany()
|
||||
}
|
||||
|
||||
export const project: QueryResolvers['project'] = ({ id }) => {
|
||||
return db.project.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const createProject: MutationResolvers['createProject'] = ({
|
||||
input,
|
||||
}) => {
|
||||
return db.project.create({
|
||||
data: input,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateProject: MutationResolvers['updateProject'] = ({
|
||||
id,
|
||||
input,
|
||||
}) => {
|
||||
return db.project.update({
|
||||
data: input,
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteProject: MutationResolvers['deleteProject'] = ({ id }) => {
|
||||
return db.project.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const Project: ProjectRelationResolvers = {
|
||||
images: (_obj, { root }) => {
|
||||
return db.project.findUnique({ where: { id: root?.id } }).images()
|
||||
},
|
||||
tags: (_obj, { root }) => {
|
||||
return db.project.findUnique({ where: { id: root?.id } }).tags()
|
||||
},
|
||||
}
|
42
api/src/services/tags/tags.ts
Normal file
42
api/src/services/tags/tags.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import type {
|
||||
QueryResolvers,
|
||||
MutationResolvers,
|
||||
TagRelationResolvers,
|
||||
} from 'types/graphql'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
export const tags: QueryResolvers['tags'] = () => {
|
||||
return db.tag.findMany()
|
||||
}
|
||||
|
||||
export const tag: QueryResolvers['tag'] = ({ id }) => {
|
||||
return db.tag.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const createTag: MutationResolvers['createTag'] = ({ input }) => {
|
||||
return db.tag.create({
|
||||
data: input,
|
||||
})
|
||||
}
|
||||
|
||||
export const updateTag: MutationResolvers['updateTag'] = ({ id, input }) => {
|
||||
return db.tag.update({
|
||||
data: input,
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteTag: MutationResolvers['deleteTag'] = ({ id }) => {
|
||||
return db.tag.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export const Tag: TagRelationResolvers = {
|
||||
projects: (_obj, { root }) => {
|
||||
return db.tag.findUnique({ where: { id: root?.id } }).projects()
|
||||
},
|
||||
}
|
Reference in New Issue
Block a user