-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api-service): Add user service (#46)
* feat: create user script * fix: set database name as singular * build(dep): add class-transformer * feat: domain persistence and usecase * feat: remove profile image * feat: user usecases * feat: user port * feat: user di token * feat: remove T prefix * feat: remove constructure and getter/setter * feat: export functions * fix: add new User function * feat: add User service * chore: add service path * fix: resolve issues * refactor: domain and service --------- Co-authored-by: spicyzboss <supachai@spicyz.io>
- Loading branch information
1 parent
854f7b9
commit e536b18
Showing
36 changed files
with
330 additions
and
80 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CREATE TABLE User ( | ||
user_id VARCHAR(255) PRIMARY KEY, | ||
user_name VARCHAR(255) NOT NULL, | ||
email VARCHAR(255) NOT NULL, | ||
first_name VARCHAR(255) NOT NULL, | ||
last_name VARCHAR(255) NOT NULL, | ||
created_at int NOT NULL, | ||
updated_at int, | ||
deleted_at int | ||
); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export * from './entity'; | ||
export * from './exception'; | ||
export * from './nullable'; | ||
export * from './optional'; | ||
export * from './removable'; | ||
export * from './repository'; | ||
export * from './statusCode'; | ||
export * from './usecase'; | ||
export * from './validator'; |
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export type FindOptions = { | ||
includeRemoved?: boolean; | ||
limit?: number; | ||
offset?: number; | ||
}; | ||
|
||
export type UpdateManyOptions = { | ||
includeRemoved?: boolean; | ||
}; | ||
|
||
export type RemoveOptions = { | ||
disableSoftDeleting?: boolean; | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export interface UseCase<Port, T> { | ||
execute(port?: Port): Promise<T>; | ||
} | ||
|
||
export interface TransactionalUseCase<Port, T> extends UseCase<Port, T> { | ||
onCommit?: (result: T, port: Port) => Promise<void>; | ||
onRollback?: (error: Error, port: Port) => Promise<void>; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './user'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,39 @@ | ||
import { Entity } from '../common/entity'; | ||
import { IsDate, IsEmail, IsOptional, IsString, IsUrl } from 'class-validator'; | ||
import { CreateUserPayload } from '../model/createUserPayload'; | ||
import { Entity, Nullable } from '../common'; | ||
import { IsDate, IsOptional, IsString } from 'class-validator'; | ||
import { CreateUserPayload } from '../user'; | ||
import { typeid } from 'typeid-js'; | ||
import { Nullable } from '../common/nullable'; | ||
|
||
export class User extends Entity<string> { | ||
@IsString() | ||
private username: string; | ||
|
||
@IsEmail() | ||
private email: string; | ||
public readonly username: string; | ||
|
||
@IsString() | ||
private firstName: string; | ||
public readonly firstName: string; | ||
|
||
@IsString() | ||
private lastName: string; | ||
|
||
@IsOptional() | ||
@IsUrl() | ||
private profileImage: string; | ||
public readonly lastName: string; | ||
|
||
@IsDate() | ||
private createdAt: Date; | ||
public readonly createdAt: Date; | ||
|
||
@IsOptional() | ||
@IsDate() | ||
private updatedAt: Nullable<Date>; | ||
public readonly updatedAt: Nullable<Date>; | ||
|
||
@IsOptional() | ||
@IsDate() | ||
private deletedAt: Nullable<Date>; | ||
public readonly deletedAt: Nullable<Date>; | ||
|
||
constructor(payload: CreateUserPayload) { | ||
private constructor(payload: CreateUserPayload) { | ||
super(); | ||
|
||
this.username = payload.username; | ||
this.email = payload.email; | ||
this.id = typeid('user').toString(); | ||
this.firstName = payload.firstName; | ||
this.lastName = payload.lastName; | ||
this.profileImage = payload.profileImage; | ||
this.email = payload.email; | ||
|
||
this.id = typeid('user').toString(); | ||
this.createdAt = new Date(); | ||
this.updatedAt = null; | ||
this.deletedAt = null; | ||
} | ||
|
||
getUsername(): string { | ||
return this.username; | ||
} | ||
|
||
getEmail(): string { | ||
return this.email; | ||
} | ||
|
||
getFirstName(): string { | ||
return this.firstName; | ||
} | ||
|
||
getLastName(): string { | ||
return this.lastName; | ||
} | ||
|
||
getProfileImage(): string { | ||
return this.profileImage; | ||
} | ||
|
||
getCreatedAt(): Date { | ||
return this.createdAt; | ||
} | ||
|
||
getUpdatedAt(): Nullable<Date> { | ||
return this.updatedAt; | ||
} | ||
|
||
getDeletedAt(): Nullable<Date> { | ||
return this.deletedAt; | ||
public static new(payload: CreateUserPayload): User { | ||
return new User(payload); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './common'; | ||
export * from './entity'; | ||
export * from './user'; | ||
export * from './util'; |
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './userUseCaseDto'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { User } from '../../entity'; | ||
import { Exclude, Expose, plainToClass } from 'class-transformer'; | ||
|
||
@Exclude() | ||
export class UserUseCaseDto { | ||
@Expose() | ||
public readonly username: string; | ||
|
||
@Expose() | ||
public readonly firstName: string; | ||
|
||
@Expose() | ||
public readonly lastName: string; | ||
|
||
public static fromUser(user: User): UserUseCaseDto { | ||
return plainToClass(UserUseCaseDto, user); | ||
} | ||
|
||
public static fromUsers(users: User[]): UserUseCaseDto[] { | ||
return users.map(this.fromUser); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './dto'; | ||
export * from './model'; | ||
export * from './port'; | ||
export * from './usecase'; |
12 changes: 12 additions & 0 deletions
12
libs/api/shared/domain/src/user/model/createUserPayload.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { IsString } from 'class-validator'; | ||
|
||
export class CreateUserPayload { | ||
@IsString() | ||
public readonly username: string; | ||
|
||
@IsString() | ||
public readonly firstName: string; | ||
|
||
@IsString() | ||
public readonly lastName: string; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './createUserPayload'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface CreateUserPort { | ||
firstName: string; | ||
lastName: string; | ||
username: string; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export interface FindUserPort { | ||
id?: string; | ||
username?: string; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export * from './createUserPort'; | ||
export * from './findUserPort'; | ||
export * from './removeUserPort'; | ||
export * from './updateUserPort'; | ||
export * from './userRepositoryPort'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export interface RemoveUserPort { | ||
id: string; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export interface UpdateUserPort { | ||
firstName: string; | ||
lastName: string; | ||
username: string; | ||
} |
12 changes: 12 additions & 0 deletions
12
libs/api/shared/domain/src/user/port/userRepositoryPort.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Optional, FindOptions } from '../../common'; | ||
import { User } from '../../entity'; | ||
import { FindUserPort } from './findUserPort'; | ||
import { RemoveUserPort } from './removeUserPort'; | ||
|
||
export interface UserRepositoryPort { | ||
findUser(by: FindUserPort, options?: FindOptions): Promise<Optional<User>>; | ||
countUsers(by: FindUserPort, options?: FindOptions): Promise<number>; | ||
createUser(user: User): Promise<User>; | ||
updateUser(user: User): Promise<Optional<User>>; | ||
removeUser(by: RemoveUserPort): Promise<Optional<User>>; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Optional, UseCase } from '../../common'; | ||
import { CreateUserPort } from '../port'; | ||
import { UserUseCaseDto } from '../dto'; | ||
|
||
export interface CreateUserUseCase extends UseCase<CreateUserPort, Optional<UserUseCaseDto>> {} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Optional, UseCase } from '../../common'; | ||
import { FindUserPort } from '../port'; | ||
import { UserUseCaseDto } from '../dto'; | ||
|
||
export interface FindUserUseCase extends UseCase<FindUserPort, Optional<UserUseCaseDto>> {} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './findUserUseCase'; | ||
export * from './createUserUseCase'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Nullable } from '../common/nullable'; | ||
import { Optional } from '../common/optional'; | ||
|
||
export class Assert { | ||
static isTrue(expression: boolean, exception: Error): void { | ||
if (!expression) { | ||
throw exception; | ||
} | ||
} | ||
|
||
static isFalse(expression: boolean, exception: Error): void { | ||
if (expression) { | ||
throw exception; | ||
} | ||
} | ||
|
||
static notEmpty<T>(value: Optional<Nullable<T>>, exception: Error): T { | ||
if (value === null || value === undefined) { | ||
throw exception; | ||
} | ||
return value; | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './assert'; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"extends": ["../../../../.eslintrc.json"], | ||
"ignorePatterns": ["!**/*"], | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.js", "*.jsx"], | ||
"rules": {} | ||
} | ||
] | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"name": "api-service", | ||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json", | ||
"sourceRoot": "libs/api/shared/service/src", | ||
"projectType": "library", | ||
"targets": { | ||
"lint": { | ||
"executor": "@nx/eslint:lint", | ||
"outputs": ["{options.outputFile}"] | ||
} | ||
}, | ||
"tags": [] | ||
} |
53 changes: 53 additions & 0 deletions
53
libs/api/shared/service/src/user/usecase/createUserService.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { | ||
Assert, | ||
CreateUserPort, | ||
CreateUserUseCase, | ||
Exception, | ||
FindUserPort, | ||
Optional, | ||
StatusCode, | ||
User, | ||
UserRepositoryPort, | ||
UserUseCaseDto | ||
} from '@producktivity/api-domain'; | ||
|
||
export class CreateUserService implements CreateUserUseCase { | ||
constructor(private readonly userRepository: UserRepositoryPort) { } | ||
|
||
public async execute(payload: CreateUserPort): Promise<Optional<UserUseCaseDto>> { | ||
const isUserExist = await this.isUserExist(payload); | ||
Assert.isFalse(isUserExist, Exception.new({ code: StatusCode.ENTITY_ALREADY_EXISTS })); | ||
|
||
const user: User = User.new({ | ||
firstName: payload.firstName, | ||
lastName: payload.lastName, | ||
username: payload.lastName, | ||
}); | ||
|
||
const createdUser = await this.createUser(user); | ||
|
||
if (!createdUser) throw Exception.new({ code: StatusCode.INTERNAL_ERROR }); | ||
|
||
return UserUseCaseDto.fromUser(createdUser); | ||
} | ||
|
||
private async createUser(user: User): Promise<Optional<User>> { | ||
try { | ||
const createdUser = await this.userRepository.createUser(user); | ||
|
||
return createdUser; | ||
} catch (err) { | ||
return; | ||
} | ||
} | ||
|
||
private async isUserExist({ username }: Required<Pick<FindUserPort, 'username'>>): Promise<boolean> { | ||
try { | ||
const userCount = await this.userRepository.countUsers({ username }); | ||
|
||
return Boolean(userCount); | ||
} catch (err) { | ||
return false; | ||
} | ||
} | ||
} |
Oops, something went wrong.