feat: add component_codes management functionality

This commit is contained in:
Tran Anh Tuan
2026-05-11 11:00:46 +07:00
parent bf20286f04
commit 9ea72b4eea
14 changed files with 1562 additions and 0 deletions

View File

@@ -18,6 +18,7 @@ const (
API_GROUP_CONTAINER = "/containers"
API_GROUP_COMPONENT_TYPE = "/component-types"
API_GROUP_COMPONENT = "/components"
API_GROUP_COMPONENT_CODE = "/component-codes"
)
const (

View File

@@ -0,0 +1,33 @@
-- name: GetComponentCodeByID :one
SELECT * FROM component_codes
WHERE id = sqlc.arg(id);
-- name: ListComponentCodes :many
SELECT * FROM component_codes
ORDER BY created_at DESC;
-- name: CreateComponentCode :one
INSERT INTO component_codes (component_id,code, code_type, is_primary,metadata, created_at)
VALUES (
sqlc.arg(component_id),
sqlc.arg(code),
sqlc.arg(code_type),
sqlc.arg(is_primary),
sqlc.arg(metadata),
sqlc.arg(created_at)
)
RETURNING *;
-- name: UpdateComponentCode :one
UPDATE component_codes
SET code = CASE WHEN sqlc.arg(code) = '' THEN code ELSE sqlc.arg(code) END,
component_id = coalesce(sqlc.arg(component_id), component_id),
code_type = coalesce(sqlc.arg(code_type), code_type),
is_primary = coalesce(sqlc.arg(is_primary), is_primary),
metadata = coalesce(sqlc.arg(metadata), metadata)
WHERE id = sqlc.arg(id)
RETURNING *;
-- name: DeleteComponentCode :execrows
DELETE FROM component_codes
WHERE id = sqlc.arg(id);

View File

@@ -15,6 +15,279 @@ const docTemplate = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/api/v1/component-codes": {
"get": {
"description": "Retrieve a list of all component codes ordered by creation date",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "List all component codes",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.ComponentCode"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"post": {
"description": "Create a new component code with the provided details",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Create a new component code",
"parameters": [
{
"description": "Component code request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.CreateComponentCodeRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.CreateComponentCodeResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/api/v1/component-codes/{id}": {
"get": {
"description": "Retrieve a single component code using its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Get component code by ID",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.ComponentCode"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"put": {
"description": "Update an existing component code by its ID. Only non-empty fields will be updated.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Update component code",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Component code request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.UpdateComponentCodeRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.UpdateComponentCodeResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"delete": {
"description": "Delete a component code by its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Delete component code",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.SuccessResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/api/v1/component-types": {
"get": {
"description": "Retrieve a list of all component types ordered by creation date",
@@ -2073,6 +2346,35 @@ const docTemplate = `{
}
}
},
"models.ComponentCode": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"createdAt": {
"type": "string"
},
"id": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"models.ComponentType": {
"type": "object",
"properties": {
@@ -2247,6 +2549,33 @@ const docTemplate = `{
}
}
},
"requests.CreateComponentCodeRequest": {
"type": "object",
"required": [
"code",
"componentId"
],
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"requests.CreateComponentRequest": {
"type": "object",
"required": [
@@ -2399,6 +2728,29 @@ const docTemplate = `{
}
}
},
"requests.UpdateComponentCodeRequest": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"requests.UpdateComponentRequest": {
"type": "object",
"properties": {
@@ -2553,6 +2905,14 @@ const docTemplate = `{
}
}
},
"responses.CreateComponentCodeResponse": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"responses.CreateComponentResponse": {
"type": "object",
"properties": {
@@ -2618,6 +2978,26 @@ const docTemplate = `{
}
}
},
"responses.UpdateComponentCodeResponse": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
}
}
},
"responses.UpdateComponentResponse": {
"type": "object",
"properties": {

View File

@@ -9,6 +9,279 @@
"host": "localhost:3000",
"basePath": "/api/v1",
"paths": {
"/api/v1/component-codes": {
"get": {
"description": "Retrieve a list of all component codes ordered by creation date",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "List all component codes",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/models.ComponentCode"
}
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"post": {
"description": "Create a new component code with the provided details",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Create a new component code",
"parameters": [
{
"description": "Component code request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.CreateComponentCodeRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.CreateComponentCodeResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/api/v1/component-codes/{id}": {
"get": {
"description": "Retrieve a single component code using its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Get component code by ID",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/models.ComponentCode"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"put": {
"description": "Update an existing component code by its ID. Only non-empty fields will be updated.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Update component code",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Component code request body",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.UpdateComponentCodeRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.UpdateComponentCodeResponse"
}
}
}
]
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
},
"delete": {
"description": "Delete a component code by its unique identifier",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"component-code"
],
"summary": "Delete component code",
"parameters": [
{
"type": "integer",
"description": "Component code ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.SuccessResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.ErrorResponse"
}
}
}
}
},
"/api/v1/component-types": {
"get": {
"description": "Retrieve a list of all component types ordered by creation date",
@@ -2067,6 +2340,35 @@
}
}
},
"models.ComponentCode": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"createdAt": {
"type": "string"
},
"id": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"models.ComponentType": {
"type": "object",
"properties": {
@@ -2241,6 +2543,33 @@
}
}
},
"requests.CreateComponentCodeRequest": {
"type": "object",
"required": [
"code",
"componentId"
],
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"requests.CreateComponentRequest": {
"type": "object",
"required": [
@@ -2393,6 +2722,29 @@
}
}
},
"requests.UpdateComponentCodeRequest": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
},
"metadata": {
"type": "array",
"items": {
"type": "integer"
}
}
}
},
"requests.UpdateComponentRequest": {
"type": "object",
"properties": {
@@ -2547,6 +2899,14 @@
}
}
},
"responses.CreateComponentCodeResponse": {
"type": "object",
"properties": {
"id": {
"type": "integer"
}
}
},
"responses.CreateComponentResponse": {
"type": "object",
"properties": {
@@ -2612,6 +2972,26 @@
}
}
},
"responses.UpdateComponentCodeResponse": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"codeType": {
"type": "string"
},
"componentId": {
"type": "integer"
},
"id": {
"type": "integer"
},
"isPrimary": {
"type": "boolean"
}
}
},
"responses.UpdateComponentResponse": {
"type": "object",
"properties": {

View File

@@ -40,6 +40,25 @@ definitions:
updatedAt:
type: string
type: object
models.ComponentCode:
properties:
code:
type: string
codeType:
type: string
componentId:
type: integer
createdAt:
type: string
id:
type: integer
isPrimary:
type: boolean
metadata:
items:
type: integer
type: array
type: object
models.ComponentType:
properties:
createdAt:
@@ -155,6 +174,24 @@ definitions:
- name
- roomId
type: object
requests.CreateComponentCodeRequest:
properties:
code:
type: string
codeType:
type: string
componentId:
type: integer
isPrimary:
type: boolean
metadata:
items:
type: integer
type: array
required:
- code
- componentId
type: object
requests.CreateComponentRequest:
properties:
componentTypeId:
@@ -257,6 +294,21 @@ definitions:
name:
type: string
type: object
requests.UpdateComponentCodeRequest:
properties:
code:
type: string
codeType:
type: string
componentId:
type: integer
isPrimary:
type: boolean
metadata:
items:
type: integer
type: array
type: object
requests.UpdateComponentRequest:
properties:
componentTypeId:
@@ -357,6 +409,11 @@ definitions:
id:
type: integer
type: object
responses.CreateComponentCodeResponse:
properties:
id:
type: integer
type: object
responses.CreateComponentResponse:
properties:
id:
@@ -398,6 +455,19 @@ definitions:
roomId:
type: integer
type: object
responses.UpdateComponentCodeResponse:
properties:
code:
type: string
codeType:
type: string
componentId:
type: integer
id:
type: integer
isPrimary:
type: boolean
type: object
responses.UpdateComponentResponse:
properties:
componentTypeId:
@@ -483,6 +553,176 @@ info:
title: Warehouse Management API
version: "1.0"
paths:
/api/v1/component-codes:
get:
consumes:
- application/json
description: Retrieve a list of all component codes ordered by creation date
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
items:
$ref: '#/definitions/models.ComponentCode'
type: array
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: List all component codes
tags:
- component-code
post:
consumes:
- application/json
description: Create a new component code with the provided details
parameters:
- description: Component code request body
in: body
name: body
required: true
schema:
$ref: '#/definitions/requests.CreateComponentCodeRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.CreateComponentCodeResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Create a new component code
tags:
- component-code
/api/v1/component-codes/{id}:
delete:
consumes:
- application/json
description: Delete a component code by its unique identifier
parameters:
- description: Component code ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.SuccessResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Delete component code
tags:
- component-code
get:
consumes:
- application/json
description: Retrieve a single component code using its unique identifier
parameters:
- description: Component code ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/models.ComponentCode'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Get component code by ID
tags:
- component-code
put:
consumes:
- application/json
description: Update an existing component code by its ID. Only non-empty fields
will be updated.
parameters:
- description: Component code ID
in: path
name: id
required: true
type: integer
- description: Component code request body
in: body
name: body
required: true
schema:
$ref: '#/definitions/requests.UpdateComponentCodeRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.UpdateComponentCodeResponse'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/response.ErrorResponse'
"404":
description: Not Found
schema:
$ref: '#/definitions/response.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.ErrorResponse'
summary: Update component code
tags:
- component-code
/api/v1/component-types:
get:
consumes:

View File

@@ -0,0 +1,54 @@
package mapper
import (
"wm-backend/internal/models"
db "wm-backend/sqlc_gen"
"encoding/json"
"github.com/jackc/pgx/v5/pgtype"
)
func ToDomainComponentCode(r db.ComponentCode) *models.ComponentCode {
return &models.ComponentCode{
ID: r.ID,
ComponentID: r.ComponentID,
Code: r.Code,
CodeType: r.CodeType.String,
IsPrimary: r.IsPrimary,
Metadata: json.RawMessage(r.Metadata),
CreatedAt: r.CreatedAt,
}
}
func ToModelComponentCode(r *models.ComponentCode) *db.CreateComponentCodeParams {
return &db.CreateComponentCodeParams{
ComponentID: r.ComponentID,
Code: r.Code,
CodeType: pgtype.Text{
String: r.CodeType,
Valid: r.CodeType != "",
},
IsPrimary: r.IsPrimary,
Metadata: []byte(r.Metadata),
CreatedAt: r.CreatedAt,
}
}
func ToUpdateModelComponentCode(r *models.ComponentCode) *db.UpdateComponentCodeParams {
var metadata []byte
if len(r.Metadata) > 0 {
metadata = []byte(r.Metadata)
}
return &db.UpdateComponentCodeParams{
Code: r.Code,
ComponentID: r.ComponentID,
CodeType: pgtype.Text{
String: r.CodeType,
Valid: r.CodeType != "",
},
IsPrimary: r.IsPrimary,
Metadata: metadata,
ID: r.ID,
}
}

View File

@@ -0,0 +1,16 @@
package models
import (
"encoding/json"
"time"
)
type ComponentCode struct {
ID int64 `json:"id"`
ComponentID int64 `json:"componentId"`
Code string `json:"code"`
CodeType string `json:"codeType"`
IsPrimary bool `json:"isPrimary"`
Metadata json.RawMessage `json:"metadata"`
CreatedAt time.Time `json:"createdAt"`
}

View File

@@ -0,0 +1,19 @@
package requests
import "encoding/json"
type CreateComponentCodeRequest struct {
ComponentID int64 `json:"componentId" binding:"required"`
Code string `json:"code" binding:"required"`
CodeType string `json:"codeType"`
IsPrimary bool `json:"isPrimary"`
Metadata json.RawMessage `json:"metadata"`
}
type UpdateComponentCodeRequest struct {
ComponentID int64 `json:"componentId"`
Code string `json:"code"`
CodeType string `json:"codeType"`
IsPrimary *bool `json:"isPrimary"`
Metadata json.RawMessage `json:"metadata"`
}

View File

@@ -0,0 +1,13 @@
package responses
type CreateComponentCodeResponse struct {
ID int64 `json:"id"`
}
type UpdateComponentCodeResponse struct {
ID int64 `json:"id"`
ComponentID int64 `json:"componentId"`
Code string `json:"code"`
CodeType string `json:"codeType"`
IsPrimary bool `json:"isPrimary"`
}

View File

@@ -0,0 +1,52 @@
package repositories
import (
"context"
"wm-backend/internal/mapper"
"wm-backend/internal/models"
db "wm-backend/sqlc_gen"
)
func CreateComponentCode(ctx context.Context, queries *db.Queries, body models.ComponentCode) (models.ComponentCode, error) {
result, err := queries.CreateComponentCode(ctx, *mapper.ToModelComponentCode(&body))
if err != nil {
return models.ComponentCode{}, err
}
return *mapper.ToDomainComponentCode(result), nil
}
func GetComponentCodeByID(ctx context.Context, queries *db.Queries, id int64) (models.ComponentCode, error) {
result, err := queries.GetComponentCodeByID(ctx, id)
if err != nil {
return models.ComponentCode{}, err
}
return *mapper.ToDomainComponentCode(result), nil
}
func ListComponentCodes(ctx context.Context, queries *db.Queries) ([]models.ComponentCode, error) {
results, err := queries.ListComponentCodes(ctx)
if err != nil {
return nil, err
}
var items []models.ComponentCode
for _, r := range results {
items = append(items, *mapper.ToDomainComponentCode(r))
}
return items, nil
}
func UpdateComponentCode(ctx context.Context, queries *db.Queries, body models.ComponentCode) (models.ComponentCode, error) {
result, err := queries.UpdateComponentCode(ctx, *mapper.ToUpdateModelComponentCode(&body))
if err != nil {
return models.ComponentCode{}, err
}
return *mapper.ToDomainComponentCode(result), nil
}
func DeleteComponentCode(ctx context.Context, queries *db.Queries, id int64) (int64, error) {
rowsAffected, err := queries.DeleteComponentCode(ctx, id)
if err != nil {
return rowsAffected, err
}
return rowsAffected, nil
}

View File

@@ -91,6 +91,15 @@ func NewRouter() *gin.Engine {
component.PUT("/:id", utils.AsyncHandler(services.ComponentUpdate))
component.DELETE("/:id", utils.AsyncHandler(services.ComponentDelete))
}
componentCode := v1.Group(constants.API_GROUP_COMPONENT_CODE)
{
componentCode.GET("", utils.AsyncHandler(services.ComponentCodeList))
componentCode.GET("/:id", utils.AsyncHandler(services.ComponentCodeGetByID))
componentCode.POST("", utils.AsyncHandler(services.ComponentCodeCreate))
componentCode.PUT("/:id", utils.AsyncHandler(services.ComponentCodeUpdate))
componentCode.DELETE("/:id", utils.AsyncHandler(services.ComponentCodeDelete))
}
}
r.GET(constants.API_PATH_PING, services.PingHandler)

View File

@@ -0,0 +1,195 @@
package services
import (
"net/http"
"strconv"
"time"
"wm-backend/global"
"wm-backend/internal/models"
"wm-backend/internal/models/requests"
"wm-backend/internal/models/responses"
"wm-backend/internal/repositories"
"wm-backend/pkg/helper"
"wm-backend/response"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
)
// ComponentCodeCreate creates a new component code.
// It validates the request body and creates the component code in the database.
//
// @Summary Create a new component code
// @Description Create a new component code with the provided details
// @Tags component-code
// @Accept json
// @Produce json
// @Param body body requests.CreateComponentCodeRequest true "Component code request body"
// @Success 201 {object} response.SuccessResponse{data=responses.CreateComponentCodeResponse}
// @Failure 400 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /api/v1/component-codes [post]
func ComponentCodeCreate(c *gin.Context) error {
requestBody := requests.CreateComponentCodeRequest{}
if helper.IsShouldBindJSON(c, &requestBody) {
return nil
}
componentCodeModel := &models.ComponentCode{
ComponentID: requestBody.ComponentID,
Code: requestBody.Code,
CodeType: requestBody.CodeType,
IsPrimary: requestBody.IsPrimary,
Metadata: requestBody.Metadata,
CreatedAt: time.Now(),
}
componentCode, err := repositories.CreateComponentCode(c.Request.Context(), global.Queries, *componentCodeModel)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError, "Failed to create component code")
return nil
}
response.Created(c, "Component code created successfully", &responses.CreateComponentCodeResponse{
ID: componentCode.ID,
})
return nil
}
// ComponentCodeGetByID retrieves a single component code by its ID.
//
// @Summary Get component code by ID
// @Description Retrieve a single component code using its unique identifier
// @Tags component-code
// @Accept json
// @Produce json
// @Param id path int true "Component code ID"
// @Success 200 {object} response.SuccessResponse{data=models.ComponentCode}
// @Failure 400 {object} response.ErrorResponse
// @Failure 404 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /api/v1/component-codes/{id} [get]
func ComponentCodeGetByID(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
componentCode, err := repositories.GetComponentCodeByID(c.Request.Context(), global.Queries, id)
if err != nil {
response.NotFoundError(c, http.StatusNotFound, "Component code not found")
return nil
}
response.Ok(c, "Success", componentCode)
return nil
}
// ComponentCodeList retrieves all component codes.
//
// @Summary List all component codes
// @Description Retrieve a list of all component codes ordered by creation date
// @Tags component-code
// @Accept json
// @Produce json
// @Success 200 {object} response.SuccessResponse{data=[]models.ComponentCode}
// @Failure 500 {object} response.ErrorResponse
// @Router /api/v1/component-codes [get]
func ComponentCodeList(c *gin.Context) error {
componentCodes, err := repositories.ListComponentCodes(c.Request.Context(), global.Queries)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError, "Failed to list component codes")
return nil
}
response.Ok(c, "Success", componentCodes)
return nil
}
// ComponentCodeUpdate updates an existing component code by its ID.
// It validates the request body, fetches the existing record,
// merges non-empty fields from the request, and updates the component code in the database.
//
// @Summary Update component code
// @Description Update an existing component code by its ID. Only non-empty fields will be updated.
// @Tags component-code
// @Accept json
// @Produce json
// @Param id path int true "Component code ID"
// @Param body body requests.UpdateComponentCodeRequest true "Component code request body"
// @Success 200 {object} response.SuccessResponse{data=responses.UpdateComponentCodeResponse}
// @Failure 400 {object} response.ErrorResponse
// @Failure 404 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /api/v1/component-codes/{id} [put]
func ComponentCodeUpdate(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
requestBody := requests.UpdateComponentCodeRequest{}
if helper.IsShouldBindJSON(c, &requestBody) {
return nil
}
existing, err := repositories.GetComponentCodeByID(c.Request.Context(), global.Queries, id)
if err != nil {
response.NotFoundError(c, http.StatusNotFound, "Component code not found")
return nil
}
if requestBody.ComponentID != 0 {
existing.ComponentID = requestBody.ComponentID
}
if requestBody.Code != "" {
existing.Code = requestBody.Code
}
if requestBody.CodeType != "" {
existing.CodeType = requestBody.CodeType
}
if requestBody.IsPrimary != nil {
existing.IsPrimary = *requestBody.IsPrimary
}
if len(requestBody.Metadata) > 0 {
existing.Metadata = requestBody.Metadata
}
componentCode, err := repositories.UpdateComponentCode(c.Request.Context(), global.Queries, existing)
if err != nil {
response.InternalServerError(c, http.StatusInternalServerError, "Failed to update component code")
return nil
}
response.Ok(c, "Component code updated successfully", &responses.UpdateComponentCodeResponse{
ID: componentCode.ID,
ComponentID: componentCode.ComponentID,
Code: componentCode.Code,
CodeType: componentCode.CodeType,
IsPrimary: componentCode.IsPrimary,
})
return nil
}
// ComponentCodeDelete deletes a component code by its ID.
//
// @Summary Delete component code
// @Description Delete a component code by its unique identifier
// @Tags component-code
// @Accept json
// @Produce json
// @Param id path int true "Component code ID"
// @Success 200 {object} response.SuccessResponse
// @Failure 400 {object} response.ErrorResponse
// @Failure 500 {object} response.ErrorResponse
// @Router /api/v1/component-codes/{id} [delete]
func ComponentCodeDelete(c *gin.Context) error {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequestError(c, http.StatusBadRequest, "Invalid ID")
return nil
}
rowsAffected, err := repositories.DeleteComponentCode(c.Request.Context(), global.Queries, id)
if err != nil {
log.Error().Err(err).Msgf("Failed to delete component code with ID: %d", id)
response.InternalServerError(c, http.StatusInternalServerError, "Failed to delete component code")
return nil
}
if rowsAffected == 0 {
response.NotFoundError(c, http.StatusNotFound, "Component code not found")
return nil
}
response.Ok(c, "Delete Success", nil)
return nil
}

View File

@@ -0,0 +1,165 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: component_code.sql
package db
import (
"context"
"time"
"github.com/jackc/pgx/v5/pgtype"
)
const createComponentCode = `-- name: CreateComponentCode :one
INSERT INTO component_codes (component_id,code, code_type, is_primary,metadata, created_at)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6
)
RETURNING id, component_id, code, code_type, is_primary, metadata, created_at
`
type CreateComponentCodeParams struct {
ComponentID int64 `db:"component_id" json:"componentId"`
Code string `db:"code" json:"code"`
CodeType pgtype.Text `db:"code_type" json:"codeType"`
IsPrimary bool `db:"is_primary" json:"isPrimary"`
Metadata []byte `db:"metadata" json:"metadata"`
CreatedAt time.Time `db:"created_at" json:"createdAt"`
}
func (q *Queries) CreateComponentCode(ctx context.Context, arg CreateComponentCodeParams) (ComponentCode, error) {
row := q.db.QueryRow(ctx, createComponentCode,
arg.ComponentID,
arg.Code,
arg.CodeType,
arg.IsPrimary,
arg.Metadata,
arg.CreatedAt,
)
var i ComponentCode
err := row.Scan(
&i.ID,
&i.ComponentID,
&i.Code,
&i.CodeType,
&i.IsPrimary,
&i.Metadata,
&i.CreatedAt,
)
return i, err
}
const deleteComponentCode = `-- name: DeleteComponentCode :execrows
DELETE FROM component_codes
WHERE id = $1
`
func (q *Queries) DeleteComponentCode(ctx context.Context, id int64) (int64, error) {
result, err := q.db.Exec(ctx, deleteComponentCode, id)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const getComponentCodeByID = `-- name: GetComponentCodeByID :one
SELECT id, component_id, code, code_type, is_primary, metadata, created_at FROM component_codes
WHERE id = $1
`
func (q *Queries) GetComponentCodeByID(ctx context.Context, id int64) (ComponentCode, error) {
row := q.db.QueryRow(ctx, getComponentCodeByID, id)
var i ComponentCode
err := row.Scan(
&i.ID,
&i.ComponentID,
&i.Code,
&i.CodeType,
&i.IsPrimary,
&i.Metadata,
&i.CreatedAt,
)
return i, err
}
const listComponentCodes = `-- name: ListComponentCodes :many
SELECT id, component_id, code, code_type, is_primary, metadata, created_at FROM component_codes
ORDER BY created_at DESC
`
func (q *Queries) ListComponentCodes(ctx context.Context) ([]ComponentCode, error) {
rows, err := q.db.Query(ctx, listComponentCodes)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ComponentCode
for rows.Next() {
var i ComponentCode
if err := rows.Scan(
&i.ID,
&i.ComponentID,
&i.Code,
&i.CodeType,
&i.IsPrimary,
&i.Metadata,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const updateComponentCode = `-- name: UpdateComponentCode :one
UPDATE component_codes
SET code = CASE WHEN $1 = '' THEN code ELSE $1 END,
component_id = coalesce($2, component_id),
code_type = coalesce($3, code_type),
is_primary = coalesce($4, is_primary),
metadata = coalesce($5, metadata)
WHERE id = $6
RETURNING id, component_id, code, code_type, is_primary, metadata, created_at
`
type UpdateComponentCodeParams struct {
Code interface{} `db:"code" json:"code"`
ComponentID int64 `db:"component_id" json:"componentId"`
CodeType pgtype.Text `db:"code_type" json:"codeType"`
IsPrimary bool `db:"is_primary" json:"isPrimary"`
Metadata []byte `db:"metadata" json:"metadata"`
ID int64 `db:"id" json:"id"`
}
func (q *Queries) UpdateComponentCode(ctx context.Context, arg UpdateComponentCodeParams) (ComponentCode, error) {
row := q.db.QueryRow(ctx, updateComponentCode,
arg.Code,
arg.ComponentID,
arg.CodeType,
arg.IsPrimary,
arg.Metadata,
arg.ID,
)
var i ComponentCode
err := row.Scan(
&i.ID,
&i.ComponentID,
&i.Code,
&i.CodeType,
&i.IsPrimary,
&i.Metadata,
&i.CreatedAt,
)
return i, err
}

View File

@@ -15,6 +15,7 @@ type Querier interface {
CountUsersByRoleID(ctx context.Context, roleID uuid.UUID) (int64, error)
CreateCabinet(ctx context.Context, arg CreateCabinetParams) (Cabinet, error)
CreateComponent(ctx context.Context, arg CreateComponentParams) (Component, error)
CreateComponentCode(ctx context.Context, arg CreateComponentCodeParams) (ComponentCode, error)
CreateComponentType(ctx context.Context, arg CreateComponentTypeParams) (ComponentType, error)
CreateContainer(ctx context.Context, arg CreateContainerParams) (Container, error)
CreateRole(ctx context.Context, arg CreateRoleParams) (Role, error)
@@ -24,6 +25,7 @@ type Querier interface {
CreateWarehouse(ctx context.Context, arg CreateWarehouseParams) (Warehouse, error)
DeleteCabinet(ctx context.Context, id int64) (int64, error)
DeleteComponent(ctx context.Context, id int64) (int64, error)
DeleteComponentCode(ctx context.Context, id int64) (int64, error)
DeleteComponentType(ctx context.Context, id int64) (int64, error)
DeleteContainer(ctx context.Context, id int64) (int64, error)
DeleteRole(ctx context.Context, id uuid.UUID) (int64, error)
@@ -32,6 +34,7 @@ type Querier interface {
DeleteWarehouse(ctx context.Context, id int64) (int64, error)
GetCabinetByID(ctx context.Context, id int64) (Cabinet, error)
GetComponentByID(ctx context.Context, id int64) (Component, error)
GetComponentCodeByID(ctx context.Context, id int64) (ComponentCode, error)
GetComponentTypeByID(ctx context.Context, id int64) (ComponentType, error)
GetContainerByID(ctx context.Context, id int64) (Container, error)
GetRoleByID(ctx context.Context, id uuid.UUID) (Role, error)
@@ -45,6 +48,7 @@ type Querier interface {
GetUserRolesByUserID(ctx context.Context, userID uuid.UUID) ([]GetUserRolesByUserIDRow, error)
GetWarehouseByID(ctx context.Context, id int64) (Warehouse, error)
ListCabinets(ctx context.Context) ([]Cabinet, error)
ListComponentCodes(ctx context.Context) ([]ComponentCode, error)
ListComponentTypes(ctx context.Context) ([]ComponentType, error)
ListComponents(ctx context.Context) ([]Component, error)
ListContainers(ctx context.Context) ([]Container, error)
@@ -56,6 +60,7 @@ type Querier interface {
RemoveRoleFromUser(ctx context.Context, arg RemoveRoleFromUserParams) error
UpdateCabinet(ctx context.Context, arg UpdateCabinetParams) (Cabinet, error)
UpdateComponent(ctx context.Context, arg UpdateComponentParams) (Component, error)
UpdateComponentCode(ctx context.Context, arg UpdateComponentCodeParams) (ComponentCode, error)
UpdateComponentType(ctx context.Context, arg UpdateComponentTypeParams) (ComponentType, error)
UpdateContainer(ctx context.Context, arg UpdateContainerParams) (Container, error)
UpdateRole(ctx context.Context, arg UpdateRoleParams) (Role, error)