diff --git a/functions/graphql/nexus-typegen.ts b/functions/graphql/nexus-typegen.ts index c8fd0a7..9242718 100644 --- a/functions/graphql/nexus-typegen.ts +++ b/functions/graphql/nexus-typegen.ts @@ -4,9 +4,23 @@ */ - - - +import type { core } from "nexus" +declare global { + interface NexusGenCustomInputMethods { + /** + * Date custom scalar type + */ + date(fieldName: FieldName, opts?: core.CommonInputFieldConfig): void // "Date"; + } +} +declare global { + interface NexusGenCustomOutputMethods { + /** + * Date custom scalar type + */ + date(fieldName: FieldName, ...opts: core.ScalarOutSpread): void // "Date"; + } +} declare global { @@ -27,6 +41,7 @@ export interface NexusGenScalars { Float: number Boolean: boolean ID: string + Date: any } export interface NexusGenObjects { @@ -39,10 +54,9 @@ export interface NexusGenObjects { Bounty: { // root type applicants_count: number; // Int! applications: NexusGenRootTypes['BountyApplication'][]; // [BountyApplication!]! - author: NexusGenRootTypes['User']; // User! body: string; // String! cover_image: string; // String! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! deadline: string; // String! excerpt: string; // String! id: number; // Int! @@ -73,7 +87,7 @@ export interface NexusGenObjects { PostComment: { // root type author: NexusGenRootTypes['User']; // User! body: string; // String! - created_at: string; // String! + created_at: NexusGenScalars['Date']; // Date! id: number; // Int! parentId?: number | null; // Int votes_count: number; // Int! @@ -93,10 +107,8 @@ export interface NexusGenObjects { Query: {}; Question: { // root type answers_count: number; // Int! - author: NexusGenRootTypes['User']; // User! body: string; // String! - comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! id: number; // Int! tags: NexusGenRootTypes['Tag'][]; // [Tag!]! @@ -104,12 +116,9 @@ export interface NexusGenObjects { votes_count: number; // Int! } Story: { // root type - author: NexusGenRootTypes['User']; // User! body: string; // String! - comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! - comments_count: number; // Int! cover_image: string; // String! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! id: number; // Int! tags: NexusGenRootTypes['Tag'][]; // [Tag!]! @@ -120,6 +129,11 @@ export interface NexusGenObjects { id: number; // Int! title: string; // String! } + Topic: { // root type + icon: string; // String! + id: number; // Int! + title: string; // String! + } User: { // root type id: number; // Int! image: string; // String! @@ -169,7 +183,7 @@ export interface NexusGenFieldTypes { author: NexusGenRootTypes['User']; // User! body: string; // String! cover_image: string; // String! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! deadline: string; // String! excerpt: string; // String! id: number; // Int! @@ -208,7 +222,7 @@ export interface NexusGenFieldTypes { PostComment: { // field return type author: NexusGenRootTypes['User']; // User! body: string; // String! - created_at: string; // String! + created_at: NexusGenScalars['Date']; // Date! id: number; // Int! parentId: number | null; // Int votes_count: number; // Int! @@ -231,6 +245,7 @@ export interface NexusGenFieldTypes { Query: { // field return type allCategories: NexusGenRootTypes['Category'][]; // [Category!]! allProjects: NexusGenRootTypes['Project'][]; // [Project!]! + allTopics: NexusGenRootTypes['Topic'][]; // [Topic!]! getCategory: NexusGenRootTypes['Category']; // Category! getFeed: NexusGenRootTypes['Post'][]; // [Post!]! getLnurlDetailsForProject: NexusGenRootTypes['LnurlDetails']; // LnurlDetails! @@ -247,7 +262,7 @@ export interface NexusGenFieldTypes { author: NexusGenRootTypes['User']; // User! body: string; // String! comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! id: number; // Int! tags: NexusGenRootTypes['Tag'][]; // [Tag!]! @@ -261,11 +276,12 @@ export interface NexusGenFieldTypes { comments: NexusGenRootTypes['PostComment'][]; // [PostComment!]! comments_count: number; // Int! cover_image: string; // String! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! id: number; // Int! tags: NexusGenRootTypes['Tag'][]; // [Tag!]! title: string; // String! + topic: NexusGenRootTypes['Topic']; // Topic! type: string; // String! votes_count: number; // Int! } @@ -273,6 +289,11 @@ export interface NexusGenFieldTypes { id: number; // Int! title: string; // String! } + Topic: { // field return type + icon: string; // String! + id: number; // Int! + title: string; // String! + } User: { // field return type id: number; // Int! image: string; // String! @@ -296,9 +317,8 @@ export interface NexusGenFieldTypes { payment_request: string; // String! } PostBase: { // field return type - author: NexusGenRootTypes['User']; // User! body: string; // String! - date: string; // String! + createdAt: NexusGenScalars['Date']; // Date! excerpt: string; // String! id: number; // Int! tags: NexusGenRootTypes['Tag'][]; // [Tag!]! @@ -321,7 +341,7 @@ export interface NexusGenFieldTypeNames { author: 'User' body: 'String' cover_image: 'String' - date: 'String' + createdAt: 'Date' deadline: 'String' excerpt: 'String' id: 'Int' @@ -360,7 +380,7 @@ export interface NexusGenFieldTypeNames { PostComment: { // field return type name author: 'User' body: 'String' - created_at: 'String' + created_at: 'Date' id: 'Int' parentId: 'Int' votes_count: 'Int' @@ -383,6 +403,7 @@ export interface NexusGenFieldTypeNames { Query: { // field return type name allCategories: 'Category' allProjects: 'Project' + allTopics: 'Topic' getCategory: 'Category' getFeed: 'Post' getLnurlDetailsForProject: 'LnurlDetails' @@ -399,7 +420,7 @@ export interface NexusGenFieldTypeNames { author: 'User' body: 'String' comments: 'PostComment' - date: 'String' + createdAt: 'Date' excerpt: 'String' id: 'Int' tags: 'Tag' @@ -413,11 +434,12 @@ export interface NexusGenFieldTypeNames { comments: 'PostComment' comments_count: 'Int' cover_image: 'String' - date: 'String' + createdAt: 'Date' excerpt: 'String' id: 'Int' tags: 'Tag' title: 'String' + topic: 'Topic' type: 'String' votes_count: 'Int' } @@ -425,6 +447,11 @@ export interface NexusGenFieldTypeNames { id: 'Int' title: 'String' } + Topic: { // field return type name + icon: 'String' + id: 'Int' + title: 'String' + } User: { // field return type name id: 'Int' image: 'String' @@ -448,9 +475,8 @@ export interface NexusGenFieldTypeNames { payment_request: 'String' } PostBase: { // field return type name - author: 'User' body: 'String' - date: 'String' + createdAt: 'Date' excerpt: 'String' id: 'Int' tags: 'Tag' @@ -484,10 +510,10 @@ export interface NexusGenArgTypes { id: number; // Int! } getFeed: { // args - category: string | null; // String skip?: number | null; // Int sortBy: string | null; // String take: number | null; // Int + topic?: number | null; // Int } getLnurlDetailsForProject: { // args project_id: number; // Int! diff --git a/functions/graphql/schema.graphql b/functions/graphql/schema.graphql index 5fefd58..5164ddb 100644 --- a/functions/graphql/schema.graphql +++ b/functions/graphql/schema.graphql @@ -16,7 +16,7 @@ type Bounty implements PostBase { author: User! body: String! cover_image: String! - date: String! + createdAt: Date! deadline: String! excerpt: String! id: Int! @@ -44,6 +44,9 @@ type Category { votes_sum: Int! } +"""Date custom scalar type""" +scalar Date + type LnurlDetails { commentAllowed: Int maxSendable: Int @@ -66,9 +69,8 @@ enum POST_TYPE { union Post = Bounty | Question | Story interface PostBase { - author: User! body: String! - date: String! + createdAt: Date! excerpt: String! id: Int! tags: [Tag!]! @@ -79,7 +81,7 @@ interface PostBase { type PostComment { author: User! body: String! - created_at: String! + created_at: Date! id: Int! parentId: Int votes_count: Int! @@ -104,8 +106,9 @@ type Project { type Query { allCategories: [Category!]! allProjects(skip: Int = 0, take: Int = 50): [Project!]! + allTopics: [Topic!]! getCategory(id: Int!): Category! - getFeed(category: String = "all", skip: Int = 0, sortBy: String = "all", take: Int = 10): [Post!]! + getFeed(skip: Int = 0, sortBy: String = "all", take: Int = 10, topic: Int): [Post!]! getLnurlDetailsForProject(project_id: Int!): LnurlDetails! getPostById(id: Int!, type: POST_TYPE!): Post! getProject(id: Int!): Project! @@ -121,7 +124,7 @@ type Question implements PostBase { author: User! body: String! comments: [PostComment!]! - date: String! + createdAt: Date! excerpt: String! id: Int! tags: [Tag!]! @@ -136,11 +139,12 @@ type Story implements PostBase { comments: [PostComment!]! comments_count: Int! cover_image: String! - date: String! + createdAt: Date! excerpt: String! id: Int! tags: [Tag!]! title: String! + topic: Topic! type: String! votes_count: Int! } @@ -150,6 +154,12 @@ type Tag { title: String! } +type Topic { + icon: String! + id: Int! + title: String! +} + type User { id: Int! image: String! diff --git a/functions/graphql/types/_scalars.js b/functions/graphql/types/_scalars.js new file mode 100644 index 0000000..ec7c171 --- /dev/null +++ b/functions/graphql/types/_scalars.js @@ -0,0 +1,24 @@ +const { Kind } = require("graphql") +const { scalarType } = require("nexus") + +const DateScalar = scalarType({ + name: 'Date', + asNexusMethod: 'date', + description: 'Date custom scalar type', + parseValue(value) { + return new Date(value) + }, + serialize(value) { + return value.toISOString() + }, + parseLiteral(ast) { + if (ast.kind === Kind.INT) { + return new Date(ast.value) + } + return null + }, +}) + +module.exports = { + DateScalar +} \ No newline at end of file diff --git a/functions/graphql/types/index.js b/functions/graphql/types/index.js index 6e9b03a..3b97a9d 100644 --- a/functions/graphql/types/index.js +++ b/functions/graphql/types/index.js @@ -1,3 +1,4 @@ +const scalars = require('./_scalars') const category = require('./category') const project = require('./project') const vote = require('./vote') @@ -5,6 +6,7 @@ const post = require('./post') const users = require('./users') module.exports = { + ...scalars, ...category, ...project, ...vote, diff --git a/functions/graphql/types/post.js b/functions/graphql/types/post.js index 6bf54bf..136d364 100644 --- a/functions/graphql/types/post.js +++ b/functions/graphql/types/post.js @@ -16,7 +16,17 @@ const { prisma } = require('../prisma') const POST_TYPE = enumType({ name: 'POST_TYPE', members: ['Story', 'Bounty', 'Question'], -}) +}); + +const asType = type => (obj) => { + if (Array.isArray(obj)) return obj.map(o => ({ ...o, type })) + return { ...obj, type } +} + +const asStoryType = asType('Story') +const asQuestionType = asType('Question') +const asBountyType = asType('Bounty') + const Topic = objectType({ name: 'Topic', @@ -44,21 +54,18 @@ const allTopics = extendType({ const PostBase = interfaceType({ name: 'PostBase', - resolveType() { - return null + resolveType(item) { + return item.type }, definition(t) { t.nonNull.int('id'); t.nonNull.string('title'); - t.nonNull.string('date'); + t.nonNull.date('createdAt'); t.nonNull.string('excerpt'); t.nonNull.string('body'); t.nonNull.list.nonNull.field('tags', { type: "Tag" }); - t.nonNull.field('topic', { - type: "Topic" - }); t.nonNull.int('votes_count'); }, }) @@ -68,23 +75,45 @@ const Story = objectType({ definition(t) { t.implements('PostBase'); t.nonNull.string('type', { - resolve: () => 'Story' + resolve: () => t.typeName }); t.nonNull.string('cover_image'); - t.nonNull.int('comments_count'); + t.nonNull.list.nonNull.field('comments', { type: "PostComment", - resolve: (parent) => { - return prisma.story.findUnique({ where: { id: parent.id } }).comments(); + resolve: (parent) => prisma.story.findUnique({ where: { id: parent.id } }).comments() + + }); + t.nonNull.int('comments_count', { + resolve: async (parent) => { + const post = await prisma.story.findUnique({ + where: { id: parent.id }, + include: { + _count: { + select: { + comments: true + } + } + } + }) + return post._count.comments; } }); - + t.nonNull.field('topic', { + type: "Topic", + resolve: parent => { + return prisma.story.findUnique({ + where: { id: parent.id } + }).topic() + } + }) t.nonNull.field('author', { type: "User", - resolve: (parent) => { - return prisma.story.findUnique({ where: { id: parent.id } }).user(); - } + resolve: (parent) => + prisma.story.findUnique({ where: { id: parent.id } }).user() + }); + }, }) @@ -152,7 +181,7 @@ const PostComment = objectType({ name: 'PostComment', definition(t) { t.nonNull.int('id'); - t.nonNull.string('created_at'); + t.nonNull.date('created_at'); t.nonNull.string('body'); t.nonNull.field('author', { type: "User" @@ -167,7 +196,9 @@ const Post = unionType({ definition(t) { t.members('Story', 'Bounty', 'Question') }, - resolveType: (item) => item.type, + resolveType: (item) => { + return item.type + }, }) @@ -191,7 +222,7 @@ const getFeed = extendType({ }, skip, take, - }); + }).then(asStoryType) } }) } @@ -207,15 +238,15 @@ const getTrendingPosts = extendType({ }, resolve() { const now = new Date(); - const lastWeekDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7).toUTCString() + const lastWeekDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7) return prisma.story.findMany({ take: 5, where: { createdAt: { - gt: lastWeekDate + gte: lastWeekDate } } - }) + }).then(asStoryType) } }) } @@ -233,30 +264,17 @@ const getPostById = extendType({ type: nonNull('POST_TYPE') }) }, - resolve(_, { id }) { - return { - id: 4, - title: 'Digital Editor, Mars Review of Books', - body: "AASA", - cover_image: "AASA", - comments_count: 31, - date: "SSSS", - votes_count: 120, - excerpt: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In odio libero accumsan...', - type: "Story", - tags: [ - { id: 1, title: "lnurl" }, - { id: 2, title: "webln" }, - { id: 3, title: "guide" }, - ], - author: { + resolve(_, { id, type }) { + if (type === 'Story') + return prisma.story.findUnique({ + where: { id } + }).then(asStoryType) - id: 12, - name: "John Doe", - image: "SSSS", - join_date: "SSSS" - }, - } + if (type === 'Question') + return prisma.question.findUnique({ + where: { id } + }).then(asQuestionType) + return null } }) } diff --git a/prisma/migrations/20220520054239_remove_thumbnail_img_col/migration.sql b/prisma/migrations/20220520054239_remove_thumbnail_img_col/migration.sql new file mode 100644 index 0000000..1f692cf --- /dev/null +++ b/prisma/migrations/20220520054239_remove_thumbnail_img_col/migration.sql @@ -0,0 +1,20 @@ +/* + Warnings: + + - You are about to drop the column `date` on the `Hackathon` table. All the data in the column will be lost. + - You are about to drop the column `thumbnail_image` on the `Question` table. All the data in the column will be lost. + - You are about to drop the column `thumbnail_image` on the `Story` table. All the data in the column will be lost. + - Added the required column `end_date` to the `Hackathon` table without a default value. This is not possible if the table is not empty. + - Added the required column `start_date` to the `Hackathon` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Hackathon" DROP COLUMN "date", +ADD COLUMN "end_date" DATE NOT NULL, +ADD COLUMN "start_date" DATE NOT NULL; + +-- AlterTable +ALTER TABLE "Question" DROP COLUMN "thumbnail_image"; + +-- AlterTable +ALTER TABLE "Story" DROP COLUMN "thumbnail_image"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 83aac32..f83a7cd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -95,14 +95,13 @@ model Award { // ----------------- model Story { - id Int @id @default(autoincrement()) - title String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - body String - thumbnail_image String - cover_image String - votes_count Int @default(0) + id Int @id @default(autoincrement()) + title String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + body String + cover_image String + votes_count Int @default(0) topic Topic @relation(fields: [topic_id], references: [id]) topic_id Int @@ -116,13 +115,12 @@ model Story { } model Question { - id Int @id @default(autoincrement()) - title String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - body String - thumbnail_image String - votes_count Int @default(0) + id Int @id @default(autoincrement()) + title String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + body String + votes_count Int @default(0) topic Topic @relation(fields: [topic_id], references: [id]) topic_id Int @@ -171,14 +169,15 @@ model PostComment { // Hackathons // ----------------- model Hackathon { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) title String - date String + start_date DateTime @db.Date + end_date DateTime @db.Date cover_image String description String location String website String - votes_count Int @default(0) + votes_count Int @default(0) topics Topic[] }