Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions api/graphql/department.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Department types and inputs

type Department {
id: ID!
name: String!
description: String!
managerId: ID
createdAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
updatedAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
}

type DepartmentConnection {
edges: [DepartmentEdge!]!
pageInfo: PageInfo!
}

type DepartmentEdge {
node: Department!
cursor: String!
}

input CreateDepartmentInput {
name: String!
description: String!
managerId: ID
}

input UpdateDepartmentInput {
name: String
description: String
managerId: ID
}

type CreateDepartmentPayload {
department: Department!
errors: [Error!]
}

type UpdateDepartmentPayload {
department: Department!
errors: [Error!]
}

type DeleteDepartmentPayload {
success: Boolean!
errors: [Error!]
}
74 changes: 74 additions & 0 deletions api/graphql/leave.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Leave types and inputs

type Leave {
id: ID!
employeeId: ID!
leaveType: String!
startDate: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
endDate: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
reason: String!
status: String!
approvedBy: ID
approvedAt: String # TODO: Change to Time scalar when custom scalar marshaling is implemented
createdAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
updatedAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
}

type LeaveConnection {
edges: [LeaveEdge!]!
pageInfo: PageInfo!
}

type LeaveEdge {
node: Leave!
cursor: String!
}

input CreateLeaveInput {
employeeId: ID!
leaveType: String!
startDate: String!
endDate: String!
reason: String!
}

input UpdateLeaveInput {
leaveType: String
startDate: String
endDate: String
reason: String
}

input ApproveLeaveInput {
approvedBy: ID!
}

type CreateLeavePayload {
leave: Leave!
errors: [Error!]
}

type UpdateLeavePayload {
leave: Leave!
errors: [Error!]
}

type ApproveLeavePayload {
leave: Leave!
errors: [Error!]
}

type RejectLeavePayload {
leave: Leave!
errors: [Error!]
}

type CancelLeavePayload {
leave: Leave!
errors: [Error!]
}

type DeleteLeavePayload {
success: Boolean!
errors: [Error!]
}
14 changes: 13 additions & 1 deletion api/graphql/mutation.graphqls
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# User and Employee mutations
# User, Employee, Department, Position, and Leave mutations

type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
Expand All @@ -7,4 +7,16 @@ type Mutation {
createEmployee(input: CreateEmployeeInput!): CreateEmployeePayload!
updateEmployee(id: ID!, input: UpdateEmployeeInput!): UpdateEmployeePayload!
deleteEmployee(id: ID!): DeleteEmployeePayload!
createDepartment(input: CreateDepartmentInput!): CreateDepartmentPayload!
updateDepartment(id: ID!, input: UpdateDepartmentInput!): UpdateDepartmentPayload!
deleteDepartment(id: ID!): DeleteDepartmentPayload!
createPosition(input: CreatePositionInput!): CreatePositionPayload!
updatePosition(id: ID!, input: UpdatePositionInput!): UpdatePositionPayload!
deletePosition(id: ID!): DeletePositionPayload!
createLeave(input: CreateLeaveInput!): CreateLeavePayload!
updateLeave(id: ID!, input: UpdateLeaveInput!): UpdateLeavePayload!
approveLeave(id: ID!, input: ApproveLeaveInput!): ApproveLeavePayload!
rejectLeave(id: ID!, input: ApproveLeaveInput!): RejectLeavePayload!
cancelLeave(id: ID!): CancelLeavePayload!
deleteLeave(id: ID!): DeleteLeavePayload!
}
56 changes: 56 additions & 0 deletions api/graphql/position.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Position types and inputs

type Position {
id: ID!
title: String!
description: String!
departmentId: ID
requirements: String!
minSalary: Float!
maxSalary: Float!
createdAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
updatedAt: String! # TODO: Change to Time scalar when custom scalar marshaling is implemented
}

type PositionConnection {
edges: [PositionEdge!]!
pageInfo: PageInfo!
}

type PositionEdge {
node: Position!
cursor: String!
}

input CreatePositionInput {
title: String!
description: String!
departmentId: ID
requirements: String!
minSalary: Float!
maxSalary: Float!
}

input UpdatePositionInput {
title: String
description: String
departmentId: ID
requirements: String
minSalary: Float
maxSalary: Float
}

type CreatePositionPayload {
position: Position!
errors: [Error!]
}

type UpdatePositionPayload {
position: Position!
errors: [Error!]
}

type DeletePositionPayload {
success: Boolean!
errors: [Error!]
}
12 changes: 11 additions & 1 deletion api/graphql/query.graphqls
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# User and Employee queries
# User, Employee, Department, Position, and Leave queries

