Skip to content
This repository was archived by the owner on Dec 31, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
API_PORT = 8000
API_ENDPOINT=http://localhost:8090/api/v1

DB_USER=dev
DB_PASSWORD=password
Expand Down
12 changes: 9 additions & 3 deletions db/housing.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@ func CreateHousing(housing *models.Housing) (*models.Housing, error) {
return housing, nil
}

// GetAllHousing get all housings from the database
func GetAllHousing() ([]models.Housing, error) {
// GetHousings get all housings from the database
func GetHousings(limit int, cursor *models.Cursor) ([]models.Housing, error) {
var housing []models.Housing

if err := Db.Model(&housing).Order("created_at").Select(); err != nil {
query := Db.Model(&housing)

if cursor != nil {
query.Where("created_at <= ?", &cursor.CreatedAt).Where("id < ?", &cursor.ID)
}

if err := query.Order("created_at DESC").Limit(limit).Select(); err != nil {
return nil, err
}

Expand Down
15 changes: 15 additions & 0 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ var doc = `{
"application/json"
],
"summary": "Get all housing",
"parameters": [
{
"type": "string",
"description": "Per page limit",
"name": "per_page",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Previous request response Pagination-Cursor value",
"name": "cursor",
"in": "path"
}
],
"responses": {
"200": {
"description": "OK",
Expand Down
15 changes: 15 additions & 0 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@
"application/json"
],
"summary": "Get all housing",
"parameters": [
{
"type": "string",
"description": "Per page limit",
"name": "per_page",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Previous request response Pagination-Cursor value",
"name": "cursor",
"in": "path"
}
],
"responses": {
"200": {
"description": "OK",
Expand Down
10 changes: 10 additions & 0 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ paths:
/housing:
get:
description: Search all housing
parameters:
- description: Per page limit
in: path
name: per_page
required: true
type: string
- description: Previous request response Pagination-Cursor value
in: path
name: cursor
type: string
produces:
- application/json
responses:
Expand Down
100 changes: 100 additions & 0 deletions fixtures/housings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: 6c7de9e6-eddd-4139-bda7-5852beff8b49
created_at: 2020-10-16 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 45
Expand All @@ -27,6 +28,7 @@
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: a04e7587-87a1-4d5a-81c8-286a5fceee39
created_at: 2020-10-17 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
Expand All @@ -42,6 +44,7 @@
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-18 23:59:59

- type_id: 45a74d6b-1249-4c30-9ccd-6d4a3777b794
surface_area: 13
Expand All @@ -55,3 +58,100 @@
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: a04e7587-87a1-4d5a-81c8-286a5fceee39
created_at: 2020-10-19 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-15 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-14 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-13 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-12 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-11 23:59:59

- type_id: 58fc4ce6-3509-4185-845f-3d9ccda6469a
surface_area: 86.4
rent_price: 956.50
rental_charges: 95
country: FR
state: Pas-de-Calais
city: Arras
zip: 62000
street: 89 Rue Méaulens
has_electricity: true
has_gas: true
owner_id: RAW=gen_random_uuid()
last_tenant_id: RAW=gen_random_uuid()
status_id: f2625e4e-d06b-4ee5-ae99-258493643702
created_at: 2020-10-10 23:59:59
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ require (
github.com/rs/cors v1.7.0
github.com/swaggo/http-swagger v0.0.0-20200308142732-58ac5e232fba
github.com/swaggo/swag v1.6.7
golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4 // indirect
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 // indirect
golang.org/x/net v0.0.0-20201020065357-d65d470038a5 // indirect
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 // indirect
golang.org/x/tools v0.0.0-20201019175715-b894a3290fff // indirect
)
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
Expand Down Expand Up @@ -213,6 +215,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201020065357-d65d470038a5 h1:KrxvpY64uUzANd9wKWr6ZAsufiii93XnvXaeikyCJ2g=
golang.org/x/net v0.0.0-20201020065357-d65d470038a5/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -238,6 +242,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13 h1:5jaG59Zhd+8ZXe8C+lgiAGqkOaZBruqrWclLkgAww34=
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
Expand All @@ -253,8 +259,8 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b h1:/mJ+GKieZA6hFDQGdWZrjj4
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4 h1:rQWkJiVIyJ3PgiSHL+RXc8xbrK8duU6jG5eeZ9G7nk8=
golang.org/x/tools v0.0.0-20201015182029-a5d9e455e9c4/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201019175715-b894a3290fff h1:HiwHyqQ9ttqCHuTa++R4wNxOg6MY1hduSDT8j2aXoMM=
golang.org/x/tools v0.0.0-20201019175715-b894a3290fff/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
42 changes: 39 additions & 3 deletions handlers/housing.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ package handlers

import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"

"github.com/qimpl/housing/db"
"github.com/qimpl/housing/models"
"github.com/qimpl/housing/utils"

"github.com/google/uuid"
"github.com/gorilla/mux"
Expand Down Expand Up @@ -46,15 +50,32 @@ func CreateHousing(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(housing)
}

// GetAllHousing returns all the housing found on the request response
// GetHousings returns all the housings found on the database
// @Summary Get all housing
// @Description Search all housing
// @Produce json
// @Param per_page path string true "Per page limit"
// @Param cursor path string false "Previous request response Pagination-Cursor value"
// @Success 200 {string} []models.Housing
// @Failure 400 {string} models.ErrorResponse
// @Router /housing [get]
func GetAllHousing(w http.ResponseWriter, r *http.Request) {
housing, err := db.GetAllHousing()
func GetHousings(w http.ResponseWriter, r *http.Request) {
perPage, _ := strconv.Atoi(r.URL.Query().Get("per_page"))

var cursor *models.Cursor
var err error

if cursorParam := r.URL.Query().Get("cursor"); cursorParam != "" {
cursor, err = utils.DecodeCursor(cursorParam)

if err != nil {
w.WriteHeader(http.StatusBadRequest)
var badRequest *models.BadRequest
json.NewEncoder(w).Encode(badRequest.GetError(err.Error()))
}
}

housing, err := db.GetHousings(perPage, cursor)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
var badRequest *models.BadRequest
Expand All @@ -63,6 +84,21 @@ func GetAllHousing(w http.ResponseWriter, r *http.Request) {
return
}

nextCursor := utils.EncodeCursor(housing[len(housing)-1].ID, housing[len(housing)-1].CreatedAt)
paginationHeader := models.PaginationHeaders{
Link: []string{
fmt.Sprintf(
"<%s/housing?per_page=%d&cursor=%s>; rel=\"next\"",
os.Getenv("API_ENDPOINT"),
perPage,
nextCursor,
),
},
Cursor: nextCursor,
}

utils.WritePaginationHeaders(w, &paginationHeader)

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(housing)
}
Expand Down
2 changes: 2 additions & 0 deletions migrations/20201008143740_create_housing_tables.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ CREATE TABLE "housings" (
"updated_at" timestamp DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_housings_pagination ON housings (created_at, id);

CREATE TRIGGER update_timestamp
BEFORE UPDATE ON "housings"
FOR EACH ROW
Expand Down
15 changes: 15 additions & 0 deletions models/pagination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package models

import "time"

// Cursor yo
type Cursor struct {
ID string
CreatedAt time.Time
}

// PaginationHeaders a
type PaginationHeaders struct {
Link []string
Cursor string
}
3 changes: 2 additions & 1 deletion router/housing.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ func createHousingRouter(router *mux.Router) {
Methods("POST")

housingRouter.
HandleFunc("", handlers.GetAllHousing).
HandleFunc("", handlers.GetHousings).
Queries("per_page", "{per_page:[0-9]+}").
Methods("GET")

housingRouter.
Expand Down
Loading