Untitled

 avatar
unknown
plain_text
5 months ago
7.2 kB
4
Indexable
database.go:
package config

import (
	"log"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var DB *gorm.DB

func ConnectDatabase() {
	dsn := "user:Password@1@tcp(127.0.0.1:3306)/choice_db?charset=utf8mb4&parseTime=True&loc=Local"
	database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("Failed to connect to database!", err)
	}

	DB = database
	log.Println("Database connected successfully!")
}


redis.go:
package config

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/go-redis/redis/v8"
)

var (
	RDB *redis.Client
	Ctx = context.Background()
)

// ConnectRedis initializes the Redis client connection
func ConnectRedis() {
	RDB = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "",
		DB:       0,
	})

	_, err := RDB.Ping(Ctx).Result()
	if err != nil {
		log.Fatal("Failed to connect to Redis!", err)
	}
	log.Println("Redis connected successfully!")
}

// ToDo: Test: SetKeyWithTTL sets a Redis key with a 5-minute TTL
func SetKeyWithTTL(key, value string) error {
	err := RDB.Set(Ctx, key, value, 5*time.Minute).Err()
	if err != nil {
		return fmt.Errorf("failed to set key with TTL: %v", err)
	}
	log.Printf("Key '%s' set with a TTL of 5 minutes\n", key)
	return nil
}

// ToDo: Test: CheckTTL retrieves the TTL of a key in Redis
func CheckTTL(key string) error {
	ttl, err := RDB.TTL(Ctx, key).Result()
	if err != nil {
		return fmt.Errorf("failed to retrieve TTL: %v", err)
	}
	log.Printf("Key '%s' TTL: %v\n", key, ttl)
	return nil
}


employees.go:
package models

import (
	"time"
)

type Employee struct {
	ID         uint   `gorm:"primaryKey"`
	Name       string `gorm:"type:varchar(255)"`
	Age        int
	Position   string  `gorm:"type:varchar(255)"`
	Department string  `gorm:"type:varchar(255)"`
	Salary     float64 `gorm:"type:decimal(10,2)"`
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

routes.go:
package routes

package routes

import (
	"golang-assignment/config"
	"golang-assignment/services"

	"github.com/gin-gonic/gin"
)

func SetupRoutes(r *gin.Engine) {
	r.POST("/upload", services.UploadExcel)
	r.GET("/employees", services.GetEmployees)
	r.PUT("/employee/:id", services.UpdateEmployee)
	r.DELETE("/employee/:id", services.DeleteEmployee)

	//ToDo : Verify this
	r.GET("/set-key", func(c *gin.Context) {
		key := "imported_data"
		value := "test data"
		if err := config.SetKeyWithTTL(key, value); err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "Key set in Redis with TTL"})
	})

	//ToDo : Verify this
	r.GET("/check-ttl", func(c *gin.Context) {
		key := "imported_data"
		if err := config.CheckTTL(key); err != nil {
			c.JSON(500, gin.H{"error": err.Error()})
			return
		}
		c.JSON(200, gin.H{"message": "TTL checked in logs"})
	})
}


delete.go:
package services

import (
	"golang-assignment/config"
	"golang-assignment/models"
	"net/http"

	"github.com/gin-gonic/gin"
)

// DeleteEmployee deletes a specific employee record
func DeleteEmployee(c *gin.Context) {
	id := c.Param("id")
	var employee models.Employee

	if err := config.DB.First(&employee, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Employee not found"})
		return
	}

	config.DB.Delete(&employee)
	c.JSON(http.StatusOK, gin.H{"message": "Employee deleted successfully"})
}

get.go:
package services

import (
	"encoding/json"
	"golang-assignment/config"
	"golang-assignment/models"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

// GetEmployees retrieves employees data
func GetEmployees(c *gin.Context) {
	var employees []models.Employee

	cachedData, err := config.RDB.Get(config.Ctx, "employees_cache").Result()
	if err == nil {
		// If cache hit, return cached data
		var cachedEmployees []models.Employee
		json.Unmarshal([]byte(cachedData), &cachedEmployees)
		c.JSON(http.StatusOK, cachedEmployees)
		return
	}

	// Fallback to MySQL if Redis has no data
	config.DB.Find(&employees)

	// Cache the fetched data in Redis for 5 minutes
	jsonData, _ := json.Marshal(employees)
	config.RDB.Set(config.Ctx, "employees_cache", jsonData, 5*time.Minute)

	c.JSON(http.StatusOK, employees)
}



update.go:
package services

import (
	"golang-assignment/config"
	"golang-assignment/models"
	"net/http"

	"github.com/gin-gonic/gin"
)

// UpdateEmployee updates a specific employee record
func UpdateEmployee(c *gin.Context) {
	id := c.Param("id")
	var employee models.Employee

	if err := config.DB.First(&employee, id).Error; err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "Employee not found"})
		return
	}

	if err := c.ShouldBindJSON(&employee); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid input"})
		return
	}

	config.DB.Save(&employee)
	c.JSON(http.StatusOK, gin.H{"message": "Employee updated successfully"})
}


upload.go:
package services

import (
	"encoding/json"
	"golang-assignment/config"
	"golang-assignment/models"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
)

// UploadExcel handles the upload and parsing of Excel data
func UploadExcel(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "File upload failed"})
		return
	}

	filePath := "./" + file.Filename
	if err := c.SaveUploadedFile(file, filePath); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
		return
	}

	f, err := excelize.OpenFile(filePath)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid Excel file"})
		return
	}
	defer f.Close()

	var employees []models.Employee
	rows, err := f.GetRows("uk-500")
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read rows"})
		return
	}

	for _, row := range rows[1:] {
		if len(row) < 5 {
			continue
		}
		employee := models.Employee{
			Name:       row[0],
			Age:        parseAge(row[1]),
			Position:   row[2],
			Department: row[3],
			Salary:     parseSalary(row[4]),
		}
		employees = append(employees, employee)
	}

	// Insert data into MySQL
	if err := config.DB.Create(&employees).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error":   "Failed to insert data into database",
			"details": err.Error(),
		})
		return
	}

	// Cache data in Redis
	jsonData, _ := json.Marshal(employees)
	config.RDB.Set(config.Ctx, "employees_cache", jsonData, 5*time.Minute)

	c.JSON(http.StatusOK, gin.H{"message": "File uploaded and data imported successfully"})
}

// Helper function to parse age as an integer, returns 0 if conversion fails
func parseAge(ageStr string) int {
	age, err := strconv.Atoi(ageStr)
	if err != nil {
		return 0
	}
	return age
}

func parseSalary(salaryStr string) float64 {
	salary, err := strconv.ParseFloat(salaryStr, 64)
	if err != nil {
		return 0.0
	}
	return salary
}

main.go:
package main

import (
	"golang-assignment/config"
	"golang-assignment/routes"
	"log"

	"github.com/gin-gonic/gin"
)

func main() {
	config.ConnectDatabase()
	config.ConnectRedis()

	r := gin.Default()
	routes.SetupRoutes(r)

	if err := r.Run(":8081"); err != nil {
		log.Fatal("Failed to start server:", err)
	}
}
Editor is loading...
Leave a Comment