type Query {
user(id: ID!): User
Expand All @@ -7,4 +7,14 @@ type Query {
employees(first: Int, after: String): EmployeeConnection!
employeesByDepartment(department: String!, first: Int, after: String): EmployeeConnection!
employeesByStatus(status: String!, first: Int, after: String): EmployeeConnection!
department(id: ID!): Department
departments(first: Int, after: String): DepartmentConnection!
departmentsByManager(managerId: ID!, first: Int, after: String): DepartmentConnection!
position(id: ID!): Position
positions(first: Int, after: String): PositionConnection!
positionsByDepartment(departmentId: ID!, first: Int, after: String): PositionConnection!
leave(id: ID!): Leave
leaves(first: Int, after: String): LeaveConnection!
leavesByEmployee(employeeId: ID!, first: Int, after: String): LeaveConnection!
leavesByStatus(status: String!, first: Int, after: String): LeaveConnection!
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Strongly type leave status as an enum.

Avoids invalid strings at runtime.

-  leavesByStatus(status: String!, first: Int, after: String): LeaveConnection!
+  leavesByStatus(status: LeaveStatus!, first: Int, after: String): LeaveConnection!

Follow-up: define enum LeaveStatus { PENDING APPROVED REJECTED CANCELED } in leave.graphqls.

🤖 Prompt for AI Agents
In api/graphql/query.graphqls around lines 19-19, the leavesByStatus argument is
currently typed as String which allows invalid values; change its type to the
new enum LeaveStatus so GraphQL enforces allowed values, and add a new enum
definition in api/graphql/leave.graphqls: define enum LeaveStatus { PENDING
APPROVED REJECTED CANCELED }. After adding the enum, update any schema
imports/exports and adjust resolver/input handling to expect the LeaveStatus
enum value (or map it to internal strings) so existing resolver logic continues
to work.

}
102 changes: 102 additions & 0 deletions internal/application/department/dto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package department

import (
"time"
)

// DepartmentDTO represents a department data transfer object
type DepartmentDTO struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
ManagerID *string `json:"managerId,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}

// DepartmentConnectionDTO represents a paginated connection of departments
type DepartmentConnectionDTO struct {
Departments []*DepartmentDTO `json:"departments"`
NextCursor string `json:"nextCursor"`
}

// GetDepartmentRequest represents a request to get a department by ID
type GetDepartmentRequest struct {
ID string `json:"id"`
}

// GetDepartmentResponse represents a response for getting a department
type GetDepartmentResponse struct {
Department *DepartmentDTO `json:"department,omitempty"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// ListDepartmentsRequest represents a request to list departments
type ListDepartmentsRequest struct {
Limit int `json:"limit"`
Cursor string `json:"cursor,omitempty"`
}

// ListDepartmentsResponse represents a response for listing departments
type ListDepartmentsResponse struct {
Departments *DepartmentConnectionDTO `json:"departments,omitempty"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// ListDepartmentsByManagerRequest represents a request to list departments by manager
type ListDepartmentsByManagerRequest struct {
ManagerID string `json:"managerId"`
Limit int `json:"limit"`
Cursor string `json:"cursor,omitempty"`
}

// ListDepartmentsByManagerResponse represents a response for listing departments by manager
type ListDepartmentsByManagerResponse struct {
Departments *DepartmentConnectionDTO `json:"departments,omitempty"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// CreateDepartmentRequest represents a request to create a department
type CreateDepartmentRequest struct {
Name string `json:"name"`
Description string `json:"description"`
ManagerID *string `json:"managerId,omitempty"`
}

// CreateDepartmentResponse represents a response for creating a department
type CreateDepartmentResponse struct {
Department *DepartmentDTO `json:"department,omitempty"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// UpdateDepartmentRequest represents a request to update a department
type UpdateDepartmentRequest struct {
ID string `json:"id"`
Name *string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
ManagerID *string `json:"managerId,omitempty"`
}

// UpdateDepartmentResponse represents a response for updating a department
type UpdateDepartmentResponse struct {
Department *DepartmentDTO `json:"department,omitempty"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// DeleteDepartmentRequest represents a request to delete a department
type DeleteDepartmentRequest struct {
ID string `json:"id"`
}

// DeleteDepartmentResponse represents a response for deleting a department
type DeleteDepartmentResponse struct {
Success bool `json:"success"`
Errors []ErrorDTO `json:"errors,omitempty"`
}

// ErrorDTO represents an error data transfer object
type ErrorDTO struct {
Message string `json:"message"`
Field string `json:"field,omitempty"`
Code string `json:"code,omitempty"`
}
Loading