From 0ca174b335740ecb17ec6bbb97253f3e6bdabb8f Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sat, 21 Sep 2019 13:34:44 +0200 Subject: [PATCH 1/6] DataAccess changes - changed data access structure - changed graphql schema - changed create-tables sql script (added vote_type to votes table) --- src/app.ts | 6 +- src/lib/dataaccess/DataObject.ts | 14 ++ src/lib/dataaccess/Post.ts | 101 ++++++++++++++ src/lib/dataaccess/User.ts | 136 +++++++++++++++++++ src/lib/{DTO.ts => dataaccess/index.ts} | 4 +- src/public/graphql/schema.graphql | 167 ++++++++++++++---------- src/sql/create-tables.sql | 3 +- 7 files changed, 355 insertions(+), 76 deletions(-) create mode 100644 src/lib/dataaccess/DataObject.ts create mode 100644 src/lib/dataaccess/Post.ts create mode 100644 src/lib/dataaccess/User.ts rename src/lib/{DTO.ts => dataaccess/index.ts} (98%) diff --git a/src/app.ts b/src/app.ts index 698a895..3634256 100644 --- a/src/app.ts +++ b/src/app.ts @@ -2,7 +2,7 @@ import * as express from "express"; import * as http from "http"; import * as path from "path"; import * as socketIo from "socket.io"; -import {DTO} from "./lib/DTO"; +import dataaccess from "./lib/dataaccess"; import globals from "./lib/globals"; import routes from "./routes"; @@ -10,20 +10,18 @@ class App { public app: express.Application; public io: socketIo.Server; public server: http.Server; - public dto: DTO; constructor() { this.app = express(); this.server = new http.Server(this.app); this.io = socketIo(this.server); - this.dto = new DTO(); } /** * initializes everything that needs to be initialized asynchronous. */ public async init() { - await this.dto.init(); + await dataaccess.init(); await routes.ioListeners(this.io); this.app.set("views", path.join(__dirname, "views")); this.app.set("view engine", "pug"); diff --git a/src/lib/dataaccess/DataObject.ts b/src/lib/dataaccess/DataObject.ts new file mode 100644 index 0000000..afabc32 --- /dev/null +++ b/src/lib/dataaccess/DataObject.ts @@ -0,0 +1,14 @@ +abstract class DataObject { + protected dataLoaded: boolean = false; + + constructor(public id: number, protected row?: any) { + } + + protected abstract loadData(): Promise; + + protected loadDataIfNotExists() { + if (this.dataLoaded) { + this.loadData(); + } + } +} diff --git a/src/lib/dataaccess/Post.ts b/src/lib/dataaccess/Post.ts new file mode 100644 index 0000000..51c6b4c --- /dev/null +++ b/src/lib/dataaccess/Post.ts @@ -0,0 +1,101 @@ +import {queryHelper, VoteType} from "./index"; +import {User} from "./User"; + +export class Post extends DataObject { + public readonly id: number; + private $upvotes: number; + private $downvotes: number; + private $createdAt: string; + private $content: string; + private $author: number; + private $type: string; + + /** + * Returns the upvotes of a post. + */ + public async upvotes(): Promise { + this.loadDataIfNotExists(); + return this.$upvotes; + } + + /** + * Returns the downvotes of the post + */ + public async downvotes(): Promise { + this.loadDataIfNotExists(); + return this.$downvotes; + } + + /** + * The content of the post (markdown) + */ + public async content(): Promise { + this.loadDataIfNotExists(); + return this.$content; + } + + /** + * The date the post was created at. + */ + public async createdAt(): Promise { + this.loadDataIfNotExists(); + return this.$createdAt; + } + + /** + * The autor of the post. + */ + public async author(): Promise { + this.loadDataIfNotExists(); + return new User(this.$author); + } + + /** + * Deletes the post. + */ + public async delete(): Promise { + const query = await queryHelper.first({ + text: "DELETE FROM posts WHERE id = $1", + values: [this.id], + }); + } + + /** + * The type of vote the user performed on the post. + */ + public async userVote(userId: number): Promise { + const result = await queryHelper.first({ + text: "SELECT vote_type FROM votes WHERE user_id = $1 AND item_id = $2", + values: [userId, this.id], + }); + if (result) { + return result.vote_type; + } else { + return null; + } + } + + /** + * Loads the data from the database if needed. + */ + protected async loadData(): Promise { + let result: any; + if (this.row) { + result = this.row; + } else { + result = await queryHelper.first({ + text: "SELECT * FROM posts WHERE posts.id = $1", + values: [this.id], + }); + } + if (result) { + this.$author = result.author; + this.$content = result.content; + this.$downvotes = result.downvotes; + this.$upvotes = result.upvotes; + this.$createdAt = result.created_at; + this.$type = result.type; + this.dataLoaded = true; + } + } +} diff --git a/src/lib/dataaccess/User.ts b/src/lib/dataaccess/User.ts new file mode 100644 index 0000000..ea7c7c9 --- /dev/null +++ b/src/lib/dataaccess/User.ts @@ -0,0 +1,136 @@ +import {queryHelper} from "./index"; +import {Post} from "./Post"; + +export class User extends DataObject { + private $name: string; + private $handle: string; + private $email: string; + private $greenpoints: number; + private $joinedAt: string; + + /** + * The name of the user + */ + public async name(): Promise { + this.loadDataIfNotExists(); + return this.$name; + } + + /** + * Sets the username of the user + * @param name + */ + public async setName(name: string): Promise { + const result = await queryHelper.first({ + text: "UPDATE TABLE users SET name = $1 WHERE id = $2", + values: [name, this.id], + }); + return result.name; + } + + /** + * The unique handle of the user. + */ + public async handle(): Promise { + this.loadDataIfNotExists(); + return this.$handle; + } + + /** + * Updates the handle of the user + */ + public async setHandle(handle: string): Promise { + const result = await queryHelper.first({ + text: "UPDATE TABLE users SET handle = $1 WHERE id = $2", + values: [handle, this.id], + }); + return result.handle; + } + + /** + * The email of the user + */ + public async email(): Promise { + this.loadDataIfNotExists(); + return this.$email; + } + + /** + * Sets the email of the user + * @param email + */ + public async setEmail(email: string): Promise { + const result = await queryHelper.first({ + text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email", + values: [email, this.id], + }); + return result.email; + } + + /** + * The number of greenpoints of the user + */ + public async greenpoints(): Promise { + this.loadDataIfNotExists(); + return this.$greenpoints; + } + + /** + * Sets the greenpoints of a user. + * @param points + */ + public async setGreenpoints(points: number): Promise { + const result = await queryHelper.first({ + text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints", + values: [points, this.id], + }); + return result.greenpoints; + } + + /** + * The date the user joined the platform + */ + public async joinedAt(): Promise { + this.loadDataIfNotExists(); + return new Date(this.$joinedAt); + } + + /** + * Returns all posts for a user. + */ + public async posts(): Promise { + const result = await queryHelper.all({ + text: "SELECT * FROM posts WHERE author = $1", + values: [this.id], + }); + const posts = []; + + for (const row of result) { + posts.push(new Post(row.id, row)); + } + return posts; + } + + /** + * Fetches the data for the user. + */ + protected async loadData(): Promise { + let result: any; + if (this.row) { + result = this.row; + } else { + result = await queryHelper.first({ + text: "SELECT * FROM users WHERE user.id = $1", + values: [this.id], + }); + } + if (result) { + this.$name = result.name; + this.$handle = result.handle; + this.$email = result.email; + this.$greenpoints = result.greenpoints; + this.$joinedAt = result.joined_at; + this.dataLoaded = true; + } + } +} diff --git a/src/lib/DTO.ts b/src/lib/dataaccess/index.ts similarity index 98% rename from src/lib/DTO.ts rename to src/lib/dataaccess/index.ts index 2d93484..6325227 100644 --- a/src/lib/DTO.ts +++ b/src/lib/dataaccess/index.ts @@ -1,7 +1,7 @@ import {Runtime} from "inspector"; import {Pool} from "pg"; -import globals from "./globals"; -import {QueryHelper} from "./QueryHelper"; +import globals from "../globals"; +import {QueryHelper} from "../QueryHelper"; const config = globals.config; const tableCreationFile = __dirname + "/../sql/create-tables.sql"; diff --git a/src/public/graphql/schema.graphql b/src/public/graphql/schema.graphql index f5feb67..fb04f53 100644 --- a/src/public/graphql/schema.graphql +++ b/src/public/graphql/schema.graphql @@ -1,100 +1,129 @@ type Query { - "returns the user object for a given user id" - getUser(userId: ID): User - "returns the post object for a post id" - getPost(postId: ID): Post - "returns the chat object for a chat id" - getChat(chatId: ID): ChatRoom - "returns the request object for a request id" - getRequest(requestId: ID): Request - "find a post by the posted date or content" - findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post] - "find a user by user name or handle" - findUser(first: Int, offset: Int, name: String!, handle: String!): [User] + "returns the user object for a given user id" + getUser(userId: ID): User + + "returns the post object for a post id" + getPost(postId: ID): Post + + "returns the chat object for a chat id" + getChat(chatId: ID): ChatRoom + + "returns the request object for a request id" + getRequest(requestId: ID): Request + + "find a post by the posted date or content" + findPost(first: Int, offset: Int, text: String!, postedDate: String): [Post] + + "find a user by user name or handle" + findUser(first: Int, offset: Int, name: String!, handle: String!): [User] } type Mutation { - "Upvote/downvote a Post" - vote(postId: ID!, type: [VoteType!]!): Boolean - "Report the post" - report(postId: ID!): Boolean + "Upvote/downvote a Post" + vote(postId: ID!, type: [VoteType!]!): Boolean + + "Report the post" + report(postId: ID!): Boolean + "lets you accept a request for a given request id" - acceptRequest(requestId: ID!): Boolean + acceptRequest(requestId: ID!): Boolean + "send a message in a Chatroom" - sendMessage(chatId: ID!, content: String!): Boolean + sendMessage(chatId: ID!, content: String!): Boolean + + # TODO: createPost, deletePost, sendRequest, denyRequest } "represents a single user account" type User { - "url for the Profile picture of the User" - profilePicture: String! - "name of the User" - name: String! - "unique identifier name from the User" - handle: String! - "Id of the User" - id: ID! - "the total number of posts the user posted" - numberOfPosts: Int - "returns a given number of posts of a user" - getAllPosts(first: Int=10, offset: Int): [Post] - "creation date of the user account" - joinedDate: String! - "returns chats the user pinned" - pinnedChats: [ChatRoom] - "returns all friends of the user" - friends: [User] - "all request for groupChats/friends/events" - requests: [Request] + "url for the Profile picture of the User" + profilePicture: String! + + "name of the User" + name: String! + + "unique identifier name from the User" + handle: String! + + "Id of the User" + id: ID! + + "the total number of posts the user posted" + numberOfPosts: Int + + "returns a given number of posts of a user" + getAllPosts(first: Int=10, offset: Int): [Post] + + "creation date of the user account" + joinedDate: String! + + "returns chats the user pinned" + pinnedChats: [ChatRoom] + + "returns all friends of the user" + friends: [User] + + "all request for groupChats/friends/events" + requests: [Request] } "represents a single user post" type Post { - "returns the path to the posts picture if it has one" - picture: String - "returns the text of the post" - text: String - "upvotes of the Post" - upvotes: Int! - "downvotes of the Post" - downvotes: Int! - "the user that is the author of the Post" - author: User! - "date the post was created" - creationDate: String! - "returns the type of vote the user performed on the post" - alreadyVoted: VoteType - "returns the tags of the post" - tags: [String] + "returns the path to the posts picture if it has one" + picture: String + + "returns the text of the post" + text: String + + "upvotes of the Post" + upvotes: Int! + + "downvotes of the Post" + downvotes: Int! + + "the user that is the author of the Post" + author: User! + + "date the post was created" + creationDate: String! + + "returns the type of vote the user performed on the post" + userVote: VoteType + + "returns the tags of the post" + tags: [String] } "represents a request of any type" type Request { - "id of the request" - id: ID! - "type of the request" - requestType: RequestType! + "id of the request" + id: ID! + + "type of the request" + requestType: RequestType! } "represents a chatroom" type ChatRoom { - "the members of the chatroom" - members: [User!] - "return a specfic range of messages posted in the chat" - getMessages(first: Int, offset: Int): [String] - "id of the chat" - id: ID! + "the members of the chatroom" + members: [User!] + + "return a specfic range of messages posted in the chat" + getMessages(first: Int, offset: Int): [String] + + "id of the chat" + id: ID! } "represents the type of vote performed on a post" enum VoteType { - UPVOTE - DOWNVOTE + UPVOTE + DOWNVOTE } "represents the type of request that the user has received" enum RequestType { - FRIENDREQUEST - GROUPINVITE - EVENTINVITE + FRIENDREQUEST + GROUPINVITE + EVENTINVITE } diff --git a/src/sql/create-tables.sql b/src/sql/create-tables.sql index 0d02b2f..7a6292e 100644 --- a/src/sql/create-tables.sql +++ b/src/sql/create-tables.sql @@ -20,7 +20,8 @@ CREATE TABLE IF NOT EXISTS posts ( CREATE TABLE IF NOT EXISTS votes ( user_id SERIAL REFERENCES users (id) ON DELETE CASCADE, - item_id BIGSERIAL REFERENCES posts (id) ON DELETE CASCADE + item_id BIGSERIAL REFERENCES posts (id) ON DELETE CASCADE, + vote_type varchar(8) DEFAULT 1 ); CREATE TABLE IF NOT EXISTS events ( From 67650267421d1e91400771c4cf9c3cac27c93890 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sat, 21 Sep 2019 13:34:58 +0200 Subject: [PATCH 2/6] Changed dataAccess index --- src/lib/dataaccess/index.ts | 219 +++--------------------------------- 1 file changed, 17 insertions(+), 202 deletions(-) diff --git a/src/lib/dataaccess/index.ts b/src/lib/dataaccess/index.ts index 6325227..8019329 100644 --- a/src/lib/dataaccess/index.ts +++ b/src/lib/dataaccess/index.ts @@ -1,7 +1,7 @@ -import {Runtime} from "inspector"; import {Pool} from "pg"; import globals from "../globals"; import {QueryHelper} from "../QueryHelper"; +import {User} from "./User"; const config = globals.config; const tableCreationFile = __dirname + "/../sql/create-tables.sql"; @@ -12,27 +12,21 @@ const dbClient: Pool = new Pool({ port: config.database.port, user: config.database.user, }); -const queryHelper = new QueryHelper(dbClient, tableCreationFile); - -export class DTO { - private queryHelper: QueryHelper; - - constructor() { - this.queryHelper = queryHelper; - } +export const queryHelper = new QueryHelper(dbClient, tableCreationFile); +namespace dataaccess { /** * Initializes everything that needs to be initialized asynchronous. */ - public async init() { - await this.queryHelper.createTables(); + export async function init() { + await queryHelper.createTables(); } /** * Returns the user by id * @param userId */ - public getUser(userId: number) { + export function getUser(userId: number) { return new User(userId); } @@ -40,209 +34,30 @@ export class DTO { * Returns the user by handle. * @param userHandle */ - public async getUserByHandle(userHandle: string) { + export async function getUserByHandle(userHandle: string) { const result = await this.queryHelper.first({ text: "SELECT * FROM users WHERE users.handle = $1", values: [userHandle], }); return new User(result.id, result); } -} - -export class User { - public readonly id: number; - private $name: string; - private $handle: string; - private $email: string; - private $greenpoints: number; - private $joinedAt: string; - private dataLoaded: boolean; - - /** - * Constructor of the user - * @param id - * @param row - */ - constructor(id: number, private row?: any) { - this.id = id; - } - - /** - * The name of the user - */ - public async name(): Promise { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$name; - } - - /** - * Sets the username of the user - * @param name - */ - public async setName(name: string): Promise { - const result = await queryHelper.first({ - text: "UPDATE TABLE users SET name = $1 WHERE id = $2", - values: [name, this.id], - }); - return result.name; - } - - /** - * The unique handle of the user. - */ - public async handle(): Promise { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$handle; - } - - /** - * Updates the handle of the user - */ - public async setHandle(handle: string): Promise { - const result = await queryHelper.first({ - text: "UPDATE TABLE users SET handle = $1 WHERE id = $2", - values: [handle, this.id], - }); - return result.handle; - } - - /** - * The email of the user - */ - public async email(): Promise { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$email; - } - - /** - * Sets the email of the user - * @param email - */ - public async setEmail(email: string): Promise { - const result = await queryHelper.first({ - text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email", - values: [email, this.id], - }); - return result.email; - } - - /** - * The number of greenpoints of the user - */ - public async greenpoints(): Promise { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$greenpoints; - } - - /** - * Sets the greenpoints of a user. - * @param points - */ - public async setGreenpoints(points: number): Promise { - const result = await queryHelper.first({ - text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints", - values: [points, this.id], - }); - return result.greenpoints; - } /** - * The date the user joined the platform + * Enum representing the types of votes that can be performed on a post. */ - public async joinedAt(): Promise { - if (!this.dataLoaded) { - await this.loadData(); - } - return new Date(this.$joinedAt); + export enum VoteType { + UPVOTE = "UPVOTE", + DOWNVOTE = "DOWNVOTE", } /** - * Fetches the data for the user. + * Enum representing the types of request that can be created. */ - private async loadData(): Promise { - let result: any; - if (this.row) { - result = this.row; - } else { - result = await queryHelper.first({ - text: "SELECT * FROM users WHERE user.id = $1", - values: [this.id], - }); - } - if (result) { - this.$name = result.name; - this.$handle = result.handle; - this.$email = result.email; - this.$greenpoints = result.greenpoints; - this.$joinedAt = result.joined_at; - this.dataLoaded = true; - } + export enum RequestType { + FRIENDREQUEST = "FRIENDREQUEST", + GROUPINVITE = "GROUPINVITE", + EVENTINVITE = "EVENTINVITE", } } -export class Post { - public readonly id: number; - private $upvotes: number; - private $downvotes: number; - private $createdAt: string; - private $content: string; - private $author: number; - private $type: string; - private dataLoaded: boolean = false; - - constructor(id: number, private row?: any) { - this.id = id; - } - - /** - * Returns the upvotes of a post. - */ - public async upvotes() { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$upvotes; - } - - /** - * Returns the downvotes of the post - */ - public async downvotes() { - if (!this.dataLoaded) { - await this.loadData(); - } - return this.$downvotes; - } - - /** - * Loads the data from the database if needed. - */ - private async loadData(): Promise { - let result: any; - if (this.row) { - result = this.row; - } else { - result = await queryHelper.first({ - text: "SELECT * FROM posts WHERE posts.id = $1", - values: [this.id], - }); - } - if (result) { - this.$author = result.author; - this.$content = result.content; - this.$downvotes = result.downvotes; - this.$upvotes = result.upvotes; - this.$createdAt = result.created_at; - this.$type = result.type; - this.dataLoaded = true; - } - } -} +export default dataaccess; From 65d5cee2bb2914c6b83a460e2bdd81e0299abd9a Mon Sep 17 00:00:00 2001 From: RandomUser27 Date: Sun, 22 Sep 2019 13:14:37 +0200 Subject: [PATCH 3/6] package.json --- package-lock.json | 33 +++++++++++++++++++-------------- package.json | 1 + 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 212f9d3..c35e90d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -939,9 +939,9 @@ } }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -1723,9 +1723,9 @@ } }, "es5-ext": { - "version": "0.10.50", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", - "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "version": "0.10.51", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.51.tgz", + "integrity": "sha512-oRpWzM2WcLHVKpnrcyB7OW8j/s67Ba04JCm0WnNv3RiABSvs7mrQlutB8DBv793gKcp0XENR8Il8WxGTlZ73gQ==", "dev": true, "requires": { "es6-iterator": "~2.0.3", @@ -1745,13 +1745,13 @@ } }, "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.2.tgz", + "integrity": "sha512-/ZypxQsArlv+KHpGvng52/Iz8by3EQPxhmbuz8yFG89N/caTFBSbcXONDw0aMjy827gQg26XAjP4uXFvnfINmQ==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "d": "^1.0.1", + "es5-ext": "^0.10.51" } }, "es6-weak-map": { @@ -2893,6 +2893,11 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "g": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/g/-/g-2.0.1.tgz", + "integrity": "sha1-C1lj69DKcOO8jGdmk0oCGCHIuFc=" + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -6625,9 +6630,9 @@ } }, "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", "dev": true }, "uri-js": { diff --git a/package.json b/package.json index ae3c9f0..242fe85 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "express-session": "^1.16.2", "express-socket.io-session": "^1.3.5", "fs-extra": "^8.1.0", + "g": "^2.0.1", "graphql": "^14.4.2", "graphql-import": "^0.7.1", "js-yaml": "^3.13.1", From b623018f76d61ab951924a4847bc8f6c2723b233 Mon Sep 17 00:00:00 2001 From: RandomUser27 Date: Sun, 22 Sep 2019 13:36:17 +0200 Subject: [PATCH 4/6] schema.graphql added: send reqest; deny request; post the post; sender and reciverid from request; --- src/public/graphql/schema.graphql | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/public/graphql/schema.graphql b/src/public/graphql/schema.graphql index fb04f53..e4705d6 100644 --- a/src/public/graphql/schema.graphql +++ b/src/public/graphql/schema.graphql @@ -25,13 +25,23 @@ type Mutation { "Report the post" report(postId: ID!): Boolean + "send a request" + sendRequest(request: Request!): Boolean + "lets you accept a request for a given request id" acceptRequest(requestId: ID!): Boolean + "lets you deny a request for a given request id" + denyRequest(requestId: ID!): Boolean + "send a message in a Chatroom" sendMessage(chatId: ID!, content: String!): Boolean - # TODO: createPost, deletePost, sendRequest, denyRequest + "create the post" + createPost(post: Post!): Boolean + + "delete the post for a given post id" + deletePost(postId: ID!): Boolean } "represents a single user account" @@ -99,6 +109,12 @@ type Request { "id of the request" id: ID! + "Id of the user who sended the request" + sender: User! + + "Id of the user who received the request" + receiver: User! + "type of the request" requestType: RequestType! } From ff77c14beca90be7a63fb862a91bb72120b09cb8 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sun, 22 Sep 2019 20:14:04 +0200 Subject: [PATCH 5/6] Fixed Database Integration - fixed wrong table creation path - added table update path --- src/lib/QueryHelper.ts | 16 ++++++++++++++-- src/lib/dataaccess/DataObject.ts | 8 +++++++- src/lib/dataaccess/Post.ts | 6 ++++-- src/lib/dataaccess/User.ts | 1 + src/lib/dataaccess/index.ts | 7 +++++-- src/sql/create-tables.sql | 2 +- src/sql/update-tables.sql | 3 +++ 7 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 src/sql/update-tables.sql diff --git a/src/lib/QueryHelper.ts b/src/lib/QueryHelper.ts index 7586276..5970f70 100644 --- a/src/lib/QueryHelper.ts +++ b/src/lib/QueryHelper.ts @@ -68,9 +68,10 @@ export class QueryHelper { /** * Constructor. * @param pgPool - * @param tableCreationFile + * @param [tableCreationFile] + * @param [tableUpdateFile] */ - constructor(pgPool: Pool, private tableCreationFile?: string) { + constructor(pgPool: Pool, private tableCreationFile?: string, private tableUpdateFile?: string) { this.pool = pgPool; } @@ -85,6 +86,17 @@ export class QueryHelper { } } + /** + * Updates the definition of the tables if the table update file was passed in the constructor + */ + public async updateTableDefinitions() { + if (this.tableUpdateFile) { + logger.info("Updating table definitions..."); + const tableSql = await fsx.readFile(this.tableUpdateFile, "utf-8"); + await this.query({text: tableSql}); + } + } + /** * executes the sql query with values and returns all results. * @param query diff --git a/src/lib/dataaccess/DataObject.ts b/src/lib/dataaccess/DataObject.ts index afabc32..1890425 100644 --- a/src/lib/dataaccess/DataObject.ts +++ b/src/lib/dataaccess/DataObject.ts @@ -1,4 +1,7 @@ -abstract class DataObject { +/** + * abstact DataObject class + */ +export abstract class DataObject { protected dataLoaded: boolean = false; constructor(public id: number, protected row?: any) { @@ -6,6 +9,9 @@ abstract class DataObject { protected abstract loadData(): Promise; + /** + * Loads data from the database if data has not been loaded + */ protected loadDataIfNotExists() { if (this.dataLoaded) { this.loadData(); diff --git a/src/lib/dataaccess/Post.ts b/src/lib/dataaccess/Post.ts index 51c6b4c..b4193c4 100644 --- a/src/lib/dataaccess/Post.ts +++ b/src/lib/dataaccess/Post.ts @@ -1,4 +1,6 @@ -import {queryHelper, VoteType} from "./index"; +import {DataObject} from "./DataObject"; +import {queryHelper} from "./index"; +import dataaccess from "./index"; import {User} from "./User"; export class Post extends DataObject { @@ -63,7 +65,7 @@ export class Post extends DataObject { /** * The type of vote the user performed on the post. */ - public async userVote(userId: number): Promise { + public async userVote(userId: number): Promise { const result = await queryHelper.first({ text: "SELECT vote_type FROM votes WHERE user_id = $1 AND item_id = $2", values: [userId, this.id], diff --git a/src/lib/dataaccess/User.ts b/src/lib/dataaccess/User.ts index ea7c7c9..bb680c4 100644 --- a/src/lib/dataaccess/User.ts +++ b/src/lib/dataaccess/User.ts @@ -1,3 +1,4 @@ +import {DataObject} from "./DataObject"; import {queryHelper} from "./index"; import {Post} from "./Post"; diff --git a/src/lib/dataaccess/index.ts b/src/lib/dataaccess/index.ts index 8019329..1d610ef 100644 --- a/src/lib/dataaccess/index.ts +++ b/src/lib/dataaccess/index.ts @@ -4,7 +4,9 @@ import {QueryHelper} from "../QueryHelper"; import {User} from "./User"; const config = globals.config; -const tableCreationFile = __dirname + "/../sql/create-tables.sql"; +const tableCreationFile = __dirname + "/../../sql/create-tables.sql"; +const tableUpdateFile = __dirname + "/../../sql/update-tables.sql"; + const dbClient: Pool = new Pool({ database: config.database.database, host: config.database.host, @@ -12,13 +14,14 @@ const dbClient: Pool = new Pool({ port: config.database.port, user: config.database.user, }); -export const queryHelper = new QueryHelper(dbClient, tableCreationFile); +export const queryHelper = new QueryHelper(dbClient, tableCreationFile, tableUpdateFile); namespace dataaccess { /** * Initializes everything that needs to be initialized asynchronous. */ export async function init() { + await queryHelper.updateTableDefinitions(); await queryHelper.createTables(); } diff --git a/src/sql/create-tables.sql b/src/sql/create-tables.sql index 7a6292e..7c1c97a 100644 --- a/src/sql/create-tables.sql +++ b/src/sql/create-tables.sql @@ -21,7 +21,7 @@ CREATE TABLE IF NOT EXISTS posts ( CREATE TABLE IF NOT EXISTS votes ( user_id SERIAL REFERENCES users (id) ON DELETE CASCADE, item_id BIGSERIAL REFERENCES posts (id) ON DELETE CASCADE, - vote_type varchar(8) DEFAULT 1 + vote_type varchar(8) DEFAULT 'upvote' ); CREATE TABLE IF NOT EXISTS events ( diff --git a/src/sql/update-tables.sql b/src/sql/update-tables.sql new file mode 100644 index 0000000..52ce2f6 --- /dev/null +++ b/src/sql/update-tables.sql @@ -0,0 +1,3 @@ +ALTER TABLE IF EXISTS votes + ADD COLUMN IF NOT EXISTS vote_type varchar(8) DEFAULT 'upvote', + ALTER COLUMN vote_type SET DEFAULT 'upvote'; From 9d26d248d7ff603c1fad9406fa71c1a97b48bf04 Mon Sep 17 00:00:00 2001 From: Trivernis Date: Sun, 22 Sep 2019 20:17:38 +0200 Subject: [PATCH 6/6] Fixed Graphql Schema - removed Query types used as Input types --- src/public/graphql/schema.graphql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/public/graphql/schema.graphql b/src/public/graphql/schema.graphql index e4705d6..ff60fd3 100644 --- a/src/public/graphql/schema.graphql +++ b/src/public/graphql/schema.graphql @@ -26,7 +26,7 @@ type Mutation { report(postId: ID!): Boolean "send a request" - sendRequest(request: Request!): Boolean + sendRequest(reciever: ID!, type: RequestType): Boolean "lets you accept a request for a given request id" acceptRequest(requestId: ID!): Boolean @@ -38,7 +38,7 @@ type Mutation { sendMessage(chatId: ID!, content: String!): Boolean "create the post" - createPost(post: Post!): Boolean + createPost(text: String, picture: String, tags: [String]): Boolean "delete the post for a given post id" deletePost(postId: ID!): Boolean