Latihan Membuat Fungsi Retrieve Data All Anime

Melanjutkan dari modul sebelumnya, pada modul ini kita akan latihan membuat fungsi untuk mengambil seluruh data anime.

Tentu saja jika data anime besar, pendekatan ini kurang tepat. Nanti akan kita perbaiki di modul lainnya. Untuk saat ini coba buat fungsi sederhana untuk retrieve all anime data.

Solusi

Buka file cmd/api/animeModel.go lalu tambahkan fungsi berikut

func (m *AnimeModel) All() ([]*Anime, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	query := `SELECT id, title, description, year
				FROM animes ORDER BY title
	`

	rows, err := m.DB.QueryContext(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var animes []*Anime

	for rows.Next() {
		var anime Anime
		err = rows.Scan(
			&anime.Id,
			&anime.Title,
			&anime.Desc,
			&anime.Year,
		)
		if err != nil {
			return nil, err
		}

		query2 := `SELECT ag.id, ag.anime_id, ag.genre_id, g.genre_name
		FROM animes_genres ag
		LEFT JOIN genres g  ON (g.id = ag.id)
		WHERE ag.anime_id = $1
		`

		rows2, _ := m.DB.QueryContext(ctx, query2, anime.Id)

		genre := make(map[int]string)
		for rows2.Next() {
			var ag animeGenre
			err = rows2.Scan(
				&ag.Id,
				&ag.AnimeId,
				&ag.GenreId,
				&ag.Genre.GenreName,
			)
			if err != nil {
				return nil, err
			}
			genre[ag.Id] = ag.Genre.GenreName
		}
		rows2.Close()
		anime.AnimeGenre = genre
		animes = append(animes, &anime)
	}

	return animes, nil
}

Kemudian buka file cmd/api/animesHandlers.go dan tambahkan fungsi berikut

func (app *application) getAnimes(rw http.ResponseWriter, r *http.Request) {
	animes, err := app.models.Animes.All()
	if err != nil {
		app.errorJSON(rw, err)
		return
	}

	err = app.writeJSON(rw, http.StatusOK, animes, "animes")
	if err != nil {
		app.errorJSON(rw, err)
	}
}

Jalankan aplikasi go, lalu buka route http://localhost:4000/v1/animes untuk menampilkan seluruh data anime. Sesuai ekspektasi, seluruh data anime berhasil di retrieve.

{
   "animes":[
      {
         "id":2,
         "title":"Barakamon",
         "desc":"Young temperamental caligrapher",
         "year":2019,
         "genre":{
            
         }
      },
      {
         "id":3,
         "title":"New Game",
         "desc":"New Game Anime",
         "year":2008,
         "genre":{
            
         }
      },
      {
         "id":4,
         "title":"Nichijou",
         "desc":"Daily life ",
         "year":2000,
         "genre":{
            
         }
      },
      {
         "id":1,
         "title":"Yuru Camp",
         "desc":"All about luxury camping",
         "year":2020,
         "genre":{
            "1":"SOL"
         }
      }
   ]
}

Berikut isi lengkap cmd/api/animeModel.go

package models

import (
	"context"
	"database/sql"
	"time"
)

type AnimeModel struct {
	DB *sql.DB
}

func (m *AnimeModel) Get(id int) (*Anime, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	query := `SELECT id, title, description, year
				FROM animes WHERE id = $1
	`

	row := m.DB.QueryRowContext(ctx, query, id)

	var anime Anime

	err := row.Scan(
		&anime.Id,
		&anime.Title,
		&anime.Desc,
		&anime.Year,
	)

	if err != nil {
		return nil, err
	}

	query = `SELECT ag.id, ag.anime_id, ag.genre_id, g.genre_name
			 FROM animes_genres ag
			 LEFT JOIN genres g  ON (g.id = ag.id)
			 WHERE ag.anime_id = $1
	`

	rows, _ := m.DB.QueryContext(ctx, query, id)

	genre := make(map[int]string)
	for rows.Next() {
		var ag animeGenre
		err := rows.Scan(
			&ag.Id,
			&ag.AnimeId,
			&ag.GenreId,
			&ag.Genre.GenreName,
		)
		if err != nil {
			return nil, err
		}
		genre[ag.Id] = ag.Genre.GenreName
	}
	anime.AnimeGenre = genre

	return &anime, nil
}

func (m *AnimeModel) All() ([]*Anime, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	query := `SELECT id, title, description, year
				FROM animes ORDER BY title
	`

	rows, err := m.DB.QueryContext(ctx, query)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var animes []*Anime

	for rows.Next() {
		var anime Anime
		err = rows.Scan(
			&anime.Id,
			&anime.Title,
			&anime.Desc,
			&anime.Year,
		)
		if err != nil {
			return nil, err
		}

		query2 := `SELECT ag.id, ag.anime_id, ag.genre_id, g.genre_name
		FROM animes_genres ag
		LEFT JOIN genres g  ON (g.id = ag.id)
		WHERE ag.anime_id = $1
		`

		rows2, _ := m.DB.QueryContext(ctx, query2, anime.Id)

		genre := make(map[int]string)
		for rows2.Next() {
			var ag animeGenre
			err = rows2.Scan(
				&ag.Id,
				&ag.AnimeId,
				&ag.GenreId,
				&ag.Genre.GenreName,
			)
			if err != nil {
				return nil, err
			}
			genre[ag.Id] = ag.Genre.GenreName
		}
		rows2.Close()
		anime.AnimeGenre = genre
		animes = append(animes, &anime)
	}

	return animes, nil
}

isi lengkap file cmd/api/animesHandlers.go

package main

import (
	"errors"
	"net/http"
	"strconv"

	"github.com/julienschmidt/httprouter"
)

func (app *application) getAnime(rw http.ResponseWriter, r *http.Request) {
	params := httprouter.ParamsFromContext(r.Context())

	id, err := strconv.Atoi(params.ByName("id"))
	if err != nil {
		app.logger.Println(errors.New("invalid id"))
		app.errorJSON(rw, err)
		return
	}
	app.logger.Println(id)

	anime, err := app.models.Animes.Get(id)
	if err != nil {
		app.errorJSON(rw, err)
		return
	}

	err = app.writeJSON(rw, http.StatusOK, anime, "anime")
	if err != nil {
		app.errorJSON(rw, err)
		return
	}
}

func (app *application) getAnimes(rw http.ResponseWriter, r *http.Request) {
	animes, err := app.models.Animes.All()
	if err != nil {
		app.errorJSON(rw, err)
		return
	}

	err = app.writeJSON(rw, http.StatusOK, animes, "animes")
	if err != nil {
		app.errorJSON(rw, err)
	}
}

Sharing is caring:

Leave a Comment