From 00235fc0ac08477c023fef51367e092103bed841 Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Sat, 28 Mar 2020 15:23:05 -0700 Subject: [PATCH 1/8] Change item.artist and item.title to be required fields --- generated/binding.ts | 8 ++++---- generated/classes.ts | 8 ++++---- generated/schema.graphql | 8 ++++---- src/modules/item/item.model.ts | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/generated/binding.ts b/generated/binding.ts index 2801edf..ea3616c 100644 --- a/generated/binding.ts +++ b/generated/binding.ts @@ -184,9 +184,9 @@ export interface ItemCreateInput { mbid?: String | null rymId?: Float | null spotifyId?: ID_Input | null - title?: String | null + title: String disambiguation?: String | null - artist?: String | null + artist: String } export interface ItemUpdateInput { @@ -375,9 +375,9 @@ export interface Item extends BaseGraphQLObject { mbid?: String | null rymId?: Int | null spotifyId?: String | null - title?: String | null + title: String disambiguation?: String | null - artist?: String | null + artist: String collectionItem?: Array | null } diff --git a/generated/classes.ts b/generated/classes.ts index 7d68af5..81f61da 100644 --- a/generated/classes.ts +++ b/generated/classes.ts @@ -414,14 +414,14 @@ export class ItemCreateInput { @TypeGraphQLField(() => ID, { nullable: true }) spotifyId?: string; - @TypeGraphQLField({ nullable: true }) - title?: string; + @TypeGraphQLField() + title!: string; @TypeGraphQLField({ nullable: true }) disambiguation?: string; - @TypeGraphQLField({ nullable: true }) - artist?: string; + @TypeGraphQLField() + artist!: string; } @TypeGraphQLInputType() diff --git a/generated/schema.graphql b/generated/schema.graphql index 87bf0fb..835a46e 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -166,9 +166,9 @@ type Item implements BaseGraphQLObject { mbid: String rymId: Int spotifyId: String - title: String + title: String! disambiguation: String - artist: String + artist: String! collectionItem: [CollectionItem!] } @@ -176,9 +176,9 @@ input ItemCreateInput { mbid: String rymId: Float spotifyId: ID - title: String + title: String! disambiguation: String - artist: String + artist: String! } enum ItemOrderByInput { diff --git a/src/modules/item/item.model.ts b/src/modules/item/item.model.ts index 5f32562..6c90d6b 100644 --- a/src/modules/item/item.model.ts +++ b/src/modules/item/item.model.ts @@ -12,14 +12,14 @@ export class Item extends BaseModel { @StringField({ nullable: true }) spotifyId?: string; - @StringField({ nullable: true }) - title?: string; + @StringField() + title!: string; @StringField({ nullable: true }) disambiguation?: string; - @StringField({ nullable: true }) - artist?: string; + @StringField() + artist!: string; @OneToMany( () => CollectionItem, From 51e5975022de925d2a0ba675e095ba5470ada1ac Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Fri, 3 Apr 2020 17:52:12 -0700 Subject: [PATCH 2/8] Added basic auth --- src/modules/user/user.resolver.ts | 3 ++- src/server.ts | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/modules/user/user.resolver.ts b/src/modules/user/user.resolver.ts index 168803d..3e36b53 100644 --- a/src/modules/user/user.resolver.ts +++ b/src/modules/user/user.resolver.ts @@ -1,4 +1,4 @@ -import { Arg, Args, Mutation, Query, Resolver, FieldResolver, Root, Ctx } from 'type-graphql'; +import { Arg, Args, Mutation, Query, Resolver, FieldResolver, Root, Ctx, Authorized } from 'type-graphql'; import { Inject } from 'typedi'; import { Fields, StandardDeleteResponse, UserId, BaseContext } from 'warthog'; @@ -37,6 +37,7 @@ export class UserResolver { return ctx.dataLoader.loaders.User.collection.load(user); } + @Authorized('signedIn') @Mutation(() => User) async createUser(@Arg('data') data: UserCreateInput, @UserId() userId: string): Promise { return this.service.create(data, userId); diff --git a/src/server.ts b/src/server.ts index 59b80df..e9bacde 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,6 @@ import 'reflect-metadata'; -import { BaseContext, Server } from 'warthog'; +import { BaseContext, Server, authChecker } from 'warthog'; import { Logger } from './logger'; @@ -15,13 +15,15 @@ interface Context extends BaseContext { export function getServer(AppOptions = {}, dbOptions = {}) { return new Server( { + authChecker, // Inject a fake user. In a real app you'd parse a JWT to add the user context: (request: any) => { const userId = JSON.stringify(request.headers).length.toString(); return { user: { - id: `user:${userId}` + id: `user:${userId}`, + permissions: ['signedIn'] } }; }, From 14698d4e779e436cce27652b907cf6028e67b538 Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Sat, 11 Apr 2020 16:05:19 -0700 Subject: [PATCH 3/8] Updated warthog to 2.6.0 --- README.md | 5 ++++- docker-compose.yml | 2 +- package.json | 2 +- yarn.lock | 14 ++++++++++---- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1d3a2f6..726b419 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ -docker-compose exec -u postgres postgres psql \ No newline at end of file +docker-compose exec -u postgres postgres psql +\l +\c +\dt diff --git a/docker-compose.yml b/docker-compose.yml index 8a6cd18..88d3b01 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '2.4' services: postgres: - image: postgres:11 + image: postgres:12 restart: always volumes: - ./db_data:/var/lib/postgresql/data diff --git a/package.json b/package.json index 4cbe159..df5c35d 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "dotenv": "^8.0.0", "dotenvi": "^0.6.0", "reflect-metadata": "^0.1.13", - "warthog": "^2.1.1" + "warthog": "^2.6.0" }, "devDependencies": { "@types/jest": "^24.0.15", diff --git a/yarn.lock b/yarn.lock index b3ecacb..64e375e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2741,6 +2741,11 @@ graphql-fields@^2.0.3: resolved "https://registry.yarnpkg.com/graphql-fields/-/graphql-fields-2.0.3.tgz#5e68dff7afbb202be4f4f40623e983b22c96ab8f" integrity sha512-x3VE5lUcR4XCOxPIqaO4CE+bTK8u6gVouOdpQX9+EKHr+scqtK5Pp/l8nIGqIpN1TUlkKE6jDCCycm/WtLRAwA== +graphql-import-node@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/graphql-import-node/-/graphql-import-node-0.0.4.tgz#0522f058978c7e1b99d1e6be1b851ee17007b111" + integrity sha512-okpdABQIgIM0qdx9Mfgdu6fTsFEazZmHZdEU34cijkUj9D1db1SyPRGHPxbXmbacamhEF41ckxpCAgHiGliryQ== + graphql-import@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223" @@ -6205,10 +6210,10 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -warthog@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/warthog/-/warthog-2.1.1.tgz#61a1919099b43983169c74fca5892dcecd77ab4a" - integrity sha512-kmKtcAAZITP+O1BTGDVrV5lqPJJSMoG9W8tVGPmzSftO5polVuvLnOQBKCNqocMsvEoVKEQtrcfLVlx+he7neA== +warthog@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/warthog/-/warthog-2.6.0.tgz#cad6373a226b36a695f01a409ce345f570d11710" + integrity sha512-I0n+8+FULUqO464FVgfC8wLgqffsINWZ/4NNjBtbGG2whdn0vWOrg+FwyM+haY5jnncG3jtJ3Q4j1PrfH7xGiQ== dependencies: "@types/app-root-path" "^1.2.4" "@types/caller" "^1.0.0" @@ -6247,6 +6252,7 @@ warthog@^2.1.1: graphql "^14.5.8" graphql-binding "^2.5.2" graphql-fields "^2.0.3" + graphql-import-node "^0.0.4" graphql-iso-date "^3.6.1" graphql-tools "^4.0.6" graphql-type-json "^0.3.0" From aab28e3922163aa40680556039064107ecf2953a Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Thu, 16 Apr 2020 15:23:10 -0700 Subject: [PATCH 4/8] Updated schema to match v0.1 frontend --- db/migrations/1587075769273-True.ts | 30 ++ generated/binding.ts | 324 ++++++++--- generated/classes.ts | 503 +++++++++++++++--- generated/schema.graphql | 309 ++++++++--- package.json | 9 +- src/interfaces/account-settings.ts | 3 + .../collection-item/collection-item.model.ts | 42 +- src/modules/review/review.model.ts | 20 + src/modules/review/review.resolver.ts | 65 +++ src/modules/review/review.service.ts | 13 + src/modules/user/user.model.ts | 16 +- 11 files changed, 1121 insertions(+), 213 deletions(-) create mode 100644 db/migrations/1587075769273-True.ts create mode 100644 src/interfaces/account-settings.ts create mode 100644 src/modules/review/review.model.ts create mode 100644 src/modules/review/review.resolver.ts create mode 100644 src/modules/review/review.service.ts diff --git a/db/migrations/1587075769273-True.ts b/db/migrations/1587075769273-True.ts new file mode 100644 index 0000000..12c466c --- /dev/null +++ b/db/migrations/1587075769273-True.ts @@ -0,0 +1,30 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class True1587075769273 implements MigrationInterface { + name = 'True1587075769273' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "reviews" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "collection_item_id" character varying NOT NULL, "rating" character varying, "title" character varying, "review_text" character varying, CONSTRAINT "PK_231ae565c273ee700b283f15c1d" PRIMARY KEY ("id"))`, undefined); + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "rating"`, undefined); + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "review"`, undefined); + await queryRunner.query(`ALTER TABLE "users" ADD "password" character varying NOT NULL`, undefined); + await queryRunner.query(`ALTER TABLE "users" ADD "salt" character varying NOT NULL`, undefined); + await queryRunner.query(`ALTER TABLE "users" ADD "account_settings" jsonb`, undefined); + await queryRunner.query(`ALTER TABLE "collection_items" ADD "plays" integer DEFAULT 0`, undefined); + await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email")`, undefined); + await queryRunner.query(`ALTER TABLE "reviews" ADD CONSTRAINT "FK_fc090d3e6b0a3b369f03d9aa673" FOREIGN KEY ("collection_item_id") REFERENCES "collection_items"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, undefined); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "reviews" DROP CONSTRAINT "FK_fc090d3e6b0a3b369f03d9aa673"`, undefined); + await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3"`, undefined); + await queryRunner.query(`ALTER TABLE "collection_items" DROP COLUMN "plays"`, undefined); + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "account_settings"`, undefined); + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "salt"`, undefined); + await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "password"`, undefined); + await queryRunner.query(`ALTER TABLE "items" ADD "review" character varying`, undefined); + await queryRunner.query(`ALTER TABLE "items" ADD "rating" character varying`, undefined); + await queryRunner.query(`DROP TABLE "reviews"`, undefined); + } + +} diff --git a/generated/binding.ts b/generated/binding.ts index ea3616c..273ffa0 100644 --- a/generated/binding.ts +++ b/generated/binding.ts @@ -1,3 +1,5 @@ +import 'graphql-import-node'; // Needed so you can import *.graphql files + import { makeBindingClass, Options } from 'graphql-binding' import { GraphQLResolveInfo, GraphQLSchema } from 'graphql' import { IResolvers } from 'graphql-tools/dist/Interfaces' @@ -8,6 +10,8 @@ export interface Query { collectionItem: (args: { where: CollectionItemWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , items: >(args: { offset?: Int | null, limit?: Int | null, where?: ItemWhereInput | null, orderBy?: ItemOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , item: (args: { where: ItemWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + reviews: >(args: { offset?: Int | null, limit?: Int | null, where?: ReviewWhereInput | null, orderBy?: ReviewOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + review: (args: { where: ReviewWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , users: >(args: { offset?: Int | null, limit?: Int | null, where?: UserWhereInput | null, orderBy?: UserOrderByInput | null }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , user: (args: { where: UserWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise } @@ -21,6 +25,10 @@ export interface Mutation { createManyItems: >(args: { data: Array }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , updateItem: (args: { data: ItemUpdateInput, where: ItemWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , deleteItem: (args: { where: ItemWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + createReview: (args: { data: ReviewCreateInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + createManyReviews: >(args: { data: Array }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + updateReview: (args: { data: ReviewUpdateInput, where: ReviewWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , + deleteReview: (args: { where: ReviewWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , createUser: (args: { data: UserCreateInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , createManyUsers: >(args: { data: Array }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , updateUser: (args: { data: UserUpdateInput, where: UserWhereUniqueInput }, info?: GraphQLResolveInfo | string, options?: Options) => Promise , @@ -47,7 +55,7 @@ export interface BindingConstructor { new(...args: any[]): T } -export const Binding = makeBindingClass>({ schema }) +export const Binding = makeBindingClass>({ schema: schema as any }) /** * Types @@ -66,7 +74,15 @@ export type CollectionItemOrderByInput = 'createdAt_ASC' | 'userId_ASC' | 'userId_DESC' | 'itemDetailsId_ASC' | - 'itemDetailsId_DESC' + 'itemDetailsId_DESC' | + 'plays_ASC' | + 'plays_DESC' | + 'artist_ASC' | + 'artist_DESC' | + 'title_ASC' | + 'title_DESC' | + 'mbid_ASC' | + 'mbid_DESC' export type ItemOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | @@ -87,6 +103,21 @@ export type ItemOrderByInput = 'createdAt_ASC' | 'artist_ASC' | 'artist_DESC' +export type ReviewOrderByInput = 'createdAt_ASC' | + 'createdAt_DESC' | + 'updatedAt_ASC' | + 'updatedAt_DESC' | + 'deletedAt_ASC' | + 'deletedAt_DESC' | + 'collectionItemId_ASC' | + 'collectionItemId_DESC' | + 'rating_ASC' | + 'rating_DESC' | + 'title_ASC' | + 'title_DESC' | + 'reviewText_ASC' | + 'reviewText_DESC' + export type UserOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | 'updatedAt_ASC' | @@ -129,6 +160,10 @@ export interface CollectionItemCreateInput { customArtist?: String | null userId: ID_Output itemDetailsId: ID_Output + plays?: Float | null + artist: String + title: String + mbid?: String | null } export interface CollectionItemUpdateInput { @@ -136,30 +171,37 @@ export interface CollectionItemUpdateInput { customArtist?: String | null userId?: ID_Input | null itemDetailsId?: ID_Input | null + plays?: Float | null + artist?: String | null + title?: String | null + mbid?: String | null } export interface CollectionItemWhereInput { - id_eq?: String | null - id_in?: String[] | String | null - createdAt_eq?: String | null - createdAt_lt?: String | null - createdAt_lte?: String | null - createdAt_gt?: String | null - createdAt_gte?: String | null - createdById_eq?: String | null - updatedAt_eq?: String | null - updatedAt_lt?: String | null - updatedAt_lte?: String | null - updatedAt_gt?: String | null - updatedAt_gte?: String | null - updatedById_eq?: String | null + id_eq?: ID_Input | null + id_in?: ID_Output[] | ID_Output | null + createdAt_eq?: DateTime | null + createdAt_lt?: DateTime | null + createdAt_lte?: DateTime | null + createdAt_gt?: DateTime | null + createdAt_gte?: DateTime | null + createdById_eq?: ID_Input | null + createdById_in?: ID_Output[] | ID_Output | null + updatedAt_eq?: DateTime | null + updatedAt_lt?: DateTime | null + updatedAt_lte?: DateTime | null + updatedAt_gt?: DateTime | null + updatedAt_gte?: DateTime | null + updatedById_eq?: ID_Input | null + updatedById_in?: ID_Output[] | ID_Output | null deletedAt_all?: Boolean | null - deletedAt_eq?: String | null - deletedAt_lt?: String | null - deletedAt_lte?: String | null - deletedAt_gt?: String | null - deletedAt_gte?: String | null - deletedById_eq?: String | null + deletedAt_eq?: DateTime | null + deletedAt_lt?: DateTime | null + deletedAt_lte?: DateTime | null + deletedAt_gt?: DateTime | null + deletedAt_gte?: DateTime | null + deletedById_eq?: ID_Input | null + deletedById_in?: ID_Output[] | ID_Output | null customTitle_eq?: String | null customTitle_contains?: String | null customTitle_startsWith?: String | null @@ -174,16 +216,37 @@ export interface CollectionItemWhereInput { userId_in?: ID_Output[] | ID_Output | null itemDetailsId_eq?: ID_Input | null itemDetailsId_in?: ID_Output[] | ID_Output | null + plays_eq?: Int | null + plays_gt?: Int | null + plays_gte?: Int | null + plays_lt?: Int | null + plays_lte?: Int | null + plays_in?: Int[] | Int | null + artist_eq?: String | null + artist_contains?: String | null + artist_startsWith?: String | null + artist_endsWith?: String | null + artist_in?: String[] | String | null + title_eq?: String | null + title_contains?: String | null + title_startsWith?: String | null + title_endsWith?: String | null + title_in?: String[] | String | null + mbid_eq?: String | null + mbid_contains?: String | null + mbid_startsWith?: String | null + mbid_endsWith?: String | null + mbid_in?: String[] | String | null } export interface CollectionItemWhereUniqueInput { - id: String + id: ID_Output } export interface ItemCreateInput { mbid?: String | null rymId?: Float | null - spotifyId?: ID_Input | null + spotifyId?: String | null title: String disambiguation?: String | null artist: String @@ -192,34 +255,37 @@ export interface ItemCreateInput { export interface ItemUpdateInput { mbid?: String | null rymId?: Float | null - spotifyId?: ID_Input | null + spotifyId?: String | null title?: String | null disambiguation?: String | null artist?: String | null } export interface ItemWhereInput { - id_eq?: String | null - id_in?: String[] | String | null - createdAt_eq?: String | null - createdAt_lt?: String | null - createdAt_lte?: String | null - createdAt_gt?: String | null - createdAt_gte?: String | null - createdById_eq?: String | null - updatedAt_eq?: String | null - updatedAt_lt?: String | null - updatedAt_lte?: String | null - updatedAt_gt?: String | null - updatedAt_gte?: String | null - updatedById_eq?: String | null + id_eq?: ID_Input | null + id_in?: ID_Output[] | ID_Output | null + createdAt_eq?: DateTime | null + createdAt_lt?: DateTime | null + createdAt_lte?: DateTime | null + createdAt_gt?: DateTime | null + createdAt_gte?: DateTime | null + createdById_eq?: ID_Input | null + createdById_in?: ID_Output[] | ID_Output | null + updatedAt_eq?: DateTime | null + updatedAt_lt?: DateTime | null + updatedAt_lte?: DateTime | null + updatedAt_gt?: DateTime | null + updatedAt_gte?: DateTime | null + updatedById_eq?: ID_Input | null + updatedById_in?: ID_Output[] | ID_Output | null deletedAt_all?: Boolean | null - deletedAt_eq?: String | null - deletedAt_lt?: String | null - deletedAt_lte?: String | null - deletedAt_gt?: String | null - deletedAt_gte?: String | null - deletedById_eq?: String | null + deletedAt_eq?: DateTime | null + deletedAt_lt?: DateTime | null + deletedAt_lte?: DateTime | null + deletedAt_gt?: DateTime | null + deletedAt_gte?: DateTime | null + deletedById_eq?: ID_Input | null + deletedById_in?: ID_Output[] | ID_Output | null mbid_eq?: String | null mbid_contains?: String | null mbid_startsWith?: String | null @@ -231,8 +297,11 @@ export interface ItemWhereInput { rymId_lt?: Int | null rymId_lte?: Int | null rymId_in?: Int[] | Int | null - spotifyId_eq?: ID_Input | null - spotifyId_in?: ID_Output[] | ID_Output | null + spotifyId_eq?: String | null + spotifyId_contains?: String | null + spotifyId_startsWith?: String | null + spotifyId_endsWith?: String | null + spotifyId_in?: String[] | String | null title_eq?: String | null title_contains?: String | null title_startsWith?: String | null @@ -251,43 +320,112 @@ export interface ItemWhereInput { } export interface ItemWhereUniqueInput { - id: String + id: ID_Output +} + +export interface ReviewCreateInput { + collectionItemId: ID_Output + rating?: String | null + title?: String | null + reviewText?: String | null +} + +export interface ReviewUpdateInput { + collectionItemId?: ID_Input | null + rating?: String | null + title?: String | null + reviewText?: String | null +} + +export interface ReviewWhereInput { + id_eq?: ID_Input | null + id_in?: ID_Output[] | ID_Output | null + createdAt_eq?: DateTime | null + createdAt_lt?: DateTime | null + createdAt_lte?: DateTime | null + createdAt_gt?: DateTime | null + createdAt_gte?: DateTime | null + createdById_eq?: ID_Input | null + createdById_in?: ID_Output[] | ID_Output | null + updatedAt_eq?: DateTime | null + updatedAt_lt?: DateTime | null + updatedAt_lte?: DateTime | null + updatedAt_gt?: DateTime | null + updatedAt_gte?: DateTime | null + updatedById_eq?: ID_Input | null + updatedById_in?: ID_Output[] | ID_Output | null + deletedAt_all?: Boolean | null + deletedAt_eq?: DateTime | null + deletedAt_lt?: DateTime | null + deletedAt_lte?: DateTime | null + deletedAt_gt?: DateTime | null + deletedAt_gte?: DateTime | null + deletedById_eq?: ID_Input | null + deletedById_in?: ID_Output[] | ID_Output | null + collectionItemId_eq?: ID_Input | null + collectionItemId_in?: ID_Output[] | ID_Output | null + rating_eq?: String | null + rating_contains?: String | null + rating_startsWith?: String | null + rating_endsWith?: String | null + rating_in?: String[] | String | null + title_eq?: String | null + title_contains?: String | null + title_startsWith?: String | null + title_endsWith?: String | null + title_in?: String[] | String | null + reviewText_eq?: String | null + reviewText_contains?: String | null + reviewText_startsWith?: String | null + reviewText_endsWith?: String | null + reviewText_in?: String[] | String | null +} + +export interface ReviewWhereUniqueInput { + id: ID_Output } export interface UserCreateInput { username: String email?: String | null + password: String bio?: String | null + accountSettings?: JSONObject | null } export interface UserUpdateInput { username?: String | null email?: String | null + password?: String | null bio?: String | null + accountSettings?: JSONObject | null } export interface UserWhereInput { - id_eq?: String | null - id_in?: String[] | String | null - createdAt_eq?: String | null - createdAt_lt?: String | null - createdAt_lte?: String | null - createdAt_gt?: String | null - createdAt_gte?: String | null - createdById_eq?: String | null - updatedAt_eq?: String | null - updatedAt_lt?: String | null - updatedAt_lte?: String | null - updatedAt_gt?: String | null - updatedAt_gte?: String | null - updatedById_eq?: String | null + id_eq?: ID_Input | null + id_in?: ID_Output[] | ID_Output | null + createdAt_eq?: DateTime | null + createdAt_lt?: DateTime | null + createdAt_lte?: DateTime | null + createdAt_gt?: DateTime | null + createdAt_gte?: DateTime | null + createdById_eq?: ID_Input | null + createdById_in?: ID_Output[] | ID_Output | null + updatedAt_eq?: DateTime | null + updatedAt_lt?: DateTime | null + updatedAt_lte?: DateTime | null + updatedAt_gt?: DateTime | null + updatedAt_gte?: DateTime | null + updatedById_eq?: ID_Input | null + updatedById_in?: ID_Output[] | ID_Output | null deletedAt_all?: Boolean | null - deletedAt_eq?: String | null - deletedAt_lt?: String | null - deletedAt_lte?: String | null - deletedAt_gt?: String | null - deletedAt_gte?: String | null - deletedById_eq?: String | null + deletedAt_eq?: DateTime | null + deletedAt_lt?: DateTime | null + deletedAt_lte?: DateTime | null + deletedAt_gt?: DateTime | null + deletedAt_gte?: DateTime | null + deletedById_eq?: ID_Input | null + deletedById_in?: ID_Output[] | ID_Output | null username_eq?: String | null username_contains?: String | null username_startsWith?: String | null @@ -303,10 +441,12 @@ export interface UserWhereInput { bio_startsWith?: String | null bio_endsWith?: String | null bio_in?: String[] | String | null + accountSettings_json?: JSONObject | null } export interface UserWhereUniqueInput { - id: String + id?: ID_Input | null + email?: String | null } export interface BaseGraphQLObject { @@ -361,6 +501,11 @@ export interface CollectionItem extends BaseGraphQLObject { userId: String itemDetails?: Item | null itemDetailsId: String + plays?: Int | null + artist: String + title: String + mbid?: String | null + reviews?: Array | null } export interface Item extends BaseGraphQLObject { @@ -381,6 +526,30 @@ export interface Item extends BaseGraphQLObject { collectionItem?: Array | null } +export interface PageInfo { + limit: Float + offset: Float + totalCount: Float + hasNextPage: Boolean + hasPreviousPage: Boolean +} + +export interface Review extends BaseGraphQLObject { + id: ID_Output + createdAt: DateTime + createdById: String + updatedAt?: DateTime | null + updatedById?: String | null + deletedAt?: DateTime | null + deletedById?: String | null + version: Int + collectionItem?: CollectionItem | null + collectionItemId: String + rating?: String | null + title?: String | null + reviewText?: String | null +} + export interface StandardDeleteResponse { id: ID_Output } @@ -397,6 +566,7 @@ export interface User extends BaseGraphQLObject { username: String email?: String | null bio?: String | null + accountSettings?: JSONObject | null collection?: Array | null } @@ -426,6 +596,22 @@ The `Int` scalar type represents non-fractional signed whole numeric values. Int */ export type Int = number +/* +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +*/ + + export type JsonValue = JsonPrimitive | JsonObject | JsonArray; + + export type JsonPrimitive = string | number | boolean | null | {}; + + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface JsonArray extends Array {} + + export type JsonObject = { [member: string]: JsonValue }; + + export type JSONObject = JsonObject; + + /* The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text. */ diff --git a/generated/classes.ts b/generated/classes.ts index 81f61da..27d0b95 100644 --- a/generated/classes.ts +++ b/generated/classes.ts @@ -3,8 +3,8 @@ // new TypeGraphQL objects // @ts-ignore import { GraphQLDateTime as DateTime } from "graphql-iso-date"; +// @ts-ignore import { GraphQLID as ID } from "graphql"; - // @ts-ignore import { ArgsType, @@ -26,6 +26,8 @@ import { User } from "../src/modules/user/user.model"; // @ts-ignore import { Item } from "../src/modules/item/item.model"; // @ts-ignore +import { Review } from "../src/modules/review/review.model"; +// @ts-ignore import { CollectionItem } from "../src/modules/collection-item/collection-item.model"; export enum UserOrderByEnum { @@ -54,69 +56,78 @@ registerEnumType(UserOrderByEnum, { @TypeGraphQLInputType() export class UserWhereInput { - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) id_eq?: string; - @TypeGraphQLField(() => [String], { nullable: true }) + @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; @TypeGraphQLField({ nullable: true }) - createdAt_eq?: String; + createdAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lt?: String; + createdAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lte?: String; + createdAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gt?: String; + createdAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gte?: String; + createdAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) createdById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + createdById_in?: string[]; + @TypeGraphQLField({ nullable: true }) - updatedAt_eq?: String; + updatedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lt?: String; + updatedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lte?: String; + updatedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gt?: String; + updatedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gte?: String; + updatedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) updatedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + updatedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; @TypeGraphQLField({ nullable: true }) - deletedAt_eq?: String; + deletedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lt?: String; + deletedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lte?: String; + deletedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gt?: String; + deletedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gte?: String; + deletedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) deletedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + deletedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) username_eq?: string; @@ -161,12 +172,18 @@ export class UserWhereInput { @TypeGraphQLField(() => [String], { nullable: true }) bio_in?: string[]; + + @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true }) + accountSettings_json?: JsonObject; } @TypeGraphQLInputType() export class UserWhereUniqueInput { - @TypeGraphQLField(() => String) + @TypeGraphQLField(() => ID, { nullable: true }) id?: string; + + @TypeGraphQLField(() => String, { nullable: true }) + email?: string; } @TypeGraphQLInputType() @@ -177,8 +194,14 @@ export class UserCreateInput { @TypeGraphQLField({ nullable: true }) email?: string; + @TypeGraphQLField() + password!: string; + @TypeGraphQLField({ nullable: true }) bio?: string; + + @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true }) + accountSettings?: JsonObject; } @TypeGraphQLInputType() @@ -189,8 +212,14 @@ export class UserUpdateInput { @TypeGraphQLField({ nullable: true }) email?: string; + @TypeGraphQLField({ nullable: true }) + password?: string; + @TypeGraphQLField({ nullable: true }) bio?: string; + + @TypeGraphQLField(() => GraphQLJSONObject, { nullable: true }) + accountSettings?: JsonObject; } @ArgsType() @@ -249,69 +278,78 @@ registerEnumType(ItemOrderByEnum, { @TypeGraphQLInputType() export class ItemWhereInput { - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) id_eq?: string; - @TypeGraphQLField(() => [String], { nullable: true }) + @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; @TypeGraphQLField({ nullable: true }) - createdAt_eq?: String; + createdAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lt?: String; + createdAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lte?: String; + createdAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gt?: String; + createdAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gte?: String; + createdAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) createdById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + createdById_in?: string[]; + @TypeGraphQLField({ nullable: true }) - updatedAt_eq?: String; + updatedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lt?: String; + updatedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lte?: String; + updatedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gt?: String; + updatedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gte?: String; + updatedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) updatedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + updatedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; @TypeGraphQLField({ nullable: true }) - deletedAt_eq?: String; + deletedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lt?: String; + deletedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lte?: String; + deletedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gt?: String; + deletedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gte?: String; + deletedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) deletedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + deletedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) mbid_eq?: string; @@ -345,10 +383,19 @@ export class ItemWhereInput { @TypeGraphQLField(() => [Int], { nullable: true }) rymId_in?: number[]; - @TypeGraphQLField(() => ID, { nullable: true }) + @TypeGraphQLField({ nullable: true }) spotifyId_eq?: string; - @TypeGraphQLField(() => [ID], { nullable: true }) + @TypeGraphQLField({ nullable: true }) + spotifyId_contains?: string; + + @TypeGraphQLField({ nullable: true }) + spotifyId_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + spotifyId_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) spotifyId_in?: string[]; @TypeGraphQLField({ nullable: true }) @@ -399,7 +446,7 @@ export class ItemWhereInput { @TypeGraphQLInputType() export class ItemWhereUniqueInput { - @TypeGraphQLField(() => String) + @TypeGraphQLField(() => ID) id?: string; } @@ -411,7 +458,7 @@ export class ItemCreateInput { @TypeGraphQLField({ nullable: true }) rymId?: number; - @TypeGraphQLField(() => ID, { nullable: true }) + @TypeGraphQLField({ nullable: true }) spotifyId?: string; @TypeGraphQLField() @@ -432,7 +479,7 @@ export class ItemUpdateInput { @TypeGraphQLField({ nullable: true }) rymId?: number; - @TypeGraphQLField(() => ID, { nullable: true }) + @TypeGraphQLField({ nullable: true }) spotifyId?: string; @TypeGraphQLField({ nullable: true }) @@ -466,6 +513,216 @@ export class ItemUpdateArgs { @TypeGraphQLField() where!: ItemWhereUniqueInput; } +export enum ReviewOrderByEnum { + createdAt_ASC = "createdAt_ASC", + createdAt_DESC = "createdAt_DESC", + + updatedAt_ASC = "updatedAt_ASC", + updatedAt_DESC = "updatedAt_DESC", + + deletedAt_ASC = "deletedAt_ASC", + deletedAt_DESC = "deletedAt_DESC", + + collectionItemId_ASC = "collectionItemId_ASC", + collectionItemId_DESC = "collectionItemId_DESC", + + rating_ASC = "rating_ASC", + rating_DESC = "rating_DESC", + + title_ASC = "title_ASC", + title_DESC = "title_DESC", + + reviewText_ASC = "reviewText_ASC", + reviewText_DESC = "reviewText_DESC" +} + +registerEnumType(ReviewOrderByEnum, { + name: "ReviewOrderByInput" +}); + +@TypeGraphQLInputType() +export class ReviewWhereInput { + @TypeGraphQLField(() => ID, { nullable: true }) + id_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + id_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + createdAt_eq?: Date; + + @TypeGraphQLField({ nullable: true }) + createdAt_lt?: Date; + + @TypeGraphQLField({ nullable: true }) + createdAt_lte?: Date; + + @TypeGraphQLField({ nullable: true }) + createdAt_gt?: Date; + + @TypeGraphQLField({ nullable: true }) + createdAt_gte?: Date; + + @TypeGraphQLField(() => ID, { nullable: true }) + createdById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + createdById_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + updatedAt_eq?: Date; + + @TypeGraphQLField({ nullable: true }) + updatedAt_lt?: Date; + + @TypeGraphQLField({ nullable: true }) + updatedAt_lte?: Date; + + @TypeGraphQLField({ nullable: true }) + updatedAt_gt?: Date; + + @TypeGraphQLField({ nullable: true }) + updatedAt_gte?: Date; + + @TypeGraphQLField(() => ID, { nullable: true }) + updatedById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + updatedById_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + deletedAt_all?: Boolean; + + @TypeGraphQLField({ nullable: true }) + deletedAt_eq?: Date; + + @TypeGraphQLField({ nullable: true }) + deletedAt_lt?: Date; + + @TypeGraphQLField({ nullable: true }) + deletedAt_lte?: Date; + + @TypeGraphQLField({ nullable: true }) + deletedAt_gt?: Date; + + @TypeGraphQLField({ nullable: true }) + deletedAt_gte?: Date; + + @TypeGraphQLField(() => ID, { nullable: true }) + deletedById_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + deletedById_in?: string[]; + + @TypeGraphQLField(() => ID, { nullable: true }) + collectionItemId_eq?: string; + + @TypeGraphQLField(() => [ID], { nullable: true }) + collectionItemId_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + rating_eq?: string; + + @TypeGraphQLField({ nullable: true }) + rating_contains?: string; + + @TypeGraphQLField({ nullable: true }) + rating_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + rating_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + rating_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + title_eq?: string; + + @TypeGraphQLField({ nullable: true }) + title_contains?: string; + + @TypeGraphQLField({ nullable: true }) + title_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + title_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + title_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + reviewText_eq?: string; + + @TypeGraphQLField({ nullable: true }) + reviewText_contains?: string; + + @TypeGraphQLField({ nullable: true }) + reviewText_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + reviewText_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + reviewText_in?: string[]; +} + +@TypeGraphQLInputType() +export class ReviewWhereUniqueInput { + @TypeGraphQLField(() => ID) + id?: string; +} + +@TypeGraphQLInputType() +export class ReviewCreateInput { + @TypeGraphQLField(() => ID) + collectionItemId!: string; + + @TypeGraphQLField({ nullable: true }) + rating?: string; + + @TypeGraphQLField({ nullable: true }) + title?: string; + + @TypeGraphQLField({ nullable: true }) + reviewText?: string; +} + +@TypeGraphQLInputType() +export class ReviewUpdateInput { + @TypeGraphQLField(() => ID, { nullable: true }) + collectionItemId?: string; + + @TypeGraphQLField({ nullable: true }) + rating?: string; + + @TypeGraphQLField({ nullable: true }) + title?: string; + + @TypeGraphQLField({ nullable: true }) + reviewText?: string; +} + +@ArgsType() +export class ReviewWhereArgs extends PaginationArgs { + @TypeGraphQLField(() => ReviewWhereInput, { nullable: true }) + where?: ReviewWhereInput; + + @TypeGraphQLField(() => ReviewOrderByEnum, { nullable: true }) + orderBy?: ReviewOrderByEnum; +} + +@ArgsType() +export class ReviewCreateManyArgs { + @TypeGraphQLField(() => [ReviewCreateInput]) + data!: ReviewCreateInput[]; +} + +@ArgsType() +export class ReviewUpdateArgs { + @TypeGraphQLField() data!: ReviewUpdateInput; + @TypeGraphQLField() where!: ReviewWhereUniqueInput; +} + export enum CollectionItemOrderByEnum { createdAt_ASC = "createdAt_ASC", createdAt_DESC = "createdAt_DESC", @@ -486,7 +743,19 @@ export enum CollectionItemOrderByEnum { userId_DESC = "userId_DESC", itemDetailsId_ASC = "itemDetailsId_ASC", - itemDetailsId_DESC = "itemDetailsId_DESC" + itemDetailsId_DESC = "itemDetailsId_DESC", + + plays_ASC = "plays_ASC", + plays_DESC = "plays_DESC", + + artist_ASC = "artist_ASC", + artist_DESC = "artist_DESC", + + title_ASC = "title_ASC", + title_DESC = "title_DESC", + + mbid_ASC = "mbid_ASC", + mbid_DESC = "mbid_DESC" } registerEnumType(CollectionItemOrderByEnum, { @@ -495,69 +764,78 @@ registerEnumType(CollectionItemOrderByEnum, { @TypeGraphQLInputType() export class CollectionItemWhereInput { - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) id_eq?: string; - @TypeGraphQLField(() => [String], { nullable: true }) + @TypeGraphQLField(() => [ID], { nullable: true }) id_in?: string[]; @TypeGraphQLField({ nullable: true }) - createdAt_eq?: String; + createdAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lt?: String; + createdAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_lte?: String; + createdAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gt?: String; + createdAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - createdAt_gte?: String; + createdAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) createdById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + createdById_in?: string[]; + @TypeGraphQLField({ nullable: true }) - updatedAt_eq?: String; + updatedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lt?: String; + updatedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_lte?: String; + updatedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gt?: String; + updatedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - updatedAt_gte?: String; + updatedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) updatedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + updatedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) deletedAt_all?: Boolean; @TypeGraphQLField({ nullable: true }) - deletedAt_eq?: String; + deletedAt_eq?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lt?: String; + deletedAt_lt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_lte?: String; + deletedAt_lte?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gt?: String; + deletedAt_gt?: Date; @TypeGraphQLField({ nullable: true }) - deletedAt_gte?: String; + deletedAt_gte?: Date; - @TypeGraphQLField(() => String, { nullable: true }) + @TypeGraphQLField(() => ID, { nullable: true }) deletedById_eq?: string; + @TypeGraphQLField(() => [ID], { nullable: true }) + deletedById_in?: string[]; + @TypeGraphQLField({ nullable: true }) customTitle_eq?: string; @@ -599,11 +877,74 @@ export class CollectionItemWhereInput { @TypeGraphQLField(() => [ID], { nullable: true }) itemDetailsId_in?: string[]; + + @TypeGraphQLField(() => Int, { nullable: true }) + plays_eq?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + plays_gt?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + plays_gte?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + plays_lt?: number; + + @TypeGraphQLField(() => Int, { nullable: true }) + plays_lte?: number; + + @TypeGraphQLField(() => [Int], { nullable: true }) + plays_in?: number[]; + + @TypeGraphQLField({ nullable: true }) + artist_eq?: string; + + @TypeGraphQLField({ nullable: true }) + artist_contains?: string; + + @TypeGraphQLField({ nullable: true }) + artist_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + artist_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + artist_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + title_eq?: string; + + @TypeGraphQLField({ nullable: true }) + title_contains?: string; + + @TypeGraphQLField({ nullable: true }) + title_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + title_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + title_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + mbid_eq?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_contains?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + mbid_in?: string[]; } @TypeGraphQLInputType() export class CollectionItemWhereUniqueInput { - @TypeGraphQLField(() => String) + @TypeGraphQLField(() => ID) id?: string; } @@ -620,6 +961,18 @@ export class CollectionItemCreateInput { @TypeGraphQLField(() => ID) itemDetailsId!: string; + + @TypeGraphQLField({ nullable: true }) + plays?: number; + + @TypeGraphQLField() + artist!: string; + + @TypeGraphQLField() + title!: string; + + @TypeGraphQLField({ nullable: true }) + mbid?: string; } @TypeGraphQLInputType() @@ -635,6 +988,18 @@ export class CollectionItemUpdateInput { @TypeGraphQLField(() => ID, { nullable: true }) itemDetailsId?: string; + + @TypeGraphQLField({ nullable: true }) + plays?: number; + + @TypeGraphQLField({ nullable: true }) + artist?: string; + + @TypeGraphQLField({ nullable: true }) + title?: string; + + @TypeGraphQLField({ nullable: true }) + mbid?: string; } @ArgsType() diff --git a/generated/schema.graphql b/generated/schema.graphql index 835a46e..8220d31 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -70,6 +70,11 @@ type CollectionItem implements BaseGraphQLObject { userId: String! itemDetails: Item itemDetailsId: String! + plays: Int + artist: String! + title: String! + mbid: String + reviews: [Review!] } input CollectionItemCreateInput { @@ -77,6 +82,10 @@ input CollectionItemCreateInput { customArtist: String userId: ID! itemDetailsId: ID! + plays: Float + artist: String! + title: String! + mbid: String } enum CollectionItemOrderByInput { @@ -94,6 +103,14 @@ enum CollectionItemOrderByInput { userId_DESC itemDetailsId_ASC itemDetailsId_DESC + plays_ASC + plays_DESC + artist_ASC + artist_DESC + title_ASC + title_DESC + mbid_ASC + mbid_DESC } input CollectionItemUpdateInput { @@ -101,30 +118,37 @@ input CollectionItemUpdateInput { customArtist: String userId: ID itemDetailsId: ID + plays: Float + artist: String + title: String + mbid: String } input CollectionItemWhereInput { - id_eq: String - id_in: [String!] - createdAt_eq: String - createdAt_lt: String - createdAt_lte: String - createdAt_gt: String - createdAt_gte: String - createdById_eq: String - updatedAt_eq: String - updatedAt_lt: String - updatedAt_lte: String - updatedAt_gt: String - updatedAt_gte: String - updatedById_eq: String + id_eq: ID + id_in: [ID!] + createdAt_eq: DateTime + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + createdById_eq: ID + createdById_in: [ID!] + updatedAt_eq: DateTime + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + updatedById_eq: ID + updatedById_in: [ID!] deletedAt_all: Boolean - deletedAt_eq: String - deletedAt_lt: String - deletedAt_lte: String - deletedAt_gt: String - deletedAt_gte: String - deletedById_eq: String + deletedAt_eq: DateTime + deletedAt_lt: DateTime + deletedAt_lte: DateTime + deletedAt_gt: DateTime + deletedAt_gte: DateTime + deletedById_eq: ID + deletedById_in: [ID!] customTitle_eq: String customTitle_contains: String customTitle_startsWith: String @@ -139,10 +163,31 @@ input CollectionItemWhereInput { userId_in: [ID!] itemDetailsId_eq: ID itemDetailsId_in: [ID!] + plays_eq: Int + plays_gt: Int + plays_gte: Int + plays_lt: Int + plays_lte: Int + plays_in: [Int!] + artist_eq: String + artist_contains: String + artist_startsWith: String + artist_endsWith: String + artist_in: [String!] + title_eq: String + title_contains: String + title_startsWith: String + title_endsWith: String + title_in: [String!] + mbid_eq: String + mbid_contains: String + mbid_startsWith: String + mbid_endsWith: String + mbid_in: [String!] } input CollectionItemWhereUniqueInput { - id: String! + id: ID! } """ @@ -175,7 +220,7 @@ type Item implements BaseGraphQLObject { input ItemCreateInput { mbid: String rymId: Float - spotifyId: ID + spotifyId: String title: String! disambiguation: String artist: String! @@ -205,34 +250,37 @@ enum ItemOrderByInput { input ItemUpdateInput { mbid: String rymId: Float - spotifyId: ID + spotifyId: String title: String disambiguation: String artist: String } input ItemWhereInput { - id_eq: String - id_in: [String!] - createdAt_eq: String - createdAt_lt: String - createdAt_lte: String - createdAt_gt: String - createdAt_gte: String - createdById_eq: String - updatedAt_eq: String - updatedAt_lt: String - updatedAt_lte: String - updatedAt_gt: String - updatedAt_gte: String - updatedById_eq: String + id_eq: ID + id_in: [ID!] + createdAt_eq: DateTime + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + createdById_eq: ID + createdById_in: [ID!] + updatedAt_eq: DateTime + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + updatedById_eq: ID + updatedById_in: [ID!] deletedAt_all: Boolean - deletedAt_eq: String - deletedAt_lt: String - deletedAt_lte: String - deletedAt_gt: String - deletedAt_gte: String - deletedById_eq: String + deletedAt_eq: DateTime + deletedAt_lt: DateTime + deletedAt_lte: DateTime + deletedAt_gt: DateTime + deletedAt_gte: DateTime + deletedById_eq: ID + deletedById_in: [ID!] mbid_eq: String mbid_contains: String mbid_startsWith: String @@ -244,8 +292,11 @@ input ItemWhereInput { rymId_lt: Int rymId_lte: Int rymId_in: [Int!] - spotifyId_eq: ID - spotifyId_in: [ID!] + spotifyId_eq: String + spotifyId_contains: String + spotifyId_startsWith: String + spotifyId_endsWith: String + spotifyId_in: [String!] title_eq: String title_contains: String title_startsWith: String @@ -264,9 +315,14 @@ input ItemWhereInput { } input ItemWhereUniqueInput { - id: String! + id: ID! } +""" +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSONObject + type Mutation { createCollectionItem(data: CollectionItemCreateInput!): CollectionItem! createManyCollectionItems(data: [CollectionItemCreateInput!]!): [CollectionItem!]! @@ -276,21 +332,130 @@ type Mutation { createManyItems(data: [ItemCreateInput!]!): [Item!]! updateItem(data: ItemUpdateInput!, where: ItemWhereUniqueInput!): Item! deleteItem(where: ItemWhereUniqueInput!): StandardDeleteResponse! + createReview(data: ReviewCreateInput!): Review! + createManyReviews(data: [ReviewCreateInput!]!): [Review!]! + updateReview(data: ReviewUpdateInput!, where: ReviewWhereUniqueInput!): Review! + deleteReview(where: ReviewWhereUniqueInput!): StandardDeleteResponse! createUser(data: UserCreateInput!): User! createManyUsers(data: [UserCreateInput!]!): [User!]! updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User! deleteUser(where: UserWhereUniqueInput!): StandardDeleteResponse! } +type PageInfo { + limit: Float! + offset: Float! + totalCount: Float! + hasNextPage: Boolean! + hasPreviousPage: Boolean! +} + type Query { collectionItems(offset: Int, limit: Int = 50, where: CollectionItemWhereInput, orderBy: CollectionItemOrderByInput): [CollectionItem!]! collectionItem(where: CollectionItemWhereUniqueInput!): CollectionItem! items(offset: Int, limit: Int = 50, where: ItemWhereInput, orderBy: ItemOrderByInput): [Item!]! item(where: ItemWhereUniqueInput!): Item! + reviews(offset: Int, limit: Int = 50, where: ReviewWhereInput, orderBy: ReviewOrderByInput): [Review!]! + review(where: ReviewWhereUniqueInput!): Review! users(offset: Int, limit: Int = 50, where: UserWhereInput, orderBy: UserOrderByInput): [User!]! user(where: UserWhereUniqueInput!): User! } +type Review implements BaseGraphQLObject { + id: ID! + createdAt: DateTime! + createdById: String! + updatedAt: DateTime + updatedById: String + deletedAt: DateTime + deletedById: String + version: Int! + collectionItem: CollectionItem + collectionItemId: String! + rating: String + title: String + reviewText: String +} + +input ReviewCreateInput { + collectionItemId: ID! + rating: String + title: String + reviewText: String +} + +enum ReviewOrderByInput { + createdAt_ASC + createdAt_DESC + updatedAt_ASC + updatedAt_DESC + deletedAt_ASC + deletedAt_DESC + collectionItemId_ASC + collectionItemId_DESC + rating_ASC + rating_DESC + title_ASC + title_DESC + reviewText_ASC + reviewText_DESC +} + +input ReviewUpdateInput { + collectionItemId: ID + rating: String + title: String + reviewText: String +} + +input ReviewWhereInput { + id_eq: ID + id_in: [ID!] + createdAt_eq: DateTime + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + createdById_eq: ID + createdById_in: [ID!] + updatedAt_eq: DateTime + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + updatedById_eq: ID + updatedById_in: [ID!] + deletedAt_all: Boolean + deletedAt_eq: DateTime + deletedAt_lt: DateTime + deletedAt_lte: DateTime + deletedAt_gt: DateTime + deletedAt_gte: DateTime + deletedById_eq: ID + deletedById_in: [ID!] + collectionItemId_eq: ID + collectionItemId_in: [ID!] + rating_eq: String + rating_contains: String + rating_startsWith: String + rating_endsWith: String + rating_in: [String!] + title_eq: String + title_contains: String + title_startsWith: String + title_endsWith: String + title_in: [String!] + reviewText_eq: String + reviewText_contains: String + reviewText_startsWith: String + reviewText_endsWith: String + reviewText_in: [String!] +} + +input ReviewWhereUniqueInput { + id: ID! +} + type StandardDeleteResponse { id: ID! } @@ -307,13 +472,16 @@ type User implements BaseGraphQLObject { username: String! email: String bio: String + accountSettings: JSONObject collection: [CollectionItem!] } input UserCreateInput { username: String! email: String + password: String! bio: String + accountSettings: JSONObject } enum UserOrderByInput { @@ -334,31 +502,36 @@ enum UserOrderByInput { input UserUpdateInput { username: String email: String + password: String bio: String + accountSettings: JSONObject } input UserWhereInput { - id_eq: String - id_in: [String!] - createdAt_eq: String - createdAt_lt: String - createdAt_lte: String - createdAt_gt: String - createdAt_gte: String - createdById_eq: String - updatedAt_eq: String - updatedAt_lt: String - updatedAt_lte: String - updatedAt_gt: String - updatedAt_gte: String - updatedById_eq: String + id_eq: ID + id_in: [ID!] + createdAt_eq: DateTime + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + createdById_eq: ID + createdById_in: [ID!] + updatedAt_eq: DateTime + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime + updatedById_eq: ID + updatedById_in: [ID!] deletedAt_all: Boolean - deletedAt_eq: String - deletedAt_lt: String - deletedAt_lte: String - deletedAt_gt: String - deletedAt_gte: String - deletedById_eq: String + deletedAt_eq: DateTime + deletedAt_lt: DateTime + deletedAt_lte: DateTime + deletedAt_gt: DateTime + deletedAt_gte: DateTime + deletedById_eq: ID + deletedById_in: [ID!] username_eq: String username_contains: String username_startsWith: String @@ -374,8 +547,10 @@ input UserWhereInput { bio_startsWith: String bio_endsWith: String bio_in: [String!] + accountSettings_json: JSONObject } input UserWhereUniqueInput { - id: String! + id: ID + email: String } diff --git a/package.json b/package.json index df5c35d..a9160a3 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "patrician-api", - "version": "0.0.0", - "description": "Generated Warthog Project", + "version": "0.1.0-beta", + "description": "Patrician API", "license": "MIT", + "author": "Patrician Team", "scripts": { "bootstrap": "yarn bootstrap:dev", "bootstrap:dev": "yarn && yarn build:dev && yarn db:drop && yarn db:create && yarn db:migrate && yarn db:seed", @@ -101,5 +102,9 @@ }, "resolutions": { "ts-node": "7.0.1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/patricianapp/patrician-api.git" } } diff --git a/src/interfaces/account-settings.ts b/src/interfaces/account-settings.ts new file mode 100644 index 0000000..81a3300 --- /dev/null +++ b/src/interfaces/account-settings.ts @@ -0,0 +1,3 @@ +export interface AccountSettings { + itemsPerPage: number; +} \ No newline at end of file diff --git a/src/modules/collection-item/collection-item.model.ts b/src/modules/collection-item/collection-item.model.ts index f350574..61a65ba 100644 --- a/src/modules/collection-item/collection-item.model.ts +++ b/src/modules/collection-item/collection-item.model.ts @@ -1,6 +1,7 @@ -import { BaseModel, Model, StringField, ManyToOne } from 'warthog'; +import { BaseModel, Model, StringField, ManyToOne, OneToMany, IntField } from 'warthog'; import { User } from '../user/user.model'; import { Item } from '../item/item.model'; +import { Review } from '../review/review.model'; @Model() export class CollectionItem extends BaseModel { @@ -14,11 +15,46 @@ export class CollectionItem extends BaseModel { () => User, (user: User) => user.collection ) - user?: User; + user!: User; @ManyToOne( () => Item, (item: Item) => item.collectionItem ) - itemDetails?: Item; + itemDetails!: Item; + + @IntField({ nullable: true, default: 0 }) + plays?: number + + @StringField({ apiOnly: true }) + get artist(): string { + return this.itemDetails.artist; + } + + @StringField({ apiOnly: true }) + get title(): string { + return this.itemDetails.title; + } + + @StringField({ apiOnly: true, nullable: true }) + get mbid(): string | undefined { + return this.itemDetails.mbid; + } + + @OneToMany( + () => Review, + (review: Review) => review.collectionItem + ) + reviews?: Review[]; + + // FIXME: warthog codegen fails because of optional chaining + // @StringField({ apiOnly: true, nullable: true }) + // get rating(): string | undefined { + // return this.reviews?.pop()?.rating; // TODO: Do we need the second question mark? + // } + + // @StringField({ apiOnly: true, nullable: true }) + // get review(): string | undefined { + // return this.reviews?.pop()?.reviewText; + // } } diff --git a/src/modules/review/review.model.ts b/src/modules/review/review.model.ts new file mode 100644 index 0000000..deae3da --- /dev/null +++ b/src/modules/review/review.model.ts @@ -0,0 +1,20 @@ +import { BaseModel, Model, StringField, ManyToOne } from 'warthog'; +import { CollectionItem } from '../collection-item/collection-item.model'; + +@Model() +export class Review extends BaseModel { + @ManyToOne( + () => CollectionItem, + (collectionItem: CollectionItem) => collectionItem.reviews + ) + collectionItem!: CollectionItem; + + @StringField({ nullable: true }) + rating?: string; + + @StringField({ nullable: true }) + title?: string; + + @StringField({ nullable: true }) + reviewText?: string; +} diff --git a/src/modules/review/review.resolver.ts b/src/modules/review/review.resolver.ts new file mode 100644 index 0000000..28d8881 --- /dev/null +++ b/src/modules/review/review.resolver.ts @@ -0,0 +1,65 @@ +import { Arg, Args, Mutation, Query, Resolver } from 'type-graphql'; +import { Inject } from 'typedi'; +import { Fields, StandardDeleteResponse, UserId } from 'warthog'; + +import { + ReviewCreateInput, + ReviewCreateManyArgs, + ReviewUpdateArgs, + ReviewWhereArgs, + ReviewWhereInput, + ReviewWhereUniqueInput +} from '../../../generated'; + +import { Review } from './review.model'; +import { ReviewService } from './review.service'; + +@Resolver(Review) +export class ReviewResolver { + constructor(@Inject('ReviewService') public readonly service: ReviewService) {} + + @Query(() => [Review]) + async reviews( + @Args() { where, orderBy, limit, offset }: ReviewWhereArgs, + @Fields() fields: string[] + ): Promise { + return this.service.find(where, orderBy, limit, offset, fields); + } + + @Query(() => Review) + async review(@Arg('where') where: ReviewWhereUniqueInput): Promise { + return this.service.findOne(where); + } + + @Mutation(() => Review) + async createReview( + @Arg('data') data: ReviewCreateInput, + @UserId() userId: string + ): Promise { + return this.service.create(data, userId); + } + + @Mutation(() => [Review]) + async createManyReviews( + @Args() { data }: ReviewCreateManyArgs, + @UserId() userId: string + ): Promise { + return this.service.createMany(data, userId); + } + + @Mutation(() => Review) + async updateReview( + @Args() { data, where }: ReviewUpdateArgs, + @UserId() userId: string + ): Promise { + return this.service.update(data, where, userId); + } + + @Mutation(() => StandardDeleteResponse) + async deleteReview( + @Arg('where') where: ReviewWhereUniqueInput, + @UserId() userId: string + ): Promise { + return this.service.delete(where, userId); + } +} diff --git a/src/modules/review/review.service.ts b/src/modules/review/review.service.ts new file mode 100644 index 0000000..ce3e399 --- /dev/null +++ b/src/modules/review/review.service.ts @@ -0,0 +1,13 @@ +import { Service } from 'typedi'; +import { Repository } from 'typeorm'; +import { InjectRepository } from 'typeorm-typedi-extensions'; +import { BaseService } from 'warthog'; + +import { Review } from './review.model'; + +@Service('ReviewService') +export class ReviewService extends BaseService { + constructor(@InjectRepository(Review) protected readonly repository: Repository) { + super(Review, repository); + } +} diff --git a/src/modules/user/user.model.ts b/src/modules/user/user.model.ts index 0ea0d11..80dea3f 100644 --- a/src/modules/user/user.model.ts +++ b/src/modules/user/user.model.ts @@ -1,20 +1,30 @@ -import { BaseModel, Model, OneToMany, StringField } from 'warthog'; +import { BaseModel, Model, OneToMany, StringField, EmailField, JSONField } from 'warthog'; import { CollectionItem } from '../collection-item/collection-item.model'; +import { AccountSettings } from '../../interfaces/account-settings'; @Model() export class User extends BaseModel { @StringField() username!: string; - @StringField({ nullable: true }) + @EmailField({ nullable: true }) email?: string; + @StringField({ writeonly: true }) + password!: string; + + @StringField({ dbOnly: true }) + salt!: string; + @StringField({ nullable: true }) bio?: string; + @JSONField({ nullable: true }) + accountSettings?: AccountSettings; + @OneToMany( () => CollectionItem, (collectionItem: CollectionItem) => collectionItem.user ) - collection?: CollectionItem[]; + collection?: CollectionItem[]; // TODO: Initialize to empty array } From ec3e93f8ec8f49f3fc972df53c41d20648124f7f Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Thu, 16 Apr 2020 16:00:42 -0700 Subject: [PATCH 5/8] Recreated database again, added signUp() --- .../1584861008595-CreateUserTable.ts | 0 .../1587075769273-True.ts | 4 --- db/migrations/1587076386589-True.ts | 26 ++++++++++++++ package.json | 2 ++ src/modules/user/user.service.ts | 30 +++++++++++++++- yarn.lock | 36 ++++++++++++++++++- 6 files changed, 92 insertions(+), 6 deletions(-) rename db/{migrations => migrations-old}/1584861008595-CreateUserTable.ts (100%) rename db/{migrations => migrations-old}/1587075769273-True.ts (86%) create mode 100644 db/migrations/1587076386589-True.ts diff --git a/db/migrations/1584861008595-CreateUserTable.ts b/db/migrations-old/1584861008595-CreateUserTable.ts similarity index 100% rename from db/migrations/1584861008595-CreateUserTable.ts rename to db/migrations-old/1584861008595-CreateUserTable.ts diff --git a/db/migrations/1587075769273-True.ts b/db/migrations-old/1587075769273-True.ts similarity index 86% rename from db/migrations/1587075769273-True.ts rename to db/migrations-old/1587075769273-True.ts index 12c466c..4ad677a 100644 --- a/db/migrations/1587075769273-True.ts +++ b/db/migrations-old/1587075769273-True.ts @@ -5,8 +5,6 @@ export class True1587075769273 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(`CREATE TABLE "reviews" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "collection_item_id" character varying NOT NULL, "rating" character varying, "title" character varying, "review_text" character varying, CONSTRAINT "PK_231ae565c273ee700b283f15c1d" PRIMARY KEY ("id"))`, undefined); - await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "rating"`, undefined); - await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "review"`, undefined); await queryRunner.query(`ALTER TABLE "users" ADD "password" character varying NOT NULL`, undefined); await queryRunner.query(`ALTER TABLE "users" ADD "salt" character varying NOT NULL`, undefined); await queryRunner.query(`ALTER TABLE "users" ADD "account_settings" jsonb`, undefined); @@ -22,8 +20,6 @@ export class True1587075769273 implements MigrationInterface { await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "account_settings"`, undefined); await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "salt"`, undefined); await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "password"`, undefined); - await queryRunner.query(`ALTER TABLE "items" ADD "review" character varying`, undefined); - await queryRunner.query(`ALTER TABLE "items" ADD "rating" character varying`, undefined); await queryRunner.query(`DROP TABLE "reviews"`, undefined); } diff --git a/db/migrations/1587076386589-True.ts b/db/migrations/1587076386589-True.ts new file mode 100644 index 0000000..fa0eb4c --- /dev/null +++ b/db/migrations/1587076386589-True.ts @@ -0,0 +1,26 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class True1587076386589 implements MigrationInterface { + name = 'True1587076386589' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`CREATE TABLE "users" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "username" character varying NOT NULL, "email" character varying, "password" character varying NOT NULL, "salt" character varying NOT NULL, "bio" character varying, "account_settings" jsonb, CONSTRAINT "UQ_97672ac88f789774dd47f7c8be3" UNIQUE ("email"), CONSTRAINT "PK_a3ffb1c0c8416b9fc6f907b7433" PRIMARY KEY ("id"))`, undefined); + await queryRunner.query(`CREATE TABLE "items" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "mbid" character varying, "rym_id" integer, "spotify_id" character varying, "title" character varying NOT NULL, "disambiguation" character varying, "artist" character varying NOT NULL, CONSTRAINT "PK_ba5885359424c15ca6b9e79bcf6" PRIMARY KEY ("id"))`, undefined); + await queryRunner.query(`CREATE TABLE "reviews" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "collection_item_id" character varying NOT NULL, "rating" character varying, "title" character varying, "review_text" character varying, CONSTRAINT "PK_231ae565c273ee700b283f15c1d" PRIMARY KEY ("id"))`, undefined); + await queryRunner.query(`CREATE TABLE "collection_items" ("id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "created_by_id" character varying NOT NULL, "updated_at" TIMESTAMP DEFAULT now(), "updated_by_id" character varying, "deleted_at" TIMESTAMP, "deleted_by_id" character varying, "version" integer NOT NULL, "custom_title" character varying, "custom_artist" character varying, "user_id" character varying NOT NULL, "item_details_id" character varying NOT NULL, "plays" integer DEFAULT 0, CONSTRAINT "PK_5f299da96958a920ab58871ea57" PRIMARY KEY ("id"))`, undefined); + await queryRunner.query(`ALTER TABLE "reviews" ADD CONSTRAINT "FK_fc090d3e6b0a3b369f03d9aa673" FOREIGN KEY ("collection_item_id") REFERENCES "collection_items"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, undefined); + await queryRunner.query(`ALTER TABLE "collection_items" ADD CONSTRAINT "FK_11904cd0bab7d35969089548db8" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, undefined); + await queryRunner.query(`ALTER TABLE "collection_items" ADD CONSTRAINT "FK_08f049748e8a0c61e1c7b247028" FOREIGN KEY ("item_details_id") REFERENCES "items"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, undefined); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "collection_items" DROP CONSTRAINT "FK_08f049748e8a0c61e1c7b247028"`, undefined); + await queryRunner.query(`ALTER TABLE "collection_items" DROP CONSTRAINT "FK_11904cd0bab7d35969089548db8"`, undefined); + await queryRunner.query(`ALTER TABLE "reviews" DROP CONSTRAINT "FK_fc090d3e6b0a3b369f03d9aa673"`, undefined); + await queryRunner.query(`DROP TABLE "collection_items"`, undefined); + await queryRunner.query(`DROP TABLE "reviews"`, undefined); + await queryRunner.query(`DROP TABLE "items"`, undefined); + await queryRunner.query(`DROP TABLE "users"`, undefined); + } + +} diff --git a/package.json b/package.json index a9160a3..d35b12c 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,9 @@ ] }, "dependencies": { + "@types/bcrypt": "^3.0.0", "@types/sqlite3": "^3.1.5", + "bcrypt": "^4.0.1", "dotenv": "^8.0.0", "dotenvi": "^0.6.0", "reflect-metadata": "^0.1.13", diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index 6676c8a..be69645 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -2,12 +2,40 @@ import { Service } from 'typedi'; import { Repository } from 'typeorm'; import { InjectRepository } from 'typeorm-typedi-extensions'; import { BaseService } from 'warthog'; - +import * as bcrypt from 'bcrypt'; import { User } from './user.model'; +import { UserCreateInput } from '../../../generated'; +import { CollectionItem } from '../collection-item/collection-item.model'; @Service('UserService') export class UserService extends BaseService { constructor(@InjectRepository(User) protected readonly repository: Repository) { super(User, repository); } + + async create(user: UserCreateInput, userId: string) { + const salt = await bcrypt.genSalt(); + user.password = await bcrypt.hash(user.password, salt); + const collection: CollectionItem[] = []; + + const payload = { + ...user, + salt, + collection, + } + + return super.create(payload, userId); + } + + // TODO: Sign in + // async validateUserPassword(authCredentialsInput: UserCreateInput): Promise { + // const { username, password } = authCredentialsInput; + // const user = await this.findOne({username}); + + // if (user && user.password === bcrypt.hash(user.password, user.salt)) { + // return user.username; + // } else { + // return 'user not found'; + // } + // } } diff --git a/yarn.lock b/yarn.lock index 64e375e..cadfcef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -486,6 +486,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/bcrypt@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-3.0.0.tgz#851489a9065a067cb7f3c9cbe4ce9bed8bba0876" + integrity sha512-nohgNyv+1ViVcubKBh0+XiNJ3dO8nYu///9aJ4cgSqv70gBL+94SNy/iC2NLzKPT2Zt/QavrOkBVbZRLZmw6NQ== + "@types/bluebird@^3.5.20": version "3.5.30" resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5" @@ -1421,6 +1426,14 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bcrypt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-4.0.1.tgz#06e21e749a061020e4ff1283c1faa93187ac57fe" + integrity sha512-hSIZHkUxIDS5zA2o00Kf2O5RfVbQ888n54xQoF/eIaquU4uaLxK8vhhBdktd0B3n2MjkcAWzv4mnhogykBKOUQ== + dependencies: + node-addon-api "^2.0.0" + node-pre-gyp "0.14.0" + bindings@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" @@ -4283,6 +4296,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-addon-api@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b" + integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA== + node-emoji@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" @@ -4316,6 +4334,22 @@ node-notifier@^5.4.0, node-notifier@^5.4.2: shellwords "^0.1.1" which "^1.3.0" +node-pre-gyp@0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4.4.2" + node-pre-gyp@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" @@ -5826,7 +5860,7 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tar@^4: +tar@^4, tar@^4.4.2: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== From 0a3f8f866fb5abca739791d9a834dc3825edda3a Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Thu, 16 Apr 2020 21:07:11 -0700 Subject: [PATCH 6/8] Successfully flattened collection result --- .../1587079722249-TrueRenamedReviewBody.ts | 14 +++ generated/binding.ts | 53 +++-------- generated/classes.ts | 92 ++----------------- generated/schema.graphql | 51 +++------- .../collection-item/collection-item.model.ts | 24 +++-- .../collection-item.resolver.ts | 55 ++++++++++- .../collection-item.service.ts | 4 + src/modules/review/review.model.ts | 2 +- src/modules/user/user.model.ts | 2 +- 9 files changed, 124 insertions(+), 173 deletions(-) create mode 100644 db/migrations/1587079722249-TrueRenamedReviewBody.ts diff --git a/db/migrations/1587079722249-TrueRenamedReviewBody.ts b/db/migrations/1587079722249-TrueRenamedReviewBody.ts new file mode 100644 index 0000000..6593565 --- /dev/null +++ b/db/migrations/1587079722249-TrueRenamedReviewBody.ts @@ -0,0 +1,14 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class TrueRenamedReviewBody1587079722249 implements MigrationInterface { + name = 'TrueRenamedReviewBody1587079722249' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "reviews" RENAME COLUMN "review_text" TO "body"`, undefined); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "reviews" RENAME COLUMN "body" TO "review_text"`, undefined); + } + +} diff --git a/generated/binding.ts b/generated/binding.ts index 273ffa0..d97c86d 100644 --- a/generated/binding.ts +++ b/generated/binding.ts @@ -76,13 +76,7 @@ export type CollectionItemOrderByInput = 'createdAt_ASC' | 'itemDetailsId_ASC' | 'itemDetailsId_DESC' | 'plays_ASC' | - 'plays_DESC' | - 'artist_ASC' | - 'artist_DESC' | - 'title_ASC' | - 'title_DESC' | - 'mbid_ASC' | - 'mbid_DESC' + 'plays_DESC' export type ItemOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | @@ -115,8 +109,8 @@ export type ReviewOrderByInput = 'createdAt_ASC' | 'rating_DESC' | 'title_ASC' | 'title_DESC' | - 'reviewText_ASC' | - 'reviewText_DESC' + 'body_ASC' | + 'body_DESC' export type UserOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | @@ -161,9 +155,6 @@ export interface CollectionItemCreateInput { userId: ID_Output itemDetailsId: ID_Output plays?: Float | null - artist: String - title: String - mbid?: String | null } export interface CollectionItemUpdateInput { @@ -172,9 +163,6 @@ export interface CollectionItemUpdateInput { userId?: ID_Input | null itemDetailsId?: ID_Input | null plays?: Float | null - artist?: String | null - title?: String | null - mbid?: String | null } export interface CollectionItemWhereInput { @@ -222,21 +210,6 @@ export interface CollectionItemWhereInput { plays_lt?: Int | null plays_lte?: Int | null plays_in?: Int[] | Int | null - artist_eq?: String | null - artist_contains?: String | null - artist_startsWith?: String | null - artist_endsWith?: String | null - artist_in?: String[] | String | null - title_eq?: String | null - title_contains?: String | null - title_startsWith?: String | null - title_endsWith?: String | null - title_in?: String[] | String | null - mbid_eq?: String | null - mbid_contains?: String | null - mbid_startsWith?: String | null - mbid_endsWith?: String | null - mbid_in?: String[] | String | null } export interface CollectionItemWhereUniqueInput { @@ -327,14 +300,14 @@ export interface ReviewCreateInput { collectionItemId: ID_Output rating?: String | null title?: String | null - reviewText?: String | null + body?: String | null } export interface ReviewUpdateInput { collectionItemId?: ID_Input | null rating?: String | null title?: String | null - reviewText?: String | null + body?: String | null } export interface ReviewWhereInput { @@ -374,11 +347,11 @@ export interface ReviewWhereInput { title_startsWith?: String | null title_endsWith?: String | null title_in?: String[] | String | null - reviewText_eq?: String | null - reviewText_contains?: String | null - reviewText_startsWith?: String | null - reviewText_endsWith?: String | null - reviewText_in?: String[] | String | null + body_eq?: String | null + body_contains?: String | null + body_startsWith?: String | null + body_endsWith?: String | null + body_in?: String[] | String | null } export interface ReviewWhereUniqueInput { @@ -502,10 +475,10 @@ export interface CollectionItem extends BaseGraphQLObject { itemDetails?: Item | null itemDetailsId: String plays?: Int | null + reviews?: Array | null artist: String title: String - mbid?: String | null - reviews?: Array | null + mbid: String } export interface Item extends BaseGraphQLObject { @@ -547,7 +520,7 @@ export interface Review extends BaseGraphQLObject { collectionItemId: String rating?: String | null title?: String | null - reviewText?: String | null + body?: String | null } export interface StandardDeleteResponse { diff --git a/generated/classes.ts b/generated/classes.ts index 27d0b95..81ee53c 100644 --- a/generated/classes.ts +++ b/generated/classes.ts @@ -532,8 +532,8 @@ export enum ReviewOrderByEnum { title_ASC = "title_ASC", title_DESC = "title_DESC", - reviewText_ASC = "reviewText_ASC", - reviewText_DESC = "reviewText_DESC" + body_ASC = "body_ASC", + body_DESC = "body_DESC" } registerEnumType(ReviewOrderByEnum, { @@ -651,19 +651,19 @@ export class ReviewWhereInput { title_in?: string[]; @TypeGraphQLField({ nullable: true }) - reviewText_eq?: string; + body_eq?: string; @TypeGraphQLField({ nullable: true }) - reviewText_contains?: string; + body_contains?: string; @TypeGraphQLField({ nullable: true }) - reviewText_startsWith?: string; + body_startsWith?: string; @TypeGraphQLField({ nullable: true }) - reviewText_endsWith?: string; + body_endsWith?: string; @TypeGraphQLField(() => [String], { nullable: true }) - reviewText_in?: string[]; + body_in?: string[]; } @TypeGraphQLInputType() @@ -684,7 +684,7 @@ export class ReviewCreateInput { title?: string; @TypeGraphQLField({ nullable: true }) - reviewText?: string; + body?: string; } @TypeGraphQLInputType() @@ -699,7 +699,7 @@ export class ReviewUpdateInput { title?: string; @TypeGraphQLField({ nullable: true }) - reviewText?: string; + body?: string; } @ArgsType() @@ -746,16 +746,7 @@ export enum CollectionItemOrderByEnum { itemDetailsId_DESC = "itemDetailsId_DESC", plays_ASC = "plays_ASC", - plays_DESC = "plays_DESC", - - artist_ASC = "artist_ASC", - artist_DESC = "artist_DESC", - - title_ASC = "title_ASC", - title_DESC = "title_DESC", - - mbid_ASC = "mbid_ASC", - mbid_DESC = "mbid_DESC" + plays_DESC = "plays_DESC" } registerEnumType(CollectionItemOrderByEnum, { @@ -895,51 +886,6 @@ export class CollectionItemWhereInput { @TypeGraphQLField(() => [Int], { nullable: true }) plays_in?: number[]; - - @TypeGraphQLField({ nullable: true }) - artist_eq?: string; - - @TypeGraphQLField({ nullable: true }) - artist_contains?: string; - - @TypeGraphQLField({ nullable: true }) - artist_startsWith?: string; - - @TypeGraphQLField({ nullable: true }) - artist_endsWith?: string; - - @TypeGraphQLField(() => [String], { nullable: true }) - artist_in?: string[]; - - @TypeGraphQLField({ nullable: true }) - title_eq?: string; - - @TypeGraphQLField({ nullable: true }) - title_contains?: string; - - @TypeGraphQLField({ nullable: true }) - title_startsWith?: string; - - @TypeGraphQLField({ nullable: true }) - title_endsWith?: string; - - @TypeGraphQLField(() => [String], { nullable: true }) - title_in?: string[]; - - @TypeGraphQLField({ nullable: true }) - mbid_eq?: string; - - @TypeGraphQLField({ nullable: true }) - mbid_contains?: string; - - @TypeGraphQLField({ nullable: true }) - mbid_startsWith?: string; - - @TypeGraphQLField({ nullable: true }) - mbid_endsWith?: string; - - @TypeGraphQLField(() => [String], { nullable: true }) - mbid_in?: string[]; } @TypeGraphQLInputType() @@ -964,15 +910,6 @@ export class CollectionItemCreateInput { @TypeGraphQLField({ nullable: true }) plays?: number; - - @TypeGraphQLField() - artist!: string; - - @TypeGraphQLField() - title!: string; - - @TypeGraphQLField({ nullable: true }) - mbid?: string; } @TypeGraphQLInputType() @@ -991,15 +928,6 @@ export class CollectionItemUpdateInput { @TypeGraphQLField({ nullable: true }) plays?: number; - - @TypeGraphQLField({ nullable: true }) - artist?: string; - - @TypeGraphQLField({ nullable: true }) - title?: string; - - @TypeGraphQLField({ nullable: true }) - mbid?: string; } @ArgsType() diff --git a/generated/schema.graphql b/generated/schema.graphql index 8220d31..12abb8a 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -71,10 +71,10 @@ type CollectionItem implements BaseGraphQLObject { itemDetails: Item itemDetailsId: String! plays: Int + reviews: [Review!] artist: String! title: String! - mbid: String - reviews: [Review!] + mbid: String! } input CollectionItemCreateInput { @@ -83,9 +83,6 @@ input CollectionItemCreateInput { userId: ID! itemDetailsId: ID! plays: Float - artist: String! - title: String! - mbid: String } enum CollectionItemOrderByInput { @@ -105,12 +102,6 @@ enum CollectionItemOrderByInput { itemDetailsId_DESC plays_ASC plays_DESC - artist_ASC - artist_DESC - title_ASC - title_DESC - mbid_ASC - mbid_DESC } input CollectionItemUpdateInput { @@ -119,9 +110,6 @@ input CollectionItemUpdateInput { userId: ID itemDetailsId: ID plays: Float - artist: String - title: String - mbid: String } input CollectionItemWhereInput { @@ -169,21 +157,6 @@ input CollectionItemWhereInput { plays_lt: Int plays_lte: Int plays_in: [Int!] - artist_eq: String - artist_contains: String - artist_startsWith: String - artist_endsWith: String - artist_in: [String!] - title_eq: String - title_contains: String - title_startsWith: String - title_endsWith: String - title_in: [String!] - mbid_eq: String - mbid_contains: String - mbid_startsWith: String - mbid_endsWith: String - mbid_in: [String!] } input CollectionItemWhereUniqueInput { @@ -374,14 +347,14 @@ type Review implements BaseGraphQLObject { collectionItemId: String! rating: String title: String - reviewText: String + body: String } input ReviewCreateInput { collectionItemId: ID! rating: String title: String - reviewText: String + body: String } enum ReviewOrderByInput { @@ -397,15 +370,15 @@ enum ReviewOrderByInput { rating_DESC title_ASC title_DESC - reviewText_ASC - reviewText_DESC + body_ASC + body_DESC } input ReviewUpdateInput { collectionItemId: ID rating: String title: String - reviewText: String + body: String } input ReviewWhereInput { @@ -445,11 +418,11 @@ input ReviewWhereInput { title_startsWith: String title_endsWith: String title_in: [String!] - reviewText_eq: String - reviewText_contains: String - reviewText_startsWith: String - reviewText_endsWith: String - reviewText_in: [String!] + body_eq: String + body_contains: String + body_startsWith: String + body_endsWith: String + body_in: [String!] } input ReviewWhereUniqueInput { diff --git a/src/modules/collection-item/collection-item.model.ts b/src/modules/collection-item/collection-item.model.ts index 61a65ba..2899d16 100644 --- a/src/modules/collection-item/collection-item.model.ts +++ b/src/modules/collection-item/collection-item.model.ts @@ -26,15 +26,21 @@ export class CollectionItem extends BaseModel { @IntField({ nullable: true, default: 0 }) plays?: number - @StringField({ apiOnly: true }) - get artist(): string { - return this.itemDetails.artist; - } + // needs to be nullable for writes + // FIXME: This is calling the database even though apiOnly is true + // (Only occurs for mutation collectionItems, not collectionItem) + // TODO: The other problem seems to be that this.itemDetails doesn't exist by the time the resolver responds + // @StringField({ apiOnly: true, nullable: true }) + // get artist(): string { + // return this.itemDetails.artist; + // } - @StringField({ apiOnly: true }) - get title(): string { - return this.itemDetails.title; - } + // these fields are not required for the field resolvers to work + // however they may be required to make fields nullable + // @StringField({ apiOnly: true, nullable: true }) + // get title(): string { + // return this.itemDetails.title; + // } @StringField({ apiOnly: true, nullable: true }) get mbid(): string | undefined { @@ -47,7 +53,7 @@ export class CollectionItem extends BaseModel { ) reviews?: Review[]; - // FIXME: warthog codegen fails because of optional chaining + // FIXME: warthog codegen fails when using optional chaining // @StringField({ apiOnly: true, nullable: true }) // get rating(): string | undefined { // return this.reviews?.pop()?.rating; // TODO: Do we need the second question mark? diff --git a/src/modules/collection-item/collection-item.resolver.ts b/src/modules/collection-item/collection-item.resolver.ts index d5b67f0..dab3357 100644 --- a/src/modules/collection-item/collection-item.resolver.ts +++ b/src/modules/collection-item/collection-item.resolver.ts @@ -25,7 +25,8 @@ export class CollectionItemResolver { @Args() { where, orderBy, limit, offset }: CollectionItemWhereArgs, @Fields() fields: string[] ): Promise { - return this.service.find(where, orderBy, limit, offset, fields); + // TODO: Be able to use fields here without breaking artist/title fieldResolvers + return this.service.find(where, orderBy, limit, offset); } @Query(() => CollectionItem) @@ -35,11 +36,63 @@ export class CollectionItemResolver { return this.service.findOne(where); } + @FieldResolver(() => String) + async artist(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + let itemDetails = await ctx.dataLoader.loaders.CollectionItem.itemDetails.load(collectionItem); + return itemDetails.artist; + } + + @FieldResolver(() => String) + async title(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + let itemDetails = await ctx.dataLoader.loaders.CollectionItem.itemDetails.load(collectionItem); + return itemDetails.title; + } + + // TODO: "Cannot return null for non-nullable field CollectionItem.mbid." + // @FieldResolver(() => String) + // async mbid(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + // let itemDetails = await ctx.dataLoader.loaders.CollectionItem.itemDetails.load(collectionItem); + // if(itemDetails.mbid) { + // return itemDetails.mbid; + // } + // else { + // return ''; + // } + // } + + @FieldResolver(() => String) + async rating(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + let reviews = await ctx.dataLoader.loaders.CollectionItem.reviews.load(collectionItem); + if(reviews.length > 0) { + return reviews[reviews.length-1].rating; + } + else { + return ''; + } + } + + @FieldResolver(() => String) + async reviewBody(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + // TODO: Only loas the most recent review + let reviews = await ctx.dataLoader.loaders.CollectionItem.reviews.load(collectionItem); + if(reviews.length > 0) { + return reviews[reviews.length-1].body; + } + else { + return ''; + } + } + @FieldResolver(() => [Item]) itemDetails(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { return ctx.dataLoader.loaders.CollectionItem.itemDetails.load(collectionItem); } + @FieldResolver(() => [Item]) + reviews(@Root() collectionItem: CollectionItem, @Ctx() ctx: BaseContext): Promise { + return ctx.dataLoader.loaders.CollectionItem.reviews.load(collectionItem); + } + @Mutation(() => CollectionItem) async createCollectionItem( @Arg('data') data: CollectionItemCreateInput, diff --git a/src/modules/collection-item/collection-item.service.ts b/src/modules/collection-item/collection-item.service.ts index b189267..13fce8a 100644 --- a/src/modules/collection-item/collection-item.service.ts +++ b/src/modules/collection-item/collection-item.service.ts @@ -12,4 +12,8 @@ export class CollectionItemService extends BaseService { ) { super(CollectionItem, repository); } + + async getWithItemDetails() { + + } } diff --git a/src/modules/review/review.model.ts b/src/modules/review/review.model.ts index deae3da..77f1df2 100644 --- a/src/modules/review/review.model.ts +++ b/src/modules/review/review.model.ts @@ -16,5 +16,5 @@ export class Review extends BaseModel { title?: string; @StringField({ nullable: true }) - reviewText?: string; + body?: string; } diff --git a/src/modules/user/user.model.ts b/src/modules/user/user.model.ts index 80dea3f..0e7294c 100644 --- a/src/modules/user/user.model.ts +++ b/src/modules/user/user.model.ts @@ -26,5 +26,5 @@ export class User extends BaseModel { () => CollectionItem, (collectionItem: CollectionItem) => collectionItem.user ) - collection?: CollectionItem[]; // TODO: Initialize to empty array + collection?: CollectionItem[]; } From 41a2f412865dc672b865b11f95b5a4b4d5c55340 Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Thu, 16 Apr 2020 21:33:16 -0700 Subject: [PATCH 7/8] Added coverArt to item --- db/migrations/1587097918918-AddCoverArt.ts | 14 ++++++ generated/binding.ts | 27 +++++++++-- generated/classes.ts | 52 +++++++++++++++++++++- generated/schema.graphql | 23 +++++++++- src/modules/item/item.model.ts | 3 ++ 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 db/migrations/1587097918918-AddCoverArt.ts diff --git a/db/migrations/1587097918918-AddCoverArt.ts b/db/migrations/1587097918918-AddCoverArt.ts new file mode 100644 index 0000000..ded7eaa --- /dev/null +++ b/db/migrations/1587097918918-AddCoverArt.ts @@ -0,0 +1,14 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class AddCoverArt1587097918918 implements MigrationInterface { + name = 'AddCoverArt1587097918918' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "items" ADD "cover_art" character varying`, undefined); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "items" DROP COLUMN "cover_art"`, undefined); + } + +} diff --git a/generated/binding.ts b/generated/binding.ts index d97c86d..cd4fceb 100644 --- a/generated/binding.ts +++ b/generated/binding.ts @@ -76,7 +76,9 @@ export type CollectionItemOrderByInput = 'createdAt_ASC' | 'itemDetailsId_ASC' | 'itemDetailsId_DESC' | 'plays_ASC' | - 'plays_DESC' + 'plays_DESC' | + 'mbid_ASC' | + 'mbid_DESC' export type ItemOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | @@ -95,7 +97,9 @@ export type ItemOrderByInput = 'createdAt_ASC' | 'disambiguation_ASC' | 'disambiguation_DESC' | 'artist_ASC' | - 'artist_DESC' + 'artist_DESC' | + 'coverArt_ASC' | + 'coverArt_DESC' export type ReviewOrderByInput = 'createdAt_ASC' | 'createdAt_DESC' | @@ -155,6 +159,7 @@ export interface CollectionItemCreateInput { userId: ID_Output itemDetailsId: ID_Output plays?: Float | null + mbid?: String | null } export interface CollectionItemUpdateInput { @@ -163,6 +168,7 @@ export interface CollectionItemUpdateInput { userId?: ID_Input | null itemDetailsId?: ID_Input | null plays?: Float | null + mbid?: String | null } export interface CollectionItemWhereInput { @@ -210,6 +216,11 @@ export interface CollectionItemWhereInput { plays_lt?: Int | null plays_lte?: Int | null plays_in?: Int[] | Int | null + mbid_eq?: String | null + mbid_contains?: String | null + mbid_startsWith?: String | null + mbid_endsWith?: String | null + mbid_in?: String[] | String | null } export interface CollectionItemWhereUniqueInput { @@ -223,6 +234,7 @@ export interface ItemCreateInput { title: String disambiguation?: String | null artist: String + coverArt?: String | null } export interface ItemUpdateInput { @@ -232,6 +244,7 @@ export interface ItemUpdateInput { title?: String | null disambiguation?: String | null artist?: String | null + coverArt?: String | null } export interface ItemWhereInput { @@ -290,6 +303,11 @@ export interface ItemWhereInput { artist_startsWith?: String | null artist_endsWith?: String | null artist_in?: String[] | String | null + coverArt_eq?: String | null + coverArt_contains?: String | null + coverArt_startsWith?: String | null + coverArt_endsWith?: String | null + coverArt_in?: String[] | String | null } export interface ItemWhereUniqueInput { @@ -475,10 +493,12 @@ export interface CollectionItem extends BaseGraphQLObject { itemDetails?: Item | null itemDetailsId: String plays?: Int | null + mbid?: String | null reviews?: Array | null artist: String title: String - mbid: String + rating: String + reviewBody: String } export interface Item extends BaseGraphQLObject { @@ -496,6 +516,7 @@ export interface Item extends BaseGraphQLObject { title: String disambiguation?: String | null artist: String + coverArt?: String | null collectionItem?: Array | null } diff --git a/generated/classes.ts b/generated/classes.ts index 81ee53c..36ec78c 100644 --- a/generated/classes.ts +++ b/generated/classes.ts @@ -269,7 +269,10 @@ export enum ItemOrderByEnum { disambiguation_DESC = "disambiguation_DESC", artist_ASC = "artist_ASC", - artist_DESC = "artist_DESC" + artist_DESC = "artist_DESC", + + coverArt_ASC = "coverArt_ASC", + coverArt_DESC = "coverArt_DESC" } registerEnumType(ItemOrderByEnum, { @@ -442,6 +445,21 @@ export class ItemWhereInput { @TypeGraphQLField(() => [String], { nullable: true }) artist_in?: string[]; + + @TypeGraphQLField({ nullable: true }) + coverArt_eq?: string; + + @TypeGraphQLField({ nullable: true }) + coverArt_contains?: string; + + @TypeGraphQLField({ nullable: true }) + coverArt_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + coverArt_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + coverArt_in?: string[]; } @TypeGraphQLInputType() @@ -469,6 +487,9 @@ export class ItemCreateInput { @TypeGraphQLField() artist!: string; + + @TypeGraphQLField({ nullable: true }) + coverArt?: string; } @TypeGraphQLInputType() @@ -490,6 +511,9 @@ export class ItemUpdateInput { @TypeGraphQLField({ nullable: true }) artist?: string; + + @TypeGraphQLField({ nullable: true }) + coverArt?: string; } @ArgsType() @@ -746,7 +770,10 @@ export enum CollectionItemOrderByEnum { itemDetailsId_DESC = "itemDetailsId_DESC", plays_ASC = "plays_ASC", - plays_DESC = "plays_DESC" + plays_DESC = "plays_DESC", + + mbid_ASC = "mbid_ASC", + mbid_DESC = "mbid_DESC" } registerEnumType(CollectionItemOrderByEnum, { @@ -886,6 +913,21 @@ export class CollectionItemWhereInput { @TypeGraphQLField(() => [Int], { nullable: true }) plays_in?: number[]; + + @TypeGraphQLField({ nullable: true }) + mbid_eq?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_contains?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_startsWith?: string; + + @TypeGraphQLField({ nullable: true }) + mbid_endsWith?: string; + + @TypeGraphQLField(() => [String], { nullable: true }) + mbid_in?: string[]; } @TypeGraphQLInputType() @@ -910,6 +952,9 @@ export class CollectionItemCreateInput { @TypeGraphQLField({ nullable: true }) plays?: number; + + @TypeGraphQLField({ nullable: true }) + mbid?: string; } @TypeGraphQLInputType() @@ -928,6 +973,9 @@ export class CollectionItemUpdateInput { @TypeGraphQLField({ nullable: true }) plays?: number; + + @TypeGraphQLField({ nullable: true }) + mbid?: string; } @ArgsType() diff --git a/generated/schema.graphql b/generated/schema.graphql index 12abb8a..7831c61 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -71,10 +71,12 @@ type CollectionItem implements BaseGraphQLObject { itemDetails: Item itemDetailsId: String! plays: Int + mbid: String reviews: [Review!] artist: String! title: String! - mbid: String! + rating: String! + reviewBody: String! } input CollectionItemCreateInput { @@ -83,6 +85,7 @@ input CollectionItemCreateInput { userId: ID! itemDetailsId: ID! plays: Float + mbid: String } enum CollectionItemOrderByInput { @@ -102,6 +105,8 @@ enum CollectionItemOrderByInput { itemDetailsId_DESC plays_ASC plays_DESC + mbid_ASC + mbid_DESC } input CollectionItemUpdateInput { @@ -110,6 +115,7 @@ input CollectionItemUpdateInput { userId: ID itemDetailsId: ID plays: Float + mbid: String } input CollectionItemWhereInput { @@ -157,6 +163,11 @@ input CollectionItemWhereInput { plays_lt: Int plays_lte: Int plays_in: [Int!] + mbid_eq: String + mbid_contains: String + mbid_startsWith: String + mbid_endsWith: String + mbid_in: [String!] } input CollectionItemWhereUniqueInput { @@ -187,6 +198,7 @@ type Item implements BaseGraphQLObject { title: String! disambiguation: String artist: String! + coverArt: String collectionItem: [CollectionItem!] } @@ -197,6 +209,7 @@ input ItemCreateInput { title: String! disambiguation: String artist: String! + coverArt: String } enum ItemOrderByInput { @@ -218,6 +231,8 @@ enum ItemOrderByInput { disambiguation_DESC artist_ASC artist_DESC + coverArt_ASC + coverArt_DESC } input ItemUpdateInput { @@ -227,6 +242,7 @@ input ItemUpdateInput { title: String disambiguation: String artist: String + coverArt: String } input ItemWhereInput { @@ -285,6 +301,11 @@ input ItemWhereInput { artist_startsWith: String artist_endsWith: String artist_in: [String!] + coverArt_eq: String + coverArt_contains: String + coverArt_startsWith: String + coverArt_endsWith: String + coverArt_in: [String!] } input ItemWhereUniqueInput { diff --git a/src/modules/item/item.model.ts b/src/modules/item/item.model.ts index 6c90d6b..afc2da7 100644 --- a/src/modules/item/item.model.ts +++ b/src/modules/item/item.model.ts @@ -21,6 +21,9 @@ export class Item extends BaseModel { @StringField() artist!: string; + @StringField({ nullable: true }) + coverArt?: string; + @OneToMany( () => CollectionItem, (collectionItem: CollectionItem) => collectionItem.itemDetails From 607fd2be38e5ef0556772eab4e212e584c57ec70 Mon Sep 17 00:00:00 2001 From: Elias Jackson Date: Thu, 16 Apr 2020 22:06:28 -0700 Subject: [PATCH 8/8] 0.1.0 out of beta now that client works with it --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d35b12c..1ed8207 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "patrician-api", - "version": "0.1.0-beta", + "version": "0.1.0", "description": "Patrician API", "license": "MIT", "author": "Patrician Team",