#guys help some error i cant figure it out..

30 messages · Page 1 of 1 (latest)

upbeat remnant
#
    "Error": "sql: Scan error on column index 5, name \"created_at\": unsupported Scan, storing driver.Value type <nil> into type *time.Time"
}```
#
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

// APIServer represents the JSON API server.
type APIServer struct {
    listenAddr string
    store      Storage
}

// newAPIServer creates a new instance of APIServer with the specified listen address.
func newAPIServer(listenAddr string, store Storage) *APIServer {
    return &APIServer{
        listenAddr: listenAddr,
        store:      store,
    }
}

// Run starts the JSON API server.
func (s *APIServer) Run() {
    router := mux.NewRouter()

    // Define routes and link them to corresponding handler functions.
    router.HandleFunc("/account", makeHTTPHandleFunc(s.handleAccount))
    router.HandleFunc("/account/{id}", makeHTTPHandleFunc(s.handleGetAccountByID))
    router.HandleFunc("/account", makeHTTPHandleFunc(s.handleCreateAccount))
    router.HandleFunc("/account", makeHTTPHandleFunc(s.handleDeleteAccount))
    router.HandleFunc("/account/transfer", makeHTTPHandleFunc(s.handleTransferAccount))

    log.Println("JSON API server running on port: ", s.listenAddr)

    //start the server
    http.ListenAndServe(s.listenAddr, router)
}

// handleAccount handles requests to /account endpoint.
func (s *APIServer) handleAccount(w http.ResponseWriter, r *http.Request) error {
    // Handle different HTTP methods for /account endpoint.
    switch r.Method {
    case "GET":
        return s.handleGetAccount(w, r)
    case "POST":
        return s.handleCreateAccount(w, r)
    case "DELETE":
        return s.handleDeleteAccount(w, r)
    default:
        return fmt.Errorf("method not allowed: %s", r.Method)
    }

}

func (s *APIServer) handleGetAccount(w http.ResponseWriter, r *http.Request) error {
    accounts, err := s.store.GetAccounts()
    if err != nil {
        return err
    }

    return WriteJSON(w, http.StatusOK, accounts)

}```
#
// handleGetAccount handles GET requests to /account endpoint.
func (s *APIServer) handleGetAccountByID(w http.ResponseWriter, r *http.Request) error {
    //handle GET request to get specific acc info
    id := mux.Vars(r)["id"]
    fmt.Println(id)
    return WriteJSON(w, http.StatusOK, &Account{})
}

// handleCreateAccount handles POST requests to /account endpoint.
func (s *APIServer) handleCreateAccount(w http.ResponseWriter, r *http.Request) error {
    //handle POST request to create new acc
    CreateAccountReq := new(CreateAccountRequest)
    if err := json.NewDecoder(r.Body).Decode(CreateAccountReq); err != nil {
        return err
    }

    account := NewAccount(CreateAccountReq.FirstName, CreateAccountReq.LastName)
    if err := s.store.CreateAccount(account); err != nil {
        return err
    }

    return WriteJSON(w, http.StatusOK, account)
}

// handleDeleteAccount handles DELETE requests to /account endpoint.
func (s *APIServer) handleDeleteAccount(w http.ResponseWriter, r *http.Request) error {
    //handle DELETE request to delete an acc
    return nil
}

// handleTransferAccount handles POST requests to /account/transfer endpoint.
func (s *APIServer) handleTransferAccount(w http.ResponseWriter, r *http.Request) error {
    //handle POST request to transfer func btw accounts
    return nil
}

// writes JSON response to the http.ResponseWriter with the specified status code.
func WriteJSON(w http.ResponseWriter, status int, v any) error {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    return json.NewEncoder(w).Encode(v)
}
#
// apiFunc is a function signature for handler functions.
type apiFunc func(http.ResponseWriter, *http.Request) error

// ApiError represents the structure for API error responses.
type ApiError struct {
    Error string
}

// makeHTTPHandleFunc is a decorator to convert an apiFunc to an http.HandlerFunc
func makeHTTPHandleFunc(f apiFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        if err := f(w, r); err != nil {
            WriteJSON(w, http.StatusBadRequest, ApiError{Error: err.Error()})
        }
    }
}
#
package main

import (
    "database/sql"
    "fmt"

    _ "github.com/lib/pq"
)

// Storage interface defines methods for interacting with a storage system.
type Storage interface {
    CreateAccount(*Account) error
    DeleteAccount(int) error
    UpdateAccount(*Account) error
    GetAccounts() ([]*Account, error)
    GetAccountByID(int) (*Account, error)
}

// PostgresStore is a struct representing a PostgreSQL database store.
type PostgresStore struct {
    db *sql.DB
}

// NewPostgresStore creates a new instance of PostgresStore and initializes the database connection.
func NewPostgresStore() (*PostgresStore, error) {
    connStr := "user=postgres dbname=postgres password=kanjk2340 sslmode=disable"
    db, err := sql.Open("postgres", connStr)
    if err != nil {
        return nil, err
    }

    if err := db.Ping(); err != nil {
        return nil, err
    }

    return &PostgresStore{
        db: db,
    }, nil
}

// Init initializes the PostgreSQL database by creating the account table.
func (s *PostgresStore) Init() error {
    return s.CreateAccountTable()
}

// CreateAccountTable creates the account table if it does not exist already.
func (s *PostgresStore) CreateAccountTable() error {
    query := `CREATE TABLE if not exists account (
        id serial primary key,
        first_name varchar(50),
        last_name varchar(50),
        number serial,
        balance serial,
        created_at timestamp
    )`

    _, err := s.db.Exec(query)
    return err
}```
#
// CreateAccount creates a new account in the PostgreSQL database.
func (s *PostgresStore) CreateAccount(acc *Account) error {

    query := `INSERT INTO account 
    (first_name, last_name, number, balance, created_at)
    VALUES ($1, $2, $3, $4, $5)`

    resp, err := s.db.Query(
        query,
        acc.FirstName,
        acc.LastName,
        acc.Number,
        acc.Balance,
        acc.CreatedAt,
    )

    if err != nil {
        return err
    }

    fmt.Printf("%+v\n", resp)

    return nil
}

// UpdateAccount updates an existing account in the PostgreSQL database.
func (s *PostgresStore) UpdateAccount(*Account) error {
    return nil
}

// DeleteAccount deletes an account from the PostgreSQL database based on the given ID.
func (s *PostgresStore) DeleteAccount(id int) error {
    return nil
}

// GetAccountByID retrieves an account from the PostgreSQL database based on the given ID.
func (s *PostgresStore) GetAccountByID(id int) (*Account, error) {
    return nil, nil
}

func (s *PostgresStore) GetAccounts() ([]*Account, error) {
    rows, err := s.db.Query("select * from account")
    if err != nil {
        return nil, err 
    }

    accounts := []*Account{}
    for rows.Next() {
        account := new(Account)
        err := rows.Scan(
            &account.ID, 
            &account.FirstName,
            &account.LastName,
            &account.Number,
            &account.Balance,
            &account.CreatedAt)

        if err != nil {
                return nil, err
        }
        accounts = append(accounts, account)
    }
    return accounts, nil
}```
clever cave
#

you should use sql.NullTime instead

#

btw select * is not recommend, because you won't know what will happen after the table is changed

upbeat remnant
clever cave
#

alr, I see, but created_at should never be NULL, so maybe you have to fix your table declaration

upbeat remnant
#
    "Error": "sql: expected 0 destination arguments in Scan, not 6"
}``` now showing this
clever cave
#

not your go structure

upbeat remnant
#

```query := CREATE TABLE IF NOT EXISTS account ( id SERIAL PRIMARY KEY, first_name VARCHAR(100), last_name VARCHAR(100), number SERIAL, balance SERIAL, created_at TIMESTAMP )

clever cave
#

you should add NOT NULL strict

#
upbeat remnant
clever cave
#

yes, they works because they checked their code over and over again in their mind. You can do that as well, but if you can't, you have to add these limits to your table then you don't make mistakes

upbeat remnant
#

```query := CREATE TABLE IF NOT EXISTS account ( id SERIAL PRIMARY KEY, first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, number SERIAL, balance SERIAL, created_at TIMESTAMP NOT NULL )

clever cave
#

you have to delete the old table before you can create a new one

#

makesure your table created successfully by remove the IF NOT EXISTS condition

upbeat remnant
#

hey it worked!

upbeat remnant
#

i was spending hours on this and was sooo tired. the error occured because i didnt delete the tables and kept tryijng on it

wanton viperBOT
#

If your question has been solved, please close the thread with </solved:1022173889255706726>

upbeat remnant
upbeat remnant
#

i solved it!!!