Skip to content

Commit

Permalink
add: getOrCreateUser
Browse files Browse the repository at this point in the history
  • Loading branch information
SIY1121 committed Mar 26, 2021
1 parent fa725b0 commit c6c37ea
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 47 deletions.
12 changes: 6 additions & 6 deletions __tests__/grpc/user.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UserService } from '../../generated'
import { ServiceClientConstructor } from '@grpc/grpc-js/build/src/make-client'
import { GrpcClient } from '../../src/grpc/type'
import { Status } from '@grpc/grpc-js/build/src/constants'
import { createUserUseCase } from '../../src/usecase/createUser'
import { getOrCreateUserUseCase } from '../../src/usecase/getOrCreateUser'
import { mocked } from 'ts-jest/utils'
import { v4 } from 'uuid'
import { addAuthenticationUseCase } from '../../src/usecase/addAuthentication'
Expand All @@ -22,7 +22,7 @@ const pkg = grpc.loadPackageDefinition(def)
const ClientConstructor = pkg.UserService as ServiceClientConstructor
let client: GrpcClient<UserService>

jest.mock('../../src/usecase/createUser')
jest.mock('../../src/usecase/getOrCreateUser')
jest.mock('../../src/usecase/addAuthentication')
jest.mock('../../src/usecase/getUser')

Expand All @@ -37,21 +37,21 @@ beforeAll(async () => {
describe('createUser', () => {
test('success', (done) => {
const id = v4()
mocked(createUserUseCase).mockImplementation(async () => ({
mocked(getOrCreateUserUseCase).mockImplementation(async () => ({
id,
}))
client.createUser({}, (err, res) => {
client.getOrCreateUser({}, (err, res) => {
expect(err).toBeNull()
expect(res?.id).toEqual(id)
done()
})
})

test('unexpected error', (done) => {
mocked(createUserUseCase).mockImplementation(() => {
mocked(getOrCreateUserUseCase).mockImplementation(() => {
throw new Error('Unexpected Error')
})
client.createUser({}, (err, res) => {
client.getOrCreateUser({}, (err, res) => {
expect(err?.code).toEqual(Status.UNKNOWN)
done()
})
Expand Down
16 changes: 0 additions & 16 deletions __tests__/usecase/createUser.test.ts

This file was deleted.

34 changes: 34 additions & 0 deletions __tests__/usecase/getOrCreateUser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { connectDatabase, disconnectDatabase } from '../../src/database'
import { Provider } from '../../src/database/model/userAuthentications'
import { getOrCreateUserUseCase } from '../../src/usecase/getOrCreateUser'
import { clearDB } from '../_cleardb'

beforeAll(async () => {
await connectDatabase()
await clearDB()
})

let userId = ''
test('初回作成', async () => {
const res = await getOrCreateUserUseCase(
Provider.Google,
'100000000000000000'
)
userId = res.id
return expect(res).toEqual(
expect.objectContaining({
id: expect.any(String),
})
)
})

test('get user', () =>
expect(
getOrCreateUserUseCase(Provider.Google, '100000000000000000')
).resolves.toEqual(
expect.objectContaining({
id: userId,
})
))

afterAll(disconnectDatabase)
9 changes: 6 additions & 3 deletions protos/UserService.proto
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
syntax="proto3";

service UserService {
rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
rpc GetOrCreateUser(GetOrCreateUserRequest) returns (GetOrCreateUserResponse);
rpc AddAuthentication(AddAuthenticationRequest) returns (AddAuthenticationResponse);
rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
Expand All @@ -17,9 +17,12 @@ message Authentication {
string socialId = 2;
}

message CreateUserRequest {}
message GetOrCreateUserRequest {
Provider provider = 1;
string socialId = 2;
}

message CreateUserResponse {
message GetOrCreateUserResponse {
string id = 1;
}

Expand Down
2 changes: 1 addition & 1 deletion src/database/model/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class User {
})
id!: string

@OneToMany((type) => UserAuthentication, (auth) => auth.userId, {
@OneToMany((type) => UserAuthentication, (auth) => auth.user, {
cascade: true,
})
authentications!: UserAuthentication[]
Expand Down
2 changes: 1 addition & 1 deletion src/database/model/userAuthentications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class UserAuthentication {
id!: number

@ManyToOne((type) => User, (user) => user.id)
userId!: string
user!: User

@Column({
name: 'provider',
Expand Down
13 changes: 8 additions & 5 deletions src/grpc/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import {
AddAuthenticationResponse,
CreateUserResponse,
GetOrCreateUserResponse,
GetUserResponse,
UserService,
} from '../../generated'
import { addAuthenticationUseCase } from '../usecase/addAuthentication'
import { createUserUseCase } from '../usecase/createUser'
import { getOrCreateUserUseCase } from '../usecase/getOrCreateUser'
import { getUserUseCase } from '../usecase/getUser'
import { toGrpcError } from './converter'
import { GrpcServer } from './type'

export const userService: GrpcServer<UserService> = {
async createUser(_, callback) {
async getOrCreateUser({ request }, callback) {
try {
const res = await createUserUseCase()
callback(null, CreateUserResponse.create({ ...res }))
const res = await getOrCreateUserUseCase(
request.provider,
request.socialId
)
callback(null, GetOrCreateUserResponse.create({ ...res }))
} catch (e) {
callback(toGrpcError(e))
}
Expand Down
13 changes: 7 additions & 6 deletions src/usecase/addAuthentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ export async function addAuthenticationUseCase(
throw new NotFoundError('指定されたユーザーが見つかりません')

const authRepo = getConnection().getRepository(UserAuthentication)
if (await authRepo.findOne({ userId: id, provider }))
if (await authRepo.findOne({ provider, user: { id } }))
throw new AlreadyExistError('認証情報が既に登録されています')
const auth = new UserAuthentication()
auth.provider = provider
auth.userId = id
auth.socialId = socialId
await authRepo.save(auth)

await authRepo.save({
provider,
socialId,
user: { id },
})
}
9 changes: 0 additions & 9 deletions src/usecase/createUser.ts

This file was deleted.

23 changes: 23 additions & 0 deletions src/usecase/getOrCreateUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getConnection, getRepository } from 'typeorm'
import { v4 } from 'uuid'
import { User } from '../database/model/user'
import {
Provider,
UserAuthentication,
} from '../database/model/userAuthentications'

export async function getOrCreateUserUseCase(
provider: Provider,
socialId: string
): Promise<{ id: string }> {
const auth = await getRepository(UserAuthentication).findOne({
where: { provider, socialId },
relations: ['user'],
})
if (auth) return getRepository(User).findOneOrFail({ id: auth.user.id })
else
return getRepository(User).save({
id: v4(),
authentications: [{ socialId, provider }],
})
}

0 comments on commit c6c37ea

Please sign in to comment.