package datastore import ( "database/sql" "fmt" "git.sa.vin/any-remark/backend/types" "math/rand" ) type Mapper interface { GetOpenGraphData(url string) (string, error) SaveOpenGraphData(url, opengraph string) error AddComment(req types.AddCommentRequest) error GetComments(url string) ([]types.Comment, error) } type mapper struct { db *sql.DB } func NewMapper(db *sql.DB) Mapper { // Empty function for NewMapper return &mapper{ db: db, } } func (m *mapper) GetOpenGraphData(url string) (string, error) { // get the opengraph data from the db table named "webpages" using the url query := `SELECT opengraph FROM webpages WHERE url = ?` rows, err := m.db.Query(query, url) if err != nil { if err == sql.ErrNoRows { return "", fmt.Errorf("no data found in db for url: %s", url) } return "", fmt.Errorf("error getting webpage data from db: %s", err) } defer rows.Close() // get the opengraph data from the rows array var opengraph string for rows.Next() { err = rows.Scan(&opengraph) if err != nil { return "", fmt.Errorf("error scanning opengraph data: %s", err) } return opengraph, nil } return "", fmt.Errorf("no data found in db for url: %s", url) } // SaveOpenGraphData saves the opengraph data to the db func (m *mapper) SaveOpenGraphData(url, opengraph string) error { // generate a unique id for the webpage make it 24 bytes long id := "wp_" + generateID(24) // insert the opengraph data to the db table named "webpages" using the url query := `INSERT INTO webpages (id, url, opengraph) VALUES (?, ?, ?)` _, err := m.db.Exec(query, id, url, opengraph) if err != nil { return fmt.Errorf("error inserting webpage data to db: %s", err) } return nil } func (m *mapper) GetWebpageID(url string) (string, error) { // get the id of the webpage from the db table named "webpages" using the url query := `SELECT id FROM webpages WHERE url = ?` rows, err := m.db.Query(query, url) if err != nil { if err == sql.ErrNoRows { return "", fmt.Errorf("no data found in db for url: %s", url) } return "", fmt.Errorf("error getting webpage data from db: %s", err) } defer rows.Close() // get the id from the rows array var id string for rows.Next() { err = rows.Scan(&id) if err != nil { return "", fmt.Errorf("error scanning webpage id: %s", err) } return id, nil } return "", fmt.Errorf("no data found in db for url: %s", url) } func (m *mapper) AddComment(req types.AddCommentRequest) error { webpageID, err := m.GetWebpageID(req.URL) if err != nil { return fmt.Errorf("error getting webpage id: %s", err) } // generate a unique id for the comment make it 24 bytes long id := "c_" + generateID(24) // insert the comment data to the db table named "comments" using the url query := `INSERT INTO comments (id, content, webpage_id, commenter) VALUES (?, ?, ?, ?)` _, err = m.db.Exec(query, id, req.Comment, webpageID, req.UserID) if err != nil { return fmt.Errorf("error inserting comment data to db: %s", err) } return nil } func (m *mapper) GetComments(url string) ([]types.Comment, error) { webpageID, err := m.GetWebpageID(url) if err != nil { return nil, fmt.Errorf("error getting webpage id: %s", err) } // TODO: add up vote and down vote counts // TODO: attach avatar url to commenter // TODO: provide order by recent or most upvoted // TODO: bubble up the current user's comments // get the comments from the db table named "comments" using the webpage_id query := `SELECT id, content, commenter FROM comments WHERE webpage_id = ?` rows, err := m.db.Query(query, webpageID) if err != nil { if err == sql.ErrNoRows { return nil, fmt.Errorf("no data found in db for url: %s", url) } return nil, fmt.Errorf("error getting comments from db: %s", err) } defer rows.Close() // get the comments from the rows array var comments []types.Comment for rows.Next() { var comment types.Comment err = rows.Scan(&comment.ID, &comment.Content, &comment.Commenter) if err != nil { return nil, fmt.Errorf("error scanning comments: %s", err) } comments = append(comments, comment) } return comments, nil } func generateID(n int) string { // generate a unique id for the webpage make it 24 bytes // long using the following character set charSet := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" charSetLen := len(charSet) id := make([]byte, n) for i := range id { // choose a random character from the character set id[i] = charSet[rand.Intn(charSetLen)] } return string(id) }