feat: db schema update from string to json column type

This commit is contained in:
Mir Arif Hasan
2023-01-24 15:10:54 +06:00
parent 33e4a15830
commit ebbe015bbc
7 changed files with 84 additions and 50 deletions

View File

@@ -83,8 +83,8 @@ model User {
displayName String?
email String?
photoURL String?
currentRESTSession String?
currentGQLSession String?
currentRESTSession Json?
currentGQLSession Json?
UserEnvironments UserEnvironment[]
}

View File

@@ -26,6 +26,12 @@ export const USER_FB_DOCUMENT_DELETION_FAILED =
*/
export const USER_NOT_FOUND = 'user/not_found' as const;
/**
* User update failure
* (UserService)
*/
export const USER_UPDATE_FAILED = 'user/update_failed' as const;
/**
* User deletion failure
* (UserService)

View File

@@ -7,8 +7,6 @@ export type TopicDef = {
[
topic: `user_environment/${string}/${'created' | 'updated' | 'deleted'}`
]: UserEnvironment;
[
topic: `user/${string}/${'created' | 'updated' | 'deleted'}`
]: User;
[topic: `user/${string}/${'updated'}`]: User;
[topic: `user_environment/${string}/deleted_many`]: number;
};

View File

@@ -1,32 +0,0 @@
import { Field, InputType } from '@nestjs/graphql';
@InputType()
export class UpdateUserInput {
@Field({
nullable: true,
name: 'displayName',
description: 'Displayed name of the user (if given)',
})
displayName?: string;
@Field({
nullable: true,
name: 'photoURL',
description: 'URL to the profile photo of the user (if given)',
})
photoURL?: string;
@Field({
nullable: true,
name: 'currentRESTSession',
description: 'JSON string of the saved REST session',
})
currentRESTSession?: string;
@Field({
nullable: true,
name: 'currentGQLSession',
description: 'JSON string of the saved GQL session',
})
currentGQLSession?: string;
}

View File

@@ -1,4 +1,4 @@
import { ObjectType, ID, Field } from '@nestjs/graphql';
import { ObjectType, ID, Field, InputType } from '@nestjs/graphql';
@ObjectType()
export class User {
@@ -37,3 +37,34 @@ export class User {
})
currentGQLSession?: string;
}
@InputType()
export class UpdateUserInput {
@Field({
nullable: true,
name: 'displayName',
description: 'Displayed name of the user (if given)',
})
displayName?: string;
@Field({
nullable: true,
name: 'photoURL',
description: 'URL to the profile photo of the user (if given)',
})
photoURL?: string;
@Field({
nullable: true,
name: 'currentRESTSession',
description: 'JSON string of the saved REST session',
})
currentRESTSession?: string;
@Field({
nullable: true,
name: 'currentGQLSession',
description: 'JSON string of the saved GQL session',
})
currentGQLSession?: string;
}

View File

@@ -1,12 +1,11 @@
import { Resolver, Query, Mutation, Args, Subscription } from '@nestjs/graphql';
import { User } from './user.model';
import { UpdateUserInput, User } from './user.model';
import { UseGuards } from '@nestjs/common';
import { GqlAuthGuard } from '../guards/gql-auth.guard';
import { GqlUser } from '../decorators/gql-user.decorator';
import { UserService } from './user.service';
import { throwErr } from 'src/utils';
import * as E from 'fp-ts/lib/Either';
import { UpdateUserInput } from './dtos/update-user-input.dto';
import { PubSubService } from 'src/pubsub/pubsub.service';
@Resolver(() => User)
@@ -58,7 +57,7 @@ export class UserResolver {
resolve: (value) => value,
})
@UseGuards(GqlAuthGuard)
userSettingsUpdated(@GqlUser() user: User) {
userUpdated(@GqlUser() user: User) {
return this.pubsub.asyncIterator(`user/${user.uid}/updated`);
}
}

View File

@@ -1,10 +1,11 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { User } from './user.model';
import { UpdateUserInput, User } from './user.model';
import { User as DbUser, Prisma } from '@prisma/client';
import * as E from 'fp-ts/lib/Either';
import { USER_NOT_FOUND } from 'src/errors';
import { UpdateUserInput } from './dtos/update-user-input.dto';
import { USER_UPDATE_FAILED } from 'src/errors';
import { PubSubService } from 'src/pubsub/pubsub.service';
import { stringToJson } from 'src/utils';
@Injectable()
export class UserService {
@@ -16,22 +17,53 @@ export class UserService {
/**
* Update a user's information
* @param user User object
* @param updateUserData Properties to update
* @param updateData Properties to update
* @returns a Either of User or error
*/
async updateUser(user: User, updateUserData: UpdateUserInput) {
async updateUser(
user: User,
updateData: UpdateUserInput,
): Promise<E.Either<string, User>> {
let { currentGQLSession, currentRESTSession, ...rest } = updateData;
let updateUserObj: Partial<DbUser> = rest;
// Convert stringified JSON to JSON
if (updateData?.currentGQLSession !== undefined) {
const jsonGql = stringToJson(updateData.currentGQLSession);
if (E.isLeft<string>(jsonGql)) return jsonGql;
updateUserObj.currentGQLSession = jsonGql?.right ?? Prisma.DbNull;
}
if (updateData?.currentRESTSession !== undefined) {
const jsonRest = stringToJson(updateData.currentRESTSession);
if (E.isLeft<string>(jsonRest)) return jsonRest;
updateUserObj.currentRESTSession = jsonRest?.right ?? Prisma.DbNull;
}
// Update user
try {
const updatedUser = await this.prisma.user.update({
const dbUpdatedUser = await this.prisma.user.update({
where: { uid: user.uid },
data: updateUserData,
data: updateUserObj,
});
const updatedUser: User = {
...dbUpdatedUser,
currentGQLSession: dbUpdatedUser.currentGQLSession
? JSON.stringify(dbUpdatedUser.currentGQLSession)
: null,
currentRESTSession: dbUpdatedUser.currentRESTSession
? JSON.stringify(dbUpdatedUser.currentRESTSession)
: null,
};
// Publish subscription for user updates
await this.pubsub.publish(`user/${user.uid}/updated`, updatedUser);
await this.pubsub.publish(`user/${updatedUser.uid}/updated`, updatedUser);
return E.right(updatedUser);
} catch (e) {
return E.left(USER_NOT_FOUND);
return E.left(USER_UPDATE_FAILED);
}
}
}