feat: Introduce Undefined function for Nullable type and refactor DTOs to use Nullable directly
This commit is contained in:
parent
4170eb5fbd
commit
b47c29cf5a
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/oklog/ulid/v2"
|
"github.com/oklog/ulid/v2"
|
||||||
"github.com/timetracker/backend/internal/models"
|
"github.com/timetracker/backend/internal/models"
|
||||||
|
"github.com/timetracker/backend/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -101,7 +102,7 @@ func testUserModel(ctx context.Context) {
|
|||||||
Email: "test@example.com",
|
Email: "test@example.com",
|
||||||
Password: "Test@123456",
|
Password: "Test@123456",
|
||||||
Role: models.RoleUser,
|
Role: models.RoleUser,
|
||||||
CompanyID: companyID,
|
CompanyID: &companyID,
|
||||||
HourlyRate: 50.0,
|
HourlyRate: 50.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +197,7 @@ func testRelationships(ctx context.Context) {
|
|||||||
|
|
||||||
// Test invalid ID
|
// Test invalid ID
|
||||||
invalidID := ulid.MustNew(ulid.Timestamp(time.Now()), ulid.DefaultEntropy())
|
invalidID := ulid.MustNew(ulid.Timestamp(time.Now()), ulid.DefaultEntropy())
|
||||||
invalidUser, err := models.GetUserByID(ctx, models.FromULID(invalidID))
|
invalidUser, err := models.GetUserByID(ctx, types.FromULID(invalidID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error getting user with invalid ID: %v", err)
|
log.Fatalf("Error getting user with invalid ID: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ func (h *CompanyHandler) CreateCompany(c *gin.Context) {
|
|||||||
func (h *CompanyHandler) UpdateCompany(c *gin.Context) {
|
func (h *CompanyHandler) UpdateCompany(c *gin.Context) {
|
||||||
// Parse ID from URL
|
// Parse ID from URL
|
||||||
idStr := c.Param("id")
|
idStr := c.Param("id")
|
||||||
id, err := ulid.Parse(idStr)
|
id, err := types.ULIDFromString(idStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, "Invalid company ID format")
|
utils.BadRequestResponse(c, "Invalid company ID format")
|
||||||
return
|
return
|
||||||
@ -160,11 +160,8 @@ func (h *CompanyHandler) UpdateCompany(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ID from URL
|
|
||||||
companyUpdateDTO.ID = id.String()
|
|
||||||
|
|
||||||
// Convert DTO to model
|
// Convert DTO to model
|
||||||
companyUpdate := convertUpdateCompanyDTOToModel(companyUpdateDTO)
|
companyUpdate := convertUpdateCompanyDTOToModel(companyUpdateDTO, id)
|
||||||
|
|
||||||
// Update company in the database
|
// Update company in the database
|
||||||
company, err := models.UpdateCompany(c.Request.Context(), companyUpdate)
|
company, err := models.UpdateCompany(c.Request.Context(), companyUpdate)
|
||||||
@ -234,10 +231,9 @@ func convertCreateCompanyDTOToModel(dto dto.CompanyCreateDto) models.CompanyCrea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertUpdateCompanyDTOToModel(dto dto.CompanyUpdateDto) models.CompanyUpdate {
|
func convertUpdateCompanyDTOToModel(dto dto.CompanyUpdateDto, id types.ULID) models.CompanyUpdate {
|
||||||
id, _ := ulid.Parse(dto.ID)
|
|
||||||
update := models.CompanyUpdate{
|
update := models.CompanyUpdate{
|
||||||
ID: types.FromULID(id),
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.Name != nil {
|
if dto.Name != nil {
|
||||||
|
@ -319,16 +319,14 @@ func convertUpdateCustomerDTOToModel(dto dto.CustomerUpdateDto) (models.Customer
|
|||||||
update.Name = dto.Name
|
update.Name = dto.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.CompanyID != nil {
|
if dto.CompanyID.Valid {
|
||||||
if dto.CompanyID.Valid {
|
companyID, err := types.ULIDFromString(*dto.CompanyID.Value)
|
||||||
companyID, err := types.ULIDFromString(*dto.CompanyID.Value)
|
if err != nil {
|
||||||
if err != nil {
|
return models.CustomerUpdate{}, fmt.Errorf("invalid company ID: %w", err)
|
||||||
return models.CustomerUpdate{}, fmt.Errorf("invalid company ID: %w", err)
|
|
||||||
}
|
|
||||||
update.CompanyID = &companyID
|
|
||||||
} else {
|
|
||||||
update.CompanyID = nil
|
|
||||||
}
|
}
|
||||||
|
update.CompanyID = &companyID
|
||||||
|
} else {
|
||||||
|
update.CompanyID = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return update, nil
|
return update, nil
|
||||||
|
@ -220,7 +220,7 @@ func (h *ProjectHandler) CreateProject(c *gin.Context) {
|
|||||||
func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
||||||
// Parse ID from URL
|
// Parse ID from URL
|
||||||
idStr := c.Param("id")
|
idStr := c.Param("id")
|
||||||
id, err := ulid.Parse(idStr)
|
id, err := types.ULIDFromString(idStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, "Invalid project ID format")
|
utils.BadRequestResponse(c, "Invalid project ID format")
|
||||||
return
|
return
|
||||||
@ -233,11 +233,8 @@ func (h *ProjectHandler) UpdateProject(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ID from URL
|
|
||||||
projectUpdateDTO.ID = id.String()
|
|
||||||
|
|
||||||
// Convert DTO to model
|
// Convert DTO to model
|
||||||
projectUpdate, err := convertUpdateProjectDTOToModel(projectUpdateDTO)
|
projectUpdate, err := convertUpdateProjectDTOToModel(projectUpdateDTO, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, err.Error())
|
utils.BadRequestResponse(c, err.Error())
|
||||||
return
|
return
|
||||||
@ -297,49 +294,51 @@ func (h *ProjectHandler) DeleteProject(c *gin.Context) {
|
|||||||
// Helper functions for DTO conversion
|
// Helper functions for DTO conversion
|
||||||
|
|
||||||
func convertProjectToDTO(project *models.Project) dto.ProjectDto {
|
func convertProjectToDTO(project *models.Project) dto.ProjectDto {
|
||||||
|
customerId := project.CustomerID.String()
|
||||||
return dto.ProjectDto{
|
return dto.ProjectDto{
|
||||||
ID: project.ID.String(),
|
ID: project.ID.String(),
|
||||||
CreatedAt: project.CreatedAt,
|
CreatedAt: project.CreatedAt,
|
||||||
UpdatedAt: project.UpdatedAt,
|
UpdatedAt: project.UpdatedAt,
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
CustomerID: project.CustomerID.String(),
|
CustomerID: &customerId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertCreateProjectDTOToModel(dto dto.ProjectCreateDto) (models.ProjectCreate, error) {
|
func convertCreateProjectDTOToModel(dto dto.ProjectCreateDto) (models.ProjectCreate, error) {
|
||||||
|
create := models.ProjectCreate{Name: dto.Name}
|
||||||
// Convert CustomerID from int to ULID (this is a simplification, adjust as needed)
|
// Convert CustomerID from int to ULID (this is a simplification, adjust as needed)
|
||||||
customerID, err := types.ULIDFromString(dto.CustomerID)
|
if dto.CustomerID != nil {
|
||||||
if err != nil {
|
|
||||||
return models.ProjectCreate{}, fmt.Errorf("invalid customer ID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return models.ProjectCreate{
|
customerID, err := types.ULIDFromString(*dto.CustomerID)
|
||||||
Name: dto.Name,
|
if err != nil {
|
||||||
CustomerID: customerID,
|
return models.ProjectCreate{}, fmt.Errorf("invalid customer ID: %w", err)
|
||||||
}, nil
|
}
|
||||||
|
create.CustomerID = &customerID
|
||||||
|
}
|
||||||
|
return create, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertUpdateProjectDTOToModel(dto dto.ProjectUpdateDto) (models.ProjectUpdate, error) {
|
func convertUpdateProjectDTOToModel(dto dto.ProjectUpdateDto, id types.ULID) (models.ProjectUpdate, error) {
|
||||||
id, err := ulid.Parse(dto.ID)
|
|
||||||
if err != nil {
|
|
||||||
return models.ProjectUpdate{}, fmt.Errorf("invalid project ID: %w", err)
|
|
||||||
}
|
|
||||||
update := models.ProjectUpdate{
|
update := models.ProjectUpdate{
|
||||||
ID: types.FromULID(id),
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.Name != nil {
|
if dto.Name != nil {
|
||||||
update.Name = dto.Name
|
update.Name = dto.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.CustomerID != nil {
|
if dto.CustomerID.Valid {
|
||||||
// Convert CustomerID from int to ULID (this is a simplification, adjust as needed)
|
if dto.CustomerID.Value == nil {
|
||||||
customerID, err := types.ULIDFromString(*dto.CustomerID)
|
update.CustomerID = nil
|
||||||
if err != nil {
|
|
||||||
return models.ProjectUpdate{}, fmt.Errorf("invalid customer ID: %w", err)
|
} else {
|
||||||
|
// Convert CustomerID from int to ULID (this is a simplification, adjust as needed)
|
||||||
|
customerID, err := types.ULIDFromString(*dto.CustomerID.Value)
|
||||||
|
if err != nil {
|
||||||
|
return models.ProjectUpdate{}, fmt.Errorf("invalid customer ID: %w", err)
|
||||||
|
}
|
||||||
|
update.CustomerID = &customerID
|
||||||
}
|
}
|
||||||
update.CustomerID = &customerID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return update, nil
|
return update, nil
|
||||||
|
@ -326,7 +326,7 @@ func (h *TimeEntryHandler) CreateTimeEntry(c *gin.Context) {
|
|||||||
func (h *TimeEntryHandler) UpdateTimeEntry(c *gin.Context) {
|
func (h *TimeEntryHandler) UpdateTimeEntry(c *gin.Context) {
|
||||||
// Parse ID from URL
|
// Parse ID from URL
|
||||||
idStr := c.Param("id")
|
idStr := c.Param("id")
|
||||||
id, err := ulid.Parse(idStr)
|
id, err := types.ULIDFromString(idStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, "Invalid time entry ID format")
|
utils.BadRequestResponse(c, "Invalid time entry ID format")
|
||||||
return
|
return
|
||||||
@ -339,11 +339,8 @@ func (h *TimeEntryHandler) UpdateTimeEntry(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ID from URL
|
|
||||||
timeEntryUpdateDTO.ID = id.String()
|
|
||||||
|
|
||||||
// Convert DTO to model
|
// Convert DTO to model
|
||||||
timeEntryUpdate, err := convertUpdateTimeEntryDTOToModel(timeEntryUpdateDTO)
|
timeEntryUpdate, err := convertUpdateTimeEntryDTOToModel(timeEntryUpdateDTO, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, err.Error())
|
utils.BadRequestResponse(c, err.Error())
|
||||||
return
|
return
|
||||||
@ -445,13 +442,10 @@ func convertCreateTimeEntryDTOToModel(dto dto.TimeEntryCreateDto) (models.TimeEn
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertUpdateTimeEntryDTOToModel(dto dto.TimeEntryUpdateDto) (models.TimeEntryUpdate, error) {
|
func convertUpdateTimeEntryDTOToModel(dto dto.TimeEntryUpdateDto, id types.ULID) (models.TimeEntryUpdate, error) {
|
||||||
id, err := ulid.Parse(dto.ID)
|
|
||||||
if err != nil {
|
|
||||||
return models.TimeEntryUpdate{}, fmt.Errorf("invalid time entry ID: %w", err)
|
|
||||||
}
|
|
||||||
update := models.TimeEntryUpdate{
|
update := models.TimeEntryUpdate{
|
||||||
ID: types.FromULID(id),
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if dto.UserID != nil {
|
if dto.UserID != nil {
|
||||||
|
@ -148,7 +148,7 @@ func (h *UserHandler) CreateUser(c *gin.Context) {
|
|||||||
func (h *UserHandler) UpdateUser(c *gin.Context) {
|
func (h *UserHandler) UpdateUser(c *gin.Context) {
|
||||||
// Parse ID from URL
|
// Parse ID from URL
|
||||||
idStr := c.Param("id")
|
idStr := c.Param("id")
|
||||||
id, err := ulid.Parse(idStr)
|
id, err := types.ULIDFromString(idStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, "Invalid user ID format")
|
utils.BadRequestResponse(c, "Invalid user ID format")
|
||||||
return
|
return
|
||||||
@ -161,13 +161,9 @@ func (h *UserHandler) UpdateUser(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ID from URL
|
|
||||||
userUpdateDTO.ID = id.String()
|
|
||||||
|
|
||||||
// Convert DTO to Model
|
// Convert DTO to Model
|
||||||
idWrapper := types.FromULID(id)
|
|
||||||
update := models.UserUpdate{
|
update := models.UserUpdate{
|
||||||
ID: idWrapper,
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateDTO.Email != nil {
|
if userUpdateDTO.Email != nil {
|
||||||
@ -179,22 +175,23 @@ func (h *UserHandler) UpdateUser(c *gin.Context) {
|
|||||||
if userUpdateDTO.Role != nil {
|
if userUpdateDTO.Role != nil {
|
||||||
update.Role = userUpdateDTO.Role
|
update.Role = userUpdateDTO.Role
|
||||||
}
|
}
|
||||||
if userUpdateDTO.CompanyID != nil {
|
|
||||||
if userUpdateDTO.CompanyID.Valid {
|
if userUpdateDTO.CompanyID.Valid {
|
||||||
|
if userUpdateDTO.CompanyID.Value != nil {
|
||||||
companyID, err := types.ULIDFromString(*userUpdateDTO.CompanyID.Value)
|
companyID, err := types.ULIDFromString(*userUpdateDTO.CompanyID.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.BadRequestResponse(c, "Invalid company ID format")
|
utils.BadRequestResponse(c, "Invalid company ID format")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
update.CompanyID = &companyID
|
update.CompanyID = types.NewNullable(companyID)
|
||||||
} else {
|
} else {
|
||||||
update.CompanyID = nil
|
update.CompanyID = types.Null[types.ULID]()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if userUpdateDTO.HourlyRate != nil {
|
if userUpdateDTO.HourlyRate != nil {
|
||||||
update.HourlyRate = userUpdateDTO.HourlyRate
|
update.HourlyRate = userUpdateDTO.HourlyRate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update user in the database
|
// Update user in the database
|
||||||
user, err := models.UpdateUser(c.Request.Context(), update)
|
user, err := models.UpdateUser(c.Request.Context(), update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,9 +17,7 @@ type CompanyCreateDto struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CompanyUpdateDto struct {
|
type CompanyUpdateDto struct {
|
||||||
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
||||||
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
Name *string `json:"name" example:"Acme Corp"`
|
||||||
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
|
||||||
Name *string `json:"name" example:"Acme Corp"`
|
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ type CustomerCreateDto struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CustomerUpdateDto struct {
|
type CustomerUpdateDto struct {
|
||||||
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
||||||
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
||||||
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
||||||
Name *string `json:"name" example:"John Doe"`
|
Name *string `json:"name" example:"John Doe"`
|
||||||
CompanyID *types.Nullable[string] `json:"companyId" example:"01HGW2BBG0000000000000000"`
|
CompanyID types.Nullable[string] `json:"companyId" example:"01HGW2BBG0000000000000000"`
|
||||||
OwnerUserID *types.Nullable[string] `json:"owningUserID" example:"01HGW2BBG0000000000000000"`
|
OwnerUserID types.Nullable[string] `json:"owningUserID" example:"01HGW2BBG0000000000000000"`
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package dto
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/timetracker/backend/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectDto struct {
|
type ProjectDto struct {
|
||||||
@ -10,19 +12,17 @@ type ProjectDto struct {
|
|||||||
UpdatedAt time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
LastEditorID string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
LastEditorID string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
||||||
Name string `json:"name" example:"Time Tracking App"`
|
Name string `json:"name" example:"Time Tracking App"`
|
||||||
CustomerID string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
CustomerID *string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectCreateDto struct {
|
type ProjectCreateDto struct {
|
||||||
Name string `json:"name" example:"Time Tracking App"`
|
Name string `json:"name" example:"Time Tracking App"`
|
||||||
CustomerID string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
CustomerID *string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectUpdateDto struct {
|
type ProjectUpdateDto struct {
|
||||||
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
||||||
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
Name *string `json:"name" example:"Time Tracking App"`
|
||||||
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
CustomerID types.Nullable[string] `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
||||||
Name *string `json:"name" example:"Time Tracking App"`
|
|
||||||
CustomerID *string `json:"customerId" example:"01HGW2BBG0000000000000000"`
|
|
||||||
}
|
}
|
||||||
|
@ -29,15 +29,13 @@ type TimeEntryCreateDto struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TimeEntryUpdateDto struct {
|
type TimeEntryUpdateDto struct {
|
||||||
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
||||||
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
UserID *string `json:"userId" example:"01HGW2BBG0000000000000000"`
|
||||||
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
ProjectID *string `json:"projectId" example:"01HGW2BBG0000000000000000"`
|
||||||
UserID *string `json:"userId" example:"01HGW2BBG0000000000000000"`
|
ActivityID *string `json:"activityId" example:"01HGW2BBG0000000000000000"`
|
||||||
ProjectID *string `json:"projectId" example:"01HGW2BBG0000000000000000"`
|
Start *time.Time `json:"start" example:"2024-01-01T08:00:00Z"`
|
||||||
ActivityID *string `json:"activityId" example:"01HGW2BBG0000000000000000"`
|
End *time.Time `json:"end" example:"2024-01-01T17:00:00Z"`
|
||||||
Start *time.Time `json:"start" example:"2024-01-01T08:00:00Z"`
|
Description *string `json:"description" example:"Working on the Time Tracking App"`
|
||||||
End *time.Time `json:"end" example:"2024-01-01T17:00:00Z"`
|
Billable *int `json:"billable" example:"100"` // Percentage (0-100)
|
||||||
Description *string `json:"description" example:"Working on the Time Tracking App"`
|
|
||||||
Billable *int `json:"billable" example:"100"` // Percentage (0-100)
|
|
||||||
}
|
}
|
||||||
|
@ -26,13 +26,12 @@ type UserCreateDto struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserUpdateDto struct {
|
type UserUpdateDto struct {
|
||||||
ID string `json:"id" example:"01HGW2BBG0000000000000000"`
|
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
||||||
CreatedAt *time.Time `json:"createdAt" example:"2024-01-01T00:00:00Z"`
|
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
||||||
UpdatedAt *time.Time `json:"updatedAt" example:"2024-01-01T00:00:00Z"`
|
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
||||||
LastEditorID *string `json:"lastEditorID" example:"01HGW2BBG0000000000000000"`
|
Email *string `json:"email" example:"test@example.com"`
|
||||||
Email *string `json:"email" example:"test@example.com"`
|
Password *string `json:"password" example:"password123"`
|
||||||
Password *string `json:"password" example:"password123"`
|
Role *string `json:"role" example:"admin"`
|
||||||
Role *string `json:"role" example:"admin"`
|
CompanyID types.Nullable[string] `json:"companyId" example:"01HGW2BBG0000000000000000"`
|
||||||
CompanyID *types.Nullable[string] `json:"companyId" example:"01HGW2BBG0000000000000000"`
|
HourlyRate *float64 `json:"hourlyRate" example:"50.00"`
|
||||||
HourlyRate *float64 `json:"hourlyRate" example:"50.00"`
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -24,7 +23,6 @@ func (eb *EntityBase) BeforeCreate(tx *gorm.DB) error {
|
|||||||
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
|
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
|
||||||
newID := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
|
newID := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
|
||||||
eb.ID = types.ULID{ULID: newID}
|
eb.ID = types.ULID{ULID: newID}
|
||||||
fmt.Println("Generated ID:", eb.ID)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ import (
|
|||||||
// Project represents a project in the system
|
// Project represents a project in the system
|
||||||
type Project struct {
|
type Project struct {
|
||||||
EntityBase
|
EntityBase
|
||||||
Name string `gorm:"column:name;not null"`
|
Name string `gorm:"column:name;not null"`
|
||||||
CustomerID types.ULID `gorm:"column:customer_id;type:bytea;not null"`
|
CustomerID *types.ULID `gorm:"column:customer_id;type:bytea;not null"`
|
||||||
|
|
||||||
// Relationships (for Eager Loading)
|
// Relationships (for Eager Loading)
|
||||||
Customer *Customer `gorm:"foreignKey:CustomerID"`
|
Customer *Customer `gorm:"foreignKey:CustomerID"`
|
||||||
@ -28,7 +28,7 @@ func (Project) TableName() string {
|
|||||||
// ProjectCreate contains the fields for creating a new project
|
// ProjectCreate contains the fields for creating a new project
|
||||||
type ProjectCreate struct {
|
type ProjectCreate struct {
|
||||||
Name string
|
Name string
|
||||||
CustomerID types.ULID
|
CustomerID *types.ULID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProjectUpdate contains the updatable fields of a project
|
// ProjectUpdate contains the updatable fields of a project
|
||||||
@ -122,12 +122,14 @@ func CreateProject(ctx context.Context, create ProjectCreate) (*Project, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the customer exists
|
// Check if the customer exists
|
||||||
customer, err := GetCustomerByID(ctx, create.CustomerID)
|
if create.CustomerID == nil {
|
||||||
if err != nil {
|
customer, err := GetCustomerByID(ctx, *create.CustomerID)
|
||||||
return nil, fmt.Errorf("error checking the customer: %w", err)
|
if err != nil {
|
||||||
}
|
return nil, fmt.Errorf("error checking the customer: %w", err)
|
||||||
if customer == nil {
|
}
|
||||||
return nil, errors.New("the specified customer does not exist")
|
if customer == nil {
|
||||||
|
return nil, errors.New("the specified customer does not exist")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
project := Project{
|
project := Project{
|
||||||
|
@ -63,12 +63,12 @@ type UserCreate struct {
|
|||||||
|
|
||||||
// UserUpdate contains the updatable fields of a user
|
// UserUpdate contains the updatable fields of a user
|
||||||
type UserUpdate struct {
|
type UserUpdate struct {
|
||||||
ID types.ULID `gorm:"-"` // Exclude from updates
|
ID types.ULID `gorm:"-"` // Exclude from updates
|
||||||
Email *string `gorm:"column:email"`
|
Email *string `gorm:"column:email"`
|
||||||
Password *string `gorm:"-"` // Not stored directly in DB
|
Password *string `gorm:"-"` // Not stored directly in DB
|
||||||
Role *string `gorm:"column:role"`
|
Role *string `gorm:"column:role"`
|
||||||
CompanyID *types.ULID `gorm:"column:company_id"`
|
CompanyID types.Nullable[types.ULID] `gorm:"column:company_id"`
|
||||||
HourlyRate *float64 `gorm:"column:hourly_rate"`
|
HourlyRate *float64 `gorm:"column:hourly_rate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordData contains the data for password hash and salt
|
// PasswordData contains the data for password hash and salt
|
||||||
@ -448,13 +448,15 @@ func UpdateUser(ctx context.Context, update UserUpdate) (*User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If CompanyID is updated, check if it exists
|
// If CompanyID is updated, check if it exists
|
||||||
if update.CompanyID != nil && (user.CompanyID == nil || update.CompanyID.Compare(*user.CompanyID) != 0) {
|
if update.CompanyID.Valid && update.CompanyID.Value != nil {
|
||||||
var companyCount int64
|
if user.CompanyID == nil || *update.CompanyID.Value != *user.CompanyID {
|
||||||
if err := tx.Model(&Company{}).Where("id = ?", *update.CompanyID).Count(&companyCount).Error; err != nil {
|
var companyCount int64
|
||||||
return fmt.Errorf("error checking company: %w", err)
|
if err := tx.Model(&Company{}).Where("id = ?", *update.CompanyID.Value).Count(&companyCount).Error; err != nil {
|
||||||
}
|
return fmt.Errorf("error checking company: %w", err)
|
||||||
if companyCount == 0 {
|
}
|
||||||
return errors.New("the specified company does not exist")
|
if companyCount == 0 {
|
||||||
|
return errors.New("the specified company does not exist")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,8 +486,13 @@ func UpdateUser(ctx context.Context, update UserUpdate) (*User, error) {
|
|||||||
if update.Role != nil {
|
if update.Role != nil {
|
||||||
updates["role"] = *update.Role
|
updates["role"] = *update.Role
|
||||||
}
|
}
|
||||||
if update.CompanyID != nil {
|
if update.CompanyID.Valid {
|
||||||
updates["company_id"] = *update.CompanyID
|
if update.CompanyID.Value == nil {
|
||||||
|
updates["company_id"] = nil
|
||||||
|
} else {
|
||||||
|
updates["company_id"] = *update.CompanyID.Value
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if update.HourlyRate != nil {
|
if update.HourlyRate != nil {
|
||||||
updates["hourly_rate"] = *update.HourlyRate
|
updates["hourly_rate"] = *update.HourlyRate
|
||||||
|
@ -18,6 +18,10 @@ func NewNullable[T any](value T) Nullable[T] {
|
|||||||
|
|
||||||
// Null erstellt eine leere Nullable-Instanz (ungesetzt)
|
// Null erstellt eine leere Nullable-Instanz (ungesetzt)
|
||||||
func Null[T any]() Nullable[T] {
|
func Null[T any]() Nullable[T] {
|
||||||
|
return Nullable[T]{Valid: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Undefined[T any]() Nullable[T] {
|
||||||
return Nullable[T]{Valid: false}
|
return Nullable[T]{Valid: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user