Created
January 2, 2020 12:33
-
-
Save panki/cd36eff3cfa55c641d0d0a51e0408082 to your computer and use it in GitHub Desktop.
Graph service example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Avatar } from '../schema/avatars.schema'; | |
import { Place } from '../schema/places.schema'; | |
import { Protest } from '../schema/protests.schema'; | |
import { User, UserAvatar } from '../schema/users.schema'; | |
export class GraphMap { | |
public avatarsMap: Map<number, Avatar>; | |
public avatars: Avatar[]; | |
public placesMap: Map<number, Place>; | |
public places: Place[]; | |
public protestsMap: Map<string, Protest>; | |
public protests: Protest[]; | |
public usersMap: Map<string, User>; | |
public users: User[]; | |
public userAvatarsMap: Map<string, UserAvatar>; | |
public userAvatars: UserAvatar[]; | |
constructor() { | |
this.avatarsMap = new Map<number, Avatar>(); | |
this.avatars = new Array<Avatar>(); | |
this.placesMap = new Map<number, Place>(); | |
this.places = new Array<Place>(); | |
this.protestsMap = new Map<string, Protest>(); | |
this.protests = new Array<Protest>(); | |
this.usersMap = new Map<string, User>(); | |
this.users = new Array<User>(); | |
this.userAvatarsMap = new Map<string, UserAvatar>(); | |
this.userAvatars = new Array<UserAvatar>(); | |
} | |
addAvatar(a: Avatar) { | |
this.avatarsMap.set(a.id, a); | |
this.avatars.push(a); | |
} | |
addProtest(p: Protest) { | |
this.protestsMap.set(p.id, p); | |
this.protests.push(p); | |
} | |
addUser(u: User) { | |
this.usersMap.set(u.id, u); | |
this.users.push(u); | |
} | |
addUserAvatar(a: UserAvatar) { | |
this.userAvatarsMap.set(a.id, a); | |
this.userAvatars.push(a); | |
} | |
addPlace(p: Place) { | |
this.placesMap.set(p.id, p); | |
this.places.push(p); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Module } from '@nestjs/common'; | |
import { AvatarsModule } from '../avatars/avatars.module'; | |
import { PlacesModule } from '../places/places.module'; | |
import { ProtestsModule } from '../protests/protests.module'; | |
import { UsersModule } from '../users/users.module'; | |
import { GraphService } from './graph.service'; | |
@Module({ | |
imports: [AvatarsModule, PlacesModule, ProtestsModule, UsersModule], | |
providers: [GraphService], | |
exports: [GraphService], | |
}) | |
export class GraphModule {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@nestjs/common'; | |
import { AvatarsService } from '../avatars/avatars.service'; | |
import { PlacesService } from '../places/places.service'; | |
import { ProtestsService } from '../protests/protests.service'; | |
import { Avatar } from '../schema/avatars.schema'; | |
import { Banner } from '../schema/banners.schema'; | |
import { Graph } from '../schema/graph.schema'; | |
import { Place } from '../schema/places.schema'; | |
import { Participant, Protest } from '../schema/protests.schema'; | |
import { User, UserAvatar } from '../schema/users.schema'; | |
import { UsersService } from '../users/users.service'; | |
import { GraphMap } from './graph.map'; | |
@Injectable() | |
export class GraphService { | |
constructor( | |
private readonly placesService: PlacesService, | |
private readonly protestsService: ProtestsService, | |
private readonly usersService: UsersService, | |
private readonly avatarsService: AvatarsService, | |
) {} | |
async avatar(a: Avatar): Promise<Graph> { | |
return this.avatars([a]); | |
} | |
async avatars(a: Avatar[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillAvatars(graph, a).then(() => graph); | |
} | |
async banner(b: Banner): Promise<Graph> { | |
return this.banners([b]); | |
} | |
async banners(b: Banner[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillBanners(graph, b).then(() => graph); | |
} | |
async place(p: Place): Promise<Graph> { | |
return this.places([p]); | |
} | |
async places(p: Place[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillPlaces(graph, p).then(() => graph); | |
} | |
async protest(p: Protest): Promise<Graph> { | |
return this.protests([p]); | |
} | |
async protests(p: Protest[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillProtests(graph, p).then(() => graph); | |
} | |
async participant(p: Participant): Promise<Graph> { | |
return this.participants([p]); | |
} | |
async participants(p: Participant[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillParticipants(graph, p).then(() => graph); | |
} | |
async user(u: User): Promise<Graph> { | |
return this.users([u]); | |
} | |
async users(u: User[]): Promise<Graph> { | |
const graph = new GraphMap(); | |
return this.fillUsers(graph, u).then(() => graph); | |
} | |
// Fill | |
private async fillAvatars(m: GraphMap, avatars: Avatar[]): Promise<void> {} | |
private async fillBanners(m: GraphMap, banners: Banner[]): Promise<void> {} | |
private async fillUsers(m: GraphMap, users: User[]): Promise<void> { | |
for (const u of users) { | |
u.userAvatars = await this.usersService.queryAvatars(u.id); | |
u.participations = await this.protestsService.queryActiveParticipantsByUserId( | |
u.id, | |
); | |
await this.fillUserAvatars(m, u.userAvatars); | |
await this.fillParticipants(m, u.participations); | |
} | |
} | |
private async fillUserAvatars( | |
m: GraphMap, | |
userAvatars: UserAvatar[], | |
): Promise<void> { | |
const ids = userAvatars.map(p => p.avatarId); | |
return this.fillAvatarsIds(m, ids); | |
} | |
private async fillParticipants( | |
m: GraphMap, | |
participants: Participant[], | |
): Promise<void> { | |
const userAvatarsIds = participants.map(p => p.userAvatarId); | |
const protestIds = participants.map(p => p.protestId); | |
await this.fillUserAvatarsIds(m, userAvatarsIds); | |
await this.fillProtestsIds(m, protestIds); | |
} | |
private async fillPlaces(m: GraphMap, places: Place[]): Promise<void> { | |
const ids = places.map(place => place.protestId).filter(id => id); | |
return this.fillProtestsIds(m, ids); | |
} | |
private async fillProtests(m: GraphMap, protests: Protest[]): Promise<void> { | |
const usersIds = protests.map(p => p.organizerId); | |
const placesIds = protests.map(p => p.placeId); | |
await this.fillUsersIds(m, usersIds); | |
await this.fillPlacesIds(m, placesIds); | |
} | |
// Fill ids | |
private async fillProtestsIds(m: GraphMap, ids: string[]): Promise<void> { | |
const filteredIds = filterIds(ids, id => !m.protestsMap.has(id)); | |
if (filteredIds.length > 0) { | |
const protests = await this.protestsService.queryByIds(filteredIds); | |
protests.forEach(p => m.addProtest(p)); | |
} | |
} | |
private async fillUsersIds(m: GraphMap, ids: string[]): Promise<void> { | |
const filteredIds = filterIds(ids, id => !m.usersMap.has(id)); | |
if (filteredIds.length > 0) { | |
const users = await this.usersService.queryByIds(ids); | |
users.forEach(u => m.addUser(u)); | |
} | |
} | |
private async fillUserAvatarsIds(m: GraphMap, ids: string[]): Promise<void> { | |
const filteredIds = filterIds(ids, id => !m.userAvatarsMap.has(id)); | |
if (filteredIds.length > 0) { | |
const usersAvatars = await this.usersService.queryAvatarsByIds(ids); | |
const avatarsIds = usersAvatars.map(a => a.avatarId); | |
usersAvatars.forEach(a => m.addUserAvatar(a)); | |
await this.fillAvatarsIds(m, avatarsIds); | |
} | |
} | |
private async fillAvatarsIds(m: GraphMap, ids: number[]): Promise<void> { | |
const filteredIds = filterIds(ids, id => !m.avatarsMap.has(id)); | |
if (filteredIds.length > 0) { | |
const avatars = await this.avatarsService.queryByIds(ids); | |
avatars.forEach(a => m.addAvatar(a)); | |
} | |
} | |
private async fillPlacesIds(m: GraphMap, ids: number[]): Promise<void> { | |
const filteredIds = filterIds(ids, id => !m.placesMap.has(id)); | |
if (filteredIds.length > 0) { | |
const places = await this.placesService.queryByIds(ids); | |
places.forEach(p => m.addPlace(p)); | |
} | |
} | |
} | |
// Remove duplicates, undefined + custom filter | |
function filterIds<T>(ids: T[], filter: (id: T) => boolean): T[] { | |
return ids.filter( | |
(id, i, self) => id && self.indexOf(id) === i && filter(id), | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
BadRequestException, | |
Body, | |
Controller, | |
Get, | |
Post, | |
Put, | |
Request, | |
UseGuards | |
} from '@nestjs/common'; | |
import { AuthGuard } from '@nestjs/passport'; | |
import { | |
ApiBadRequestResponse, | |
ApiBearerAuth, | |
ApiCreatedResponse, | |
ApiOkResponse, | |
ApiOperation, | |
ApiUnauthorizedResponse, | |
ApiUseTags | |
} from '@nestjs/swagger'; | |
import { AuthService } from '../auth/auth.service'; | |
import { GraphService } from '../graph/graph.service'; | |
import { | |
CreateUserRequest, | |
CreateUserResponse, | |
UserResponse | |
} from '../schema/users.schema'; | |
import { UsersService } from '../users/users.service'; | |
@ApiUseTags('users') | |
@ApiBearerAuth() | |
@Controller('users') | |
export class UsersController { | |
constructor( | |
private readonly users: UsersService, | |
private readonly auth: AuthService, | |
private readonly graph: GraphService, | |
) {} | |
@ApiOperation({ | |
title: 'Create new user', | |
description: 'Creates new user with unityId and returns auth token', | |
}) | |
@ApiCreatedResponse({ type: CreateUserResponse, description: 'User created' }) | |
@ApiBadRequestResponse({ description: 'Error' }) | |
@Post('') | |
async create(@Body() params: CreateUserRequest): Promise<CreateUserResponse> { | |
try { | |
const user = await this.users.create(params); | |
const token = await this.auth.login(user); | |
return new CreateUserResponse({ token }); | |
} catch (error) { | |
throw new BadRequestException(error.message); | |
} | |
} | |
@UseGuards(AuthGuard('jwt')) | |
@ApiOperation({ | |
title: 'Get user profile', | |
description: 'Uses auth token to find user, so he must be authenticated', | |
}) | |
@ApiOkResponse({ type: UserResponse, description: 'User found' }) | |
@ApiUnauthorizedResponse({ description: 'Unauthorized' }) | |
@ApiBadRequestResponse({ description: 'Error' }) | |
@Get('me') | |
async me(@Request() req): Promise<UserResponse> { | |
const user = await this.users.getById(req.user.id); | |
const graph = await this.graph.user(user); | |
return new UserResponse({ user, graph }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment