| { | { | ||||
| "collection": "@nestjs/schematics", | "collection": "@nestjs/schematics", | ||||
| "sourceRoot": "src" | |||||
| "sourceRoot": "src", | |||||
| "compilerOptions": { | |||||
| "plugins": ["@nestjs/graphql/plugin"] | |||||
| } | |||||
| } | } |
| "dependencies": { | "dependencies": { | ||||
| "@nestjs/common": "^7.0.0", | "@nestjs/common": "^7.0.0", | ||||
| "@nestjs/core": "^7.0.0", | "@nestjs/core": "^7.0.0", | ||||
| "@nestjs/graphql": "^7.7.0", | |||||
| "@nestjs/mongoose": "^7.0.2", | "@nestjs/mongoose": "^7.0.2", | ||||
| "@nestjs/platform-express": "^7.0.0", | "@nestjs/platform-express": "^7.0.0", | ||||
| "@types/podcast": "^1.3.0", | "@types/podcast": "^1.3.0", | ||||
| "apollo-server-express": "^2.18.2", | |||||
| "graphql": "^15.3.0", | |||||
| "graphql-tools": "^6.2.4", | |||||
| "mongoose": "^5.10.9", | "mongoose": "^5.10.9", | ||||
| "podcast": "^1.3.0", | "podcast": "^1.3.0", | ||||
| "reflect-metadata": "^0.1.13", | "reflect-metadata": "^0.1.13", | ||||
| "rimraf": "^3.0.2", | "rimraf": "^3.0.2", | ||||
| "rxjs": "^6.5.4" | |||||
| "rxjs": "^6.5.4", | |||||
| "uuid": "^8.3.0" | |||||
| }, | }, | ||||
| "devDependencies": { | "devDependencies": { | ||||
| "@nestjs/cli": "^7.0.0", | "@nestjs/cli": "^7.0.0", | ||||
| "@types/mongoose": "^5.7.36", | "@types/mongoose": "^5.7.36", | ||||
| "@types/node": "^13.9.1", | "@types/node": "^13.9.1", | ||||
| "@types/supertest": "^2.0.8", | "@types/supertest": "^2.0.8", | ||||
| "@types/uuid": "^8.3.0", | |||||
| "@typescript-eslint/eslint-plugin": "3.9.1", | "@typescript-eslint/eslint-plugin": "3.9.1", | ||||
| "@typescript-eslint/parser": "3.9.1", | "@typescript-eslint/parser": "3.9.1", | ||||
| "eslint": "7.7.0", | "eslint": "7.7.0", |
| import { Episode } from "schemas/entity/episode.entity"; | |||||
| export class CreateEpisodeDto extends Episode { | |||||
| } |
| import { Field, InputType } from '@nestjs/graphql'; | |||||
| import { ItunesEpisodeTypeEnum } from 'schemas/enum/itunes-episode-type.enum'; | |||||
| import { EpisodeEnclosureCreateDto } from './episode-enclosure-create.dto'; | |||||
| @InputType() | |||||
| export class EpisodeCreateDto { | |||||
| @Field({ nullable: true }) | |||||
| title?: string; | |||||
| @Field({ nullable: true }) | |||||
| description?: string; | |||||
| @Field() | |||||
| url: string; | |||||
| @Field({ nullable: true }) | |||||
| guid?: string; | |||||
| @Field(type => [String], { nullable: true }) | |||||
| categories?: string[]; | |||||
| @Field({ nullable: true }) | |||||
| author?: string; | |||||
| @Field() | |||||
| date: Date; | |||||
| @Field({ nullable: true }) | |||||
| lat?: number; | |||||
| @Field({ nullable: true }) | |||||
| long?: number; | |||||
| @Field(type => EpisodeEnclosureCreateDto, { nullable: true }) | |||||
| enclosure?: EpisodeEnclosureCreateDto; | |||||
| @Field({ nullable: true }) | |||||
| content?: string; | |||||
| @Field({ nullable: true }) | |||||
| itunesAuthor?: string; | |||||
| @Field({ nullable: true }) | |||||
| itunesExplicit?: boolean; | |||||
| @Field({ nullable: true }) | |||||
| itunesSubtitle?: string; | |||||
| @Field({ nullable: true }) | |||||
| itunesSummary?: string; | |||||
| @Field({ nullable: true }) | |||||
| itunesDuration?: number; | |||||
| @Field({ nullable: true }) | |||||
| itunesImage?: string; | |||||
| @Field({ nullable: true }) | |||||
| itunesSeason?: number; | |||||
| @Field({ nullable: true }) | |||||
| itunesEpisode?: number; | |||||
| @Field({ nullable: true }) | |||||
| itunesTitle?: string; | |||||
| @Field(type => ItunesEpisodeTypeEnum, { nullable: true }) | |||||
| itunesEpisodeType?: ItunesEpisodeTypeEnum; | |||||
| } |
| import { Field, InputType } from '@nestjs/graphql'; | |||||
| @InputType() | |||||
| export class EpisodeEnclosureCreateDto { | |||||
| @Field() | |||||
| url: string; | |||||
| @Field({nullable: true}) | |||||
| file?: string; | |||||
| @Field({nullable: true}) | |||||
| size?: number; | |||||
| @Field({nullable: true}) | |||||
| type?: string; | |||||
| } |
| import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||
| import Podcast from 'podcast'; | import Podcast from 'podcast'; | ||||
| import { Document } from 'mongoose'; | import { Document } from 'mongoose'; | ||||
| import { Field, ID, InputType, ObjectType } from '@nestjs/graphql'; | |||||
| export type EpisodeEnclosureDocument = EpisodeEnclosure & Document; | export type EpisodeEnclosureDocument = EpisodeEnclosure & Document; | ||||
| @Schema() | @Schema() | ||||
| @ObjectType() | |||||
| export class EpisodeEnclosure implements Podcast.ItemEnclosure { | export class EpisodeEnclosure implements Podcast.ItemEnclosure { | ||||
| @Prop() | @Prop() | ||||
| @Field(type => ID) | |||||
| id: string; | |||||
| @Prop() | |||||
| @Field() | |||||
| url: string; | url: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| file?: string; | file?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| size?: number; | size?: number; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| type?: string; | type?: string; | ||||
| } | } | ||||
| import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||
| import Podcast from 'podcast'; | import Podcast from 'podcast'; | ||||
| import { ItunesEpisodeTypeEnum } from 'schemas/enum/itunes-episode-type.enum'; | import { ItunesEpisodeTypeEnum } from 'schemas/enum/itunes-episode-type.enum'; | ||||
| import { EpisodeEnclosure } from './episode-enclosure'; | |||||
| import { EpisodeEnclosure } from './episode-enclosure.entity'; | |||||
| import { Document } from 'mongoose'; | import { Document } from 'mongoose'; | ||||
| import { Field, ID, ObjectType } from '@nestjs/graphql'; | |||||
| export type EpisodeDocument = Episode & Document; | export type EpisodeDocument = Episode & Document; | ||||
| @Schema() | @Schema() | ||||
| @ObjectType() | |||||
| export class Episode implements Podcast.Item { | export class Episode implements Podcast.Item { | ||||
| @Prop() | @Prop() | ||||
| @Field(type => ID) | |||||
| id: string; | |||||
| @Prop() | |||||
| @Field({ nullable: true }) | |||||
| title?: string; | title?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| description?: string; | description?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field() | |||||
| url: string; | url: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| guid?: string; | guid?: string; | ||||
| @Prop([String]) | @Prop([String]) | ||||
| @Field(type => [String], {nullable: true}) | |||||
| categories?: string[]; | categories?: string[]; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| author?: string; | author?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field() | |||||
| date: Date; | date: Date; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| lat?: number; | lat?: number; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| long?: number; | long?: number; | ||||
| @Prop(EpisodeEnclosure) | @Prop(EpisodeEnclosure) | ||||
| @Field(type => EpisodeEnclosure, {nullable: true}) | |||||
| enclosure?: EpisodeEnclosure; | enclosure?: EpisodeEnclosure; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| content?: string; | content?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesAuthor?: string; | itunesAuthor?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesExplicit?: boolean; | itunesExplicit?: boolean; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesSubtitle?: string; | itunesSubtitle?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesSummary?: string; | itunesSummary?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesDuration?: number; | itunesDuration?: number; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesImage?: string; | itunesImage?: string; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesSeason?: number; | itunesSeason?: number; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesEpisode?: number; | itunesEpisode?: number; | ||||
| @Prop() | @Prop() | ||||
| @Field({ nullable: true }) | |||||
| itunesTitle?: string; | itunesTitle?: string; | ||||
| @Prop(ItunesEpisodeTypeEnum) | @Prop(ItunesEpisodeTypeEnum) | ||||
| @Field(type => ItunesEpisodeTypeEnum, {nullable: true}) | |||||
| itunesEpisodeType?: ItunesEpisodeTypeEnum; | itunesEpisodeType?: ItunesEpisodeTypeEnum; | ||||
| } | } | ||||
| import { registerEnumType } from '@nestjs/graphql'; | |||||
| export enum ItunesEpisodeTypeEnum { | export enum ItunesEpisodeTypeEnum { | ||||
| FULL = "full", | |||||
| TRAILER = "trailer", | |||||
| BONUS = "bonus", | |||||
| } | |||||
| FULL = 'full', | |||||
| TRAILER = 'trailer', | |||||
| BONUS = 'bonus', | |||||
| } | |||||
| registerEnumType(ItunesEpisodeTypeEnum, { | |||||
| name: 'ItunesEpisodeTypeEnum', | |||||
| }); |
| import { Episode, EpisodeSchema } from 'schemas/entity/episode.entity'; | import { Episode, EpisodeSchema } from 'schemas/entity/episode.entity'; | ||||
| import { AppService } from './app.service'; | import { AppService } from './app.service'; | ||||
| import { EpisodeService } from './episode/episode.service'; | import { EpisodeService } from './episode/episode.service'; | ||||
| import { GraphQLModule } from '@nestjs/graphql'; | |||||
| import { join } from 'path'; | |||||
| import { EpisodeResolver } from './episode/episode.resolver'; | |||||
| @Module({ | @Module({ | ||||
| imports: [ | imports: [ | ||||
| MongooseModule.forFeature([{ name: Episode.name, schema: EpisodeSchema }]), | MongooseModule.forFeature([{ name: Episode.name, schema: EpisodeSchema }]), | ||||
| MongooseModule.forRoot('mongodb://localhost:27017/test') | |||||
| MongooseModule.forRoot('mongodb://localhost:27017/test'), | |||||
| GraphQLModule.forRoot({ | |||||
| debug: false, | |||||
| playground: true, | |||||
| autoSchemaFile: join(process.cwd(), 'src/schema.gql'), | |||||
| installSubscriptionHandlers: true, | |||||
| }), | |||||
| ], | ], | ||||
| providers: [AppService, EpisodeService], | |||||
| providers: [AppService, EpisodeService, EpisodeResolver], | |||||
| }) | }) | ||||
| export class AppModule {} | export class AppModule {} |
| import { Test, TestingModule } from '@nestjs/testing'; | |||||
| import { EpisodeResolver } from './episode.resolver'; | |||||
| describe('EpisodeResolver', () => { | |||||
| let resolver: EpisodeResolver; | |||||
| beforeEach(async () => { | |||||
| const module: TestingModule = await Test.createTestingModule({ | |||||
| providers: [EpisodeResolver], | |||||
| }).compile(); | |||||
| resolver = module.get<EpisodeResolver>(EpisodeResolver); | |||||
| }); | |||||
| it('should be defined', () => { | |||||
| expect(resolver).toBeDefined(); | |||||
| }); | |||||
| }); |
| import { Resolver, Query, Args, Mutation } from '@nestjs/graphql'; | |||||
| import { EpisodeCreateDto } from 'schemas/dto/episode-create.dto'; | |||||
| import { Episode } from 'schemas/entity/episode.entity'; | |||||
| import { EpisodeService } from './episode.service'; | |||||
| @Resolver() | |||||
| export class EpisodeResolver { | |||||
| constructor(protected episodeService: EpisodeService) {} | |||||
| @Query(returns => [Episode]) | |||||
| async listEpisodes(): Promise<Episode[]> { | |||||
| return this.episodeService.findAll(); | |||||
| } | |||||
| @Mutation(returns => Episode) | |||||
| async createEpisode( | |||||
| @Args('episodeCreateDto') episodeCreateDto: EpisodeCreateDto, | |||||
| ) { | |||||
| const episode = await this.episodeService.create(episodeCreateDto); | |||||
| return episode; | |||||
| } | |||||
| } |
| import { Injectable } from '@nestjs/common'; | import { Injectable } from '@nestjs/common'; | ||||
| import { InjectModel } from '@nestjs/mongoose'; | import { InjectModel } from '@nestjs/mongoose'; | ||||
| import { Model } from 'mongoose'; | import { Model } from 'mongoose'; | ||||
| import { CreateEpisodeDto } from 'schemas/dto/create-episode.dto'; | |||||
| import { EpisodeCreateDto } from 'schemas/dto/episode-create.dto'; | |||||
| import { Episode, EpisodeDocument } from 'schemas/entity/episode.entity'; | import { Episode, EpisodeDocument } from 'schemas/entity/episode.entity'; | ||||
| import { v4 as uuid } from 'uuid'; | |||||
| @Injectable() | @Injectable() | ||||
| export class EpisodeService { | export class EpisodeService { | ||||
| constructor( | constructor( | ||||
| @InjectModel(Episode.name) private episodeModel: Model<EpisodeDocument>, | @InjectModel(Episode.name) private episodeModel: Model<EpisodeDocument>, | ||||
| ) {} | ) {} | ||||
| async create(createEpisodeDto: CreateEpisodeDto): Promise<Episode> { | |||||
| const createdEpisode = new this.episodeModel(createEpisodeDto); | |||||
| async create(episodeCreateDto: EpisodeCreateDto): Promise<Episode> { | |||||
| const createdEpisode = new this.episodeModel(episodeCreateDto); | |||||
| createdEpisode.id = uuid(); | |||||
| return createdEpisode.save(); | return createdEpisode.save(); | ||||
| } | } | ||||
| async findAll(): Promise<Episode[]> { | async findAll(): Promise<Episode[]> { | ||||
| return this.episodeModel.find().exec(); | return this.episodeModel.find().exec(); | ||||
| } | } | ||||
| async findOneById(): Promise<Episode[]> { | |||||
| return this.episodeModel.find().exec(); | |||||
| } | |||||
| } | } |
| # ------------------------------------------------------ | |||||
| # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) | |||||
| # ------------------------------------------------------ | |||||
| type EpisodeEnclosure { | |||||
| id: ID! | |||||
| url: String! | |||||
| file: String | |||||
| size: Float | |||||
| type: String | |||||
| } | |||||
| type Episode { | |||||
| id: ID! | |||||
| title: String | |||||
| description: String | |||||
| url: String! | |||||
| guid: String | |||||
| categories: [String!] | |||||
| author: String | |||||
| date: DateTime! | |||||
| lat: Float | |||||
| long: Float | |||||
| enclosure: EpisodeEnclosure | |||||
| content: String | |||||
| itunesAuthor: String | |||||
| itunesExplicit: Boolean | |||||
| itunesSubtitle: String | |||||
| itunesSummary: String | |||||
| itunesDuration: Float | |||||
| itunesImage: String | |||||
| itunesSeason: Float | |||||
| itunesEpisode: Float | |||||
| itunesTitle: String | |||||
| itunesEpisodeType: ItunesEpisodeTypeEnum | |||||
| } | |||||
| """ | |||||
| A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date-time format. | |||||
| """ | |||||
| scalar DateTime | |||||
| enum ItunesEpisodeTypeEnum { | |||||
| FULL | |||||
| TRAILER | |||||
| BONUS | |||||
| type | |||||
| } | |||||
| type Query { | |||||
| listEpisodes: [Episode!]! | |||||
| } | |||||
| type Mutation { | |||||
| createEpisode(episodeCreateDto: EpisodeCreateDto!): Episode! | |||||
| } | |||||
| input EpisodeCreateDto { | |||||
| title: String | |||||
| description: String | |||||
| url: String! | |||||
| guid: String | |||||
| categories: [String!] | |||||
| author: String | |||||
| date: DateTime! | |||||
| lat: Float | |||||
| long: Float | |||||
| enclosure: EpisodeEnclosureCreateDto | |||||
| content: String | |||||
| itunesAuthor: String | |||||
| itunesExplicit: Boolean | |||||
| itunesSubtitle: String | |||||
| itunesSummary: String | |||||
| itunesDuration: Float | |||||
| itunesImage: String | |||||
| itunesSeason: Float | |||||
| itunesEpisode: Float | |||||
| itunesTitle: String | |||||
| itunesEpisodeType: ItunesEpisodeTypeEnum | |||||
| } | |||||
| input EpisodeEnclosureCreateDto { | |||||
| url: String! | |||||
| file: String | |||||
| size: Float | |||||
| type: String | |||||
| } |