Skip to content

Commit

Permalink
switch to sqlite db
Browse files Browse the repository at this point in the history
  • Loading branch information
crmejia committed Sep 1, 2022
1 parent cf353e8 commit 85cb998
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 104 deletions.
8 changes: 2 additions & 6 deletions guide.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ type guide struct {
Name string
Description string
Coordinate coordinate
Pois *[]pointOfInterest
//TODO should this be private?
//in order to avoid modifications by the user
//e.g. g.Pois = append(pois.Pois, Poi{})but in reality
//the user as to create objects to insert
Pois []pointOfInterest //used to render /guide/:id
}

type coordinate struct {
Expand Down Expand Up @@ -100,7 +96,7 @@ func newGuide(name string, opts ...guideOption) (guide, error) {
}
g := guide{
Name: name,
Pois: &[]pointOfInterest{},
Pois: []pointOfInterest{},
}

for _, opt := range opts {
Expand Down
26 changes: 7 additions & 19 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (c *Server) HandleGuide() http.HandlerFunc {
http.Error(w, "guide Not Found", http.StatusNotFound)
return
}
g.Pois = c.store.GetAllPois(id)

render(w, r, "templates/guide.html", g)
}
Expand Down Expand Up @@ -123,17 +124,15 @@ func (s *Server) HandleCreatePoi() http.HandlerFunc {
return
}

newPoi, err := s.store.CreatePoi(poiForm.Name, gid, PoiWithValidStringCoordinates(poiForm.Latitude, poiForm.Longitude))
_, err = s.store.CreatePoi(poiForm.Name, gid, PoiWithValidStringCoordinates(poiForm.Latitude, poiForm.Longitude), PoiWithDescription(poiForm.Description))
if err != nil {
poiForm.Errors = append(poiForm.Errors, err.Error())
w.WriteHeader(http.StatusBadRequest)
render(w, r, "templates/createPoi.html", poiForm)
return
}
//TODO this should be a store operation func (s *store)CreatePoi(guideID, Poi{})(poiID, error)
//g.Pois = append(*g.Pois, poi)
//TODO could use gid as it's legit?
gURL := fmt.Sprintf("/guide/%d", newPoi.GuideID)

gURL := fmt.Sprintf("/guide/%d", gid)
http.Redirect(w, r, gURL, http.StatusSeeOther)
}
}
Expand All @@ -146,21 +145,10 @@ func (s *Server) Run() {
}

func ServerRun(address string) {
store := memoryStore{
Guides: map[int64]guide{
1: guide{Id: 1, Name: "Nairobi", Coordinate: coordinate{10, 10}},
2: guide{Id: 2, Name: "Fukuoka", Coordinate: coordinate{11, 11}},
3: guide{Id: 3, Name: "Guia de restaurantes Roma, CDMX", Coordinate: coordinate{12, 12}},
4: guide{Id: 4, Name: "Guia de Cuzco", Coordinate: coordinate{13, 13}},
5: guide{Id: 5, Name: "San Cristobal de las Casas", Coordinate: coordinate{Latitude: 16.7371, Longitude: -92.6375},
Description: "Beatiful town in the mountains of the state of Chiapas.",
Pois: &[]pointOfInterest{
{Name: "Cafeología", Coordinate: coordinate{16.737393, -92.635857}, Description: "Best Coffee in town. Maybe even the best coffee in the country."},
{Name: "Centralita Coworking", Coordinate: coordinate{16.739030, -92.635001}, Description: "Nice Coworking with a cool vibe."},
}},
},
store, err := OpenSQLiteStore("city_guide.db")
if err != nil {
log.Fatal(err)
}
store.nextGuideKey = 6
s, err := NewServer(address, &store)
if err != nil {
log.Fatal(err)
Expand Down
47 changes: 8 additions & 39 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,44 +390,13 @@ func TestCreatePoiHandlerPost(t *testing.T) {
if res.StatusCode != http.StatusSeeOther {
t.Errorf("expected status 303 SeeOther, got %d", res.StatusCode)
}
if len(*store.Guides[1].Pois) > 1 {
t.Error("want store to contain new guide")
pois := store.GetAllPois(g.Id)
if len(pois) != 1 {
t.Error("want store to contain new poi")
}
}

//func TestRunHTTPServer(t *testing.T) {
// t.Parallel()
// freePort, err := freeport.GetFreePort()
// if err != nil {
// t.Fatal(err)
// }
// //const (
// // localHostAddress = "127.0.0.1"
// //)
// //address := fmt.Sprintf("%s:%d", localHostAddress, freePort)
// address := fmt.Sprintf(":%d", freePort)
// go guide.ServerRun(address)
//
// res, err := http.GetGuide("http://localhost" + address)
// for err != nil {
// switch {
// case strings.Contains(err.Error(), "connection refused"):
// time.Sleep(5 * time.Millisecond)
// res, err = http.GetGuide(address)
// default:
// t.Fatal(err)
// }
// }
// if res.StatusCode != http.StatusOK {
// t.Errorf("expected status 200 OK, body %d", res.StatusCode)
// }
// body, err := io.ReadAll(res.Body)
// if err != nil {
// t.Fatal(err)
// }
// want := "San Cristobal"
// got := string(body)
// if !strings.Contains(got, want) {
// t.Errorf("want index to contain %s\nGot:\n%s", want, got)
// }
//}
got := pois[0]
if got.Description != "blah blah" {
t.Error("want poi description to be set")
}
}
72 changes: 32 additions & 40 deletions store.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ type store interface {
}
type memoryStore struct {
Guides map[int64]guide
nextGuideKey int64
nextPoiKey int64
Pois map[int64]pointOfInterest
NextGuideKey int64
NextPoiKey int64
}

func OpenMemoryStore() memoryStore {
ms := memoryStore{
Guides: map[int64]guide{},
nextGuideKey: 1,
nextPoiKey: 1,
Pois: map[int64]pointOfInterest{},
NextGuideKey: 1,
NextPoiKey: 1,
}
return ms
}
Expand All @@ -46,10 +48,9 @@ func (s *memoryStore) CreateGuide(name string, opts ...guideOption) (*guide, err
if err != nil {
return nil, err
}
g.Id = s.nextGuideKey
g.Pois = &[]pointOfInterest{}
g.Id = s.NextGuideKey
s.Guides[g.Id] = g
s.nextGuideKey++
s.NextGuideKey++
return &g, nil
}

Expand Down Expand Up @@ -78,54 +79,41 @@ func (s *memoryStore) CreatePoi(name string, guideID int64, opts ...poiOption) (
if err != nil {
return nil, err
}
g, ok := s.Guides[poi.GuideID]
_, ok := s.Guides[poi.GuideID]
if !ok {
return nil, errors.New("guide not found")
}
poi.Id = s.nextPoiKey
*g.Pois = append(*g.Pois, poi)
s.nextPoiKey++
poi.Id = s.NextPoiKey
s.Pois[poi.Id] = poi
s.NextPoiKey++
return &poi, nil
}

func (s *memoryStore) UpdatePoi(poi *pointOfInterest) error {
g, ok := s.Guides[poi.GuideID]
if !ok {
return errors.New("guide not found")
}
found := false
for i, _ := range *g.Pois {
if (*g.Pois)[i].Id == poi.Id {
found = true
(*g.Pois)[i].Name = poi.Name
(*g.Pois)[i].Description = poi.Description
(*g.Pois)[i].Coordinate = poi.Coordinate
}
}

if !found {
return errors.New("poi not found")
}
s.Pois[poi.Id] = *poi //todo validate poi
return nil
}

func (s *memoryStore) GetPoi(id int64) (pointOfInterest, error) {
for _, g := range s.Guides {
for _, p := range *g.Pois {
if p.Id == id {
return p, nil
}
}
poi, ok := s.Pois[id]
if ok {
return poi, nil
}
return pointOfInterest{}, errors.New("poi not found")
}

func (s *memoryStore) GetAllPois(guideId int64) []pointOfInterest {
g, ok := s.Guides[guideId]
_, ok := s.Guides[guideId]
if !ok {
return []pointOfInterest{}
}
return *g.Pois
pois := []pointOfInterest{}
for _, poi := range s.Pois {
if poi.GuideID == guideId {
pois = append(pois, poi)
}
}
return pois
}

type sqliteStore struct {
Expand All @@ -141,7 +129,7 @@ func OpenSQLiteStore(dbPath string) (sqliteStore, error) {
return sqliteStore{}, err
}

for _, stmt := range []string{pragmaWALEnabled, pragma500BusyTimeout, pragma500BusyTimeout} {
for _, stmt := range []string{pragmaWALEnabled, pragma500BusyTimeout, pragmaForeignKeysON} {
_, err = db.Exec(stmt, nil)
if err != nil {
return sqliteStore{}, err
Expand All @@ -166,6 +154,9 @@ func OpenSQLiteStore(dbPath string) (sqliteStore, error) {

func (s *sqliteStore) CreateGuide(name string, opts ...guideOption) (*guide, error) {
g, err := newGuide(name, opts...)
if err != nil {
return nil, err
}
stmt, err := s.db.Prepare(insertGuide)
if err != nil {
return nil, err
Expand Down Expand Up @@ -282,7 +273,6 @@ func (s *sqliteStore) CreatePoi(name string, guideID int64, opts ...poiOption) (
return nil, err
}
poi.Id = lastInsertID
*g.Pois = append(*g.Pois, poi)
return &poi, nil
}

Expand Down Expand Up @@ -378,7 +368,8 @@ id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
latitude REAL NOT NULL,
longitude REAL NOT NULL);`
longitude REAL NOT NULL,
CHECK (name <> ''));`

const createPoiTable = `
CREATE TABLE IF NOT EXISTS poi(
Expand All @@ -388,7 +379,8 @@ description TEXT,
latitude REAL NOT NULL,
longitude REAL NOT NULL,
guideId INTEGER NOT NULL,
FOREIGN KEY(guideId) REFERENCES guide(id));`
FOREIGN KEY(guideId) REFERENCES guide(id),
CHECK (name <> ''));`

const insertGuide = `INSERT INTO guide(name, description, latitude, longitude ) VALUES (?, ?, ?, ?);`

Expand Down
50 changes: 50 additions & 0 deletions store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ func TestSqliteStore_PoiRoundtripCreateUpdateGetPoi(t *testing.T) {
}
want := "testPOI"
poi.Name = want
poi.Description = want
err = sqliteStore.UpdatePoi(poi)
if err != nil {
t.Fatal(err)
Expand All @@ -241,6 +242,9 @@ func TestSqliteStore_PoiRoundtripCreateUpdateGetPoi(t *testing.T) {
if want != got.Name {
t.Errorf("want rountrip(create,update,get) test to return %s, got %s", want, got.Name)
}
if want != got.Description {
t.Errorf("want rountrip(create,update,get) description to be %s, got %s", want, got.Description)
}
}

func TestSQLiteStore_GetAllPois(t *testing.T) {
Expand All @@ -267,3 +271,49 @@ func TestSQLiteStore_GetAllPois(t *testing.T) {
t.Errorf("want GetAllPois to return %d points of interest, got %d", len(pois), len(got))
}
}

func TestSqliteStore_GuideErrors(t *testing.T) {
t.Parallel()
tempDB := t.TempDir() + "errors.db"
sqliteStore, err := guide.OpenSQLiteStore(tempDB)
if err != nil {
t.Fatal(err)
}

_, err = sqliteStore.CreateGuide("", guide.GuideWithValidStringCoordinates("10", "10"))
if err == nil {
t.Error("want error on empty guide name")
}
_, err = sqliteStore.CreateGuide("test", guide.GuideWithValidStringCoordinates("1000", "10"))
if err == nil {
t.Error("want error on invalid coordinates")
}
}

func TestSqliteStore_PoiErrors(t *testing.T) {
t.Parallel()
tempDB := t.TempDir() + "errors.db"
sqliteStore, err := guide.OpenSQLiteStore(tempDB)
if err != nil {
t.Fatal(err)
}

_, err = sqliteStore.CreatePoi("test", 100, guide.PoiWithValidStringCoordinates("10", "10"))
if err == nil {
t.Error("want error on non-existing guide")
}

g, err := sqliteStore.CreateGuide("test", guide.GuideWithValidStringCoordinates("10", "10"))
if err != nil {
t.Fatal(err)
}

_, err = sqliteStore.CreatePoi("", g.Id, guide.PoiWithValidStringCoordinates("10", "10"))
if err == nil {
t.Error("want error on empty poi name")
}
_, err = sqliteStore.CreatePoi("test", g.Id, guide.PoiWithValidStringCoordinates("1110", "10"))
if err == nil {
t.Error("want error on invalid coordinates")
}
}

0 comments on commit 85cb998

Please sign in to comment.