Context

Contextarrow-up-right adalah salah satu konkuresi pattern yang bertujuan untuk mengcancel jika menemui sebuah routine yang waktu eksekusinya lama. Karena operasi yang berjalan lama memang seharusnya diberi deadline. Jalan untuk meng-handle pembatalan adalah dengan melempar context.Context to fungsi yang mengetahui proses untuk mengecek pembatalan terminasi dini.

  • Tambahkan argumen context.Context ke semua fungsi di models/user.go

  • Passing ctx variable ke db.QueryContext, db.QueryRowContext, db.PrepareContext and stmt.ExecContext di file models/user.go

package models

import (
    "context"
    "database/sql"
    "essentials/libraries/api"
)

// User : struct of User
type User struct {
    ID       uint64
    Username string
    Password string
    Email    string
    IsActive bool
}

// List of users
func (u *User) List(ctx context.Context, db *sql.DB) ([]User, error) {
    var list []User
    const q = `SELECT id, username, password, email, is_active FROM users`

    rows, err := db.QueryContext(ctx, q)
    if err != nil {
        return list, err
    }

    defer rows.Close()

    for rows.Next() {
        var user User
        if err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.Email, &user.IsActive); err != nil {
            return list, err
        }
        list = append(list, user)
    }

    return list, rows.Err()
}

// Create new user
func (u *User) Create(ctx context.Context, db *sql.DB) error {
    const query = `
        INSERT INTO users (username, password, email, is_active, created, updated)
        VALUES (?, ?, ?, 0, NOW(), NOW())
    `
    stmt, err := db.PrepareContext(ctx, query)

    if err != nil {
        return err
    }

    defer stmt.Close()

    res, err := stmt.ExecContext(ctx, u.Username, u.Password, u.Email)
    if err != nil {
        return err
    }

    id, err := res.LastInsertId()
    if err != nil {
        return err
    }

    u.ID = uint64(id)

    return nil
}

// Get user by id
func (u *User) Get(ctx context.Context, db *sql.DB) error {
    const q string = `SELECT id, username, password, email, is_active FROM users`
    err := db.QueryRowContext(ctx, q+" WHERE id=?", u.ID).Scan(&u.ID, &u.Username, &u.Password, &u.Email, &u.IsActive)

    if err == sql.ErrNoRows {
        err = api.ErrNotFound(err, "")
    }

    return err
}

// Update user by id
func (u *User) Update(ctx context.Context, db *sql.DB) error {
    const q string = `UPDATE users SET is_active = ? WHERE id = ?`
    stmt, err := db.PrepareContext(ctx, q)
    if err != nil {
        return err
    }

    defer stmt.Close()

    _, err = stmt.ExecContext(ctx, u.IsActive, u.ID)
    return err
}

// Delete user by id
func (u *User) Delete(ctx context.Context, db *sql.DB) error {
    const q string = `DELETE FROM users WHERE id = ?`
    stmt, err := db.PrepareContext(ctx, q)
    if err != nil {
        return err
    }

    defer stmt.Close()

    _, err = stmt.ExecContext(ctx, u.ID)
    return err
}
  • Pass nilai dari r.Context() dari file controllers/users.go pada setiap kali memanggil method di models/user.go

  • Pass nilai dari r.Context() dari file usecases/user_usecase.go pada setiap kali memanggil method di models/user.go

  • Pada unit test, pass nilai dari context.Background() di file tests/user_tes.go setiap memanggil method di models/user.go

  • Kita bisa mengetesnya dengan membuat time.Sleep()

Last updated

Was this helpful?