# Membuat relasi dengan gorm di Gofiber

Baik, mari kita lanjutkan dengan membuat model, migration, dan API CRUD untuk tabel `category` dengan relasi one-to-many dengan tabel `product`. Berikut adalah langkah-langkahnya:

#### 1. Buat Migration untuk Tabel Category

Pertama, kita perlu membuat migration untuk tabel `category` dengan menambahkan foreign key ke tabel `product`.

**helpers/migration.go**

```go
package helpers

import (
	"gofiber/src/configs"
	"gofiber/src/models"
)

func Migration() {
	configs.DB.AutoMigrate(&models.Product{}, &models.Category{})
}
```

**models/Category.go**

```go
package models

import (
	"gofiber/src/configs"

	"gorm.io/gorm"
)

type Category struct {
	gorm.Model
	Name     string       `json:"name"`
	Image    string       `json:"image"`
	Products []ApiProduct `json:"products"`
}

type ApiProduct struct {
	Name       string  `json:"name" `
	Price      float64 `json:"price" `
	Stock      int     `json:"stock" `
	CategoryID uint    `json:"category_id"`
}

func SelectAllCategories() []*Category {
	var categories []*Category
	configs.DB.Preload("Products", func(db *gorm.DB) *gorm.DB {
		var items []*ApiProduct
		return db.Model(&Product{}).Find(&items)
	}).Find(&categories)
	return categories
}

func SelectCategoryById(id int) *Category {
	var category Category
	configs.DB.Preload("Products",
		func(db *gorm.DB) *gorm.DB {
			var items []*ApiProduct
			return db.Model(&Product{}).Find(&items)
		}).First(&category, "id = ?", id)
	return &category
}

func PostCategory(category *Category) error {
	result := configs.DB.Create(&category)
	return result.Error
}

func UpdateCategory(id int, updatedCategory *Category) error {
	result := configs.DB.Model(&Category{}).Where("id = ?", id).Updates(updatedCategory)
	return result.Error
}

func DeleteCategory(id int) error {
	result := configs.DB.Delete(&Category{}, "id = ?", id)
	return result.Error
}
```

Dalam implementasi di atas, kita menggunakan `Preload("Products")` untuk memuat produk yang terkait dengan setiap kategori yang dipilih. Ini memastikan bahwa ketika Anda mengambil semua kategori atau kategori berdasarkan ID, produk-produk yang terkait juga dimuat ke dalam struktur data kategori.

**models/Product.go**

```go
package models

import (
	"gofiber/src/configs"

	"gorm.io/gorm"
)

type Product struct {
	gorm.Model
	Name       string   `json:"name"`
	Price      float64  `json:"price"`
	Stock      int      `json:"stock"`
	CategoryID uint     `json:"category_id"`
	Category   Category `gorm:"foreignKey:CategoryID"`
}

func SelectAllProducts() []*Product {
	var items []*Product
	configs.DB.Preload("Category").Find(&items)
	return items
}

func SelectProductById(id int) *Product {
	var item Product
	configs.DB.Preload("Category").First(&item, "id = ?", id)
	return &item
}

func PostProduct(item *Product) error {
	result := configs.DB.Create(&item)
	return result.Error
}

func UpdateProduct(id int, newProduct *Product) error {
	var item Product
	result := configs.DB.Model(&item).Where("id = ?", id).Updates(newProduct)
	return result.Error
}

func DeleteProduct(id int) error {
	var item Product
	result := configs.DB.Delete(&item, "id = ?", id)
	return result.Error
}
```

#### 2. Buat API CRUD untuk Category

Kemudian, mari buat API CRUD untuk mengelola data kategori.

**controllers/CategoryController.go**

```go
package controllers

import (
	"gofiber/src/models"
	"strconv"

	"github.com/gofiber/fiber/v2"
)

func GetAllCategories(c *fiber.Ctx) error {
	categories := models.SelectAllCategories()
	return c.JSON(categories)
}

func GetCategoryById(c *fiber.Ctx) error {
	id, _ := strconv.Atoi(c.Params("id"))
	category := models.SelectCategoryById(id)
	return c.JSON(category)
}

func CreateCategory(c *fiber.Ctx) error {
	var category models.Category
	if err := c.BodyParser(&category); err != nil {
		c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"message": "Invalid request body",
		})
		return err
	}
	models.PostCategory(&category)
	return c.Status(fiber.StatusCreated).JSON(fiber.Map{
		"message": "Category created successfully",
	})
}

func UpdateCategory(c *fiber.Ctx) error {
	id, _ := strconv.Atoi(c.Params("id"))

	var updatedCategory models.Category
	if err := c.BodyParser(&updatedCategory); err != nil {
		c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
			"message": "Invalid request body",
		})
		return err
	}
	models.UpdateCategory(id, &updatedCategory)

	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"message": "Category updated successfully",
	})
}

func DeleteCategory(c *fiber.Ctx) error {
	id, _ := strconv.Atoi(c.Params("id"))
	models.DeleteCategory(id)
	return c.Status(fiber.StatusOK).JSON(fiber.Map{
		"message": "Category deleted successfully",
	})
}
```

**routes/main.go**

Tambahkan rute baru untuk API CRUD kategori.

```go
package routes

import (
	"gofiber/src/controllers"

	"github.com/gofiber/fiber/v2"
)

func SetupRoutes(app *fiber.App) {
	// Product routes
	app.Get("/products", controllers.GetAllProducts)
	app.Get("/product/:id", controllers.GetProductById)
	app.Post("/product", controllers.CreateProduct)
	app.Put("/product/:id", controllers.UpdateProduct)
	app.Delete("/product/:id", controllers.DeleteProduct)

	// Category routes
	app.Get("/categories", controllers.GetAllCategories)
	app.Get("/category/:id", controllers.GetCategoryById)
	app.Post("/category", controllers.CreateCategory)
	app.Put("/category/:id", controllers.UpdateCategory)
	app.Delete("/category/:id", controllers.DeleteCategory)
}
```

Dengan langkah-langkah ini, Anda telah menambahkan model, migration, dan API CRUD untuk kategori dengan relasi one-to-many dengan produk. Anda juga telah mengintegrasikan API kategori dengan rute aplikasi Anda.

sumber : [Dokumentasi](https://gorm.io/docs/has_one.html)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zakimaliki.gitbook.io/gofiber/basic-backend-dengan-gofiber-part-2/membuat-relasi-dengan-gorm-di-gofiber.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
