Skip to content
Merged
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
17 changes: 17 additions & 0 deletions Internal/adapters/repository/dynamicDBRepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package repository

type DynamicDBRepo struct {
DB *DBContainer
}

func NewDynamicDB(db *DBContainer) *DynamicDBRepo {
return &DynamicDBRepo{DB: db}
}

func (dr *DynamicDBRepo) CreateDynamicDB(query string) error {
_, err := dr.DB.Sqlx.Exec(query)
if err != nil {
return err
}
return nil
}
14 changes: 8 additions & 6 deletions Internal/api/Routes/routev1.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import (
)

type Deps struct {
User *handlers.UserHandler
Auth *handlers.AuthHandler
System *handlers.SystemHandler
Project *handlers.ProjectHandler
UserRepo *repository.UserRepository
Config *config.Config
User *handlers.UserHandler
Auth *handlers.AuthHandler
System *handlers.SystemHandler
Project *handlers.ProjectHandler
DynamicDB *handlers.DynamicDBHandler
UserRepo *repository.UserRepository
Config *config.Config
}

func SetupRouterV1(r *gin.Engine, deps Deps) {
Expand Down Expand Up @@ -57,6 +58,7 @@ func SetupRouterV1(r *gin.Engine, deps Deps) {
{
manage.POST("/invite/:projectid", deps.Project.InviteProjectHandler)
manage.DELETE("/remove/:projuserid", deps.Project.RemoveProjectUserHandler)
manage.POST("/create/table/:projectid", deps.DynamicDB.CreateDynamicDBHandler)
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions Internal/api/handlers/dynamicDBHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package handlers

import (
"strconv"

"github.com/Arjuna-Ragil/Localbase/Internal/core/services"
"github.com/gin-gonic/gin"
)

type DynamicDBHandler struct {
Serv *services.DynamicDBService
}

func NewDynamicDBHandler(serv *services.DynamicDBService) *DynamicDBHandler {
return &DynamicDBHandler{Serv: serv}
}

func (dh *DynamicDBHandler) CreateDynamicDBHandler(c *gin.Context) {
projectIDStr := c.Param("projectid")
projectID, err := strconv.Atoi(projectIDStr)
if err != nil {
c.JSON(400, gin.H{
"message": "Project ID not valid",
"error": err.Error(),
})
return
}
var input services.CreateTableReq
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(400, gin.H{
"message": "Invalid json body",
"error": err.Error(),
})
return
}
if err := dh.Serv.CreateDynamicTable(uint(projectID), input); nil != err {
c.JSON(500, gin.H{
"message": "Failed to create dynamic table",
"error": err.Error(),
})
return
}
c.JSON(200, gin.H{
"message": "Successfully created dynamic table",
"data": nil,
})

}
59 changes: 59 additions & 0 deletions Internal/core/services/dynamicDBService.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package services

import (
"fmt"
"regexp"
"strings"

"github.com/Arjuna-Ragil/Localbase/Internal/adapters/repository"
)

type DynamicDBService struct {
Repo *repository.DynamicDBRepo
}

func NewDynamicDBService(repo *repository.DynamicDBRepo) *DynamicDBService {
return &DynamicDBService{Repo: repo}
}

type ColumnReq struct {
Name string `json:"name"`
Type string `json:"type"`
}

type CreateTableReq struct {
TableName string `json:"table_name"`
Columns []ColumnReq `json:"columns"`
}

func sanitizeInput(input string) string {
result := strings.ToLower(input)
result = strings.ReplaceAll(result, " ", "_")
reg := regexp.MustCompile("[^a-z0-9_]+")
result = reg.ReplaceAllString(result, "")
return result
}

func (ds *DynamicDBService) CreateDynamicTable(projectID uint, req CreateTableReq) error {
safeTableName := fmt.Sprintf("proj_%d_%s", projectID, sanitizeInput(req.TableName))

var queryBuilder strings.Builder
queryBuilder.WriteString(fmt.Sprintf("CREATE TABLE %s (", safeTableName))
queryBuilder.WriteString("id SERIAL PRIMARY KEY, ")
queryBuilder.WriteString("created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ")

for _, col := range req.Columns {
safeColName := sanitizeInput(col.Name)
queryBuilder.WriteString(fmt.Sprintf("%s %s, ", safeColName, col.Type))
}

query := queryBuilder.String()
query = strings.TrimSuffix(query, ", ")
query += ");"

fmt.Println(query)
if err := ds.Repo.CreateDynamicDB(query); err != nil {
return err
}
return nil
}
17 changes: 11 additions & 6 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@ func SetupApp(db *repository.DBContainer, cfg *config.Config) Routes.Deps {
projectService := services.NewProjectService(projectRepo, userRepo)
projectHandler := handlers.NewProjectHandler(projectService)

dynamicDBRepo := repository.NewDynamicDB(db)
dynamicDBService := services.NewDynamicDBService(dynamicDBRepo)
dynamicDBHandler := handlers.NewDynamicDBHandler(dynamicDBService)

return Routes.Deps{
User: userHandler,
Auth: authHandler,
System: systemHandler,
Project: projectHandler,
UserRepo: userRepo,
Config: cfg,
User: userHandler,
Auth: authHandler,
System: systemHandler,
Project: projectHandler,
DynamicDB: dynamicDBHandler,
UserRepo: userRepo,
Config: cfg,
}
}
Loading