mirror of
https://gitlab.com/wheres-the-tp/server.git
synced 2026-01-25 07:54:57 -06:00
support ordering and filtering from request body
This commit is contained in:
parent
923014d563
commit
b3a94903c8
7 changed files with 115 additions and 55 deletions
|
|
@ -13,6 +13,7 @@
|
|||
[ring-middleware-format "0.7.2"]
|
||||
[org.clojure/data.json "0.2.6"]
|
||||
[ring/ring-json "0.4.0"]
|
||||
[ring/ring-mock "0.3.1"]
|
||||
[ring/ring-jetty-adapter "1.4.0"]
|
||||
[com.layerware/hugsql "0.4.8"]]
|
||||
:plugins [[lein-ring "0.9.7"] [lein-environ "1.1.0"]]
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
CREATE EXTENSION IF NOT EXISTS "postgis";
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
CREATE TYPE quantity AS ENUM ('none', 'few', 'many', 'lots');
|
||||
CREATE TYPE QUANTITY_ENUM AS ENUM ('lots', 'many', 'few', 'none');
|
||||
|
||||
CREATE TYPE category AS ENUM ('beverages', 'desserts', 'entrees', 'other');
|
||||
CREATE TYPE CATEGORY_ENUM AS ENUM ('beverages', 'desserts', 'entrees', 'other');
|
||||
|
||||
create table food_items (
|
||||
id uuid PRIMARY KEY,
|
||||
name VARCHAR(100),
|
||||
place_id VARCHAR(50),
|
||||
category category,
|
||||
category CATEGORY_ENUM,
|
||||
images VARCHAR,
|
||||
thumbImage VARCHAR,
|
||||
loc geography(POINT,4326)
|
||||
|
|
@ -19,7 +19,7 @@ create table food_items (
|
|||
create table quantities (
|
||||
food_item_id uuid,
|
||||
date timestamp (1) with time zone,
|
||||
quantity quantity,
|
||||
quantity QUANTITY_ENUM,
|
||||
PRIMARY KEY(food_item_id, date)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,13 @@
|
|||
[hugsql.core :as hugsql])
|
||||
(:import com.mchange.v2.c3p0.ComboPooledDataSource))
|
||||
|
||||
; defines a number of functions in this namesapce as defined in queries.sql
|
||||
; by-distance
|
||||
; by-last-updated
|
||||
; by-quantity
|
||||
; select-food-items
|
||||
; within-radius
|
||||
; has-category
|
||||
(hugsql/def-db-fns "aretherecookies/queries.sql")
|
||||
|
||||
(def db-spec {:uri (env :database-jdbc-uri)
|
||||
|
|
@ -28,5 +35,26 @@
|
|||
|
||||
(defonce pooled-db (delay (pool db-spec)))
|
||||
|
||||
(defn query-food-items-by-distance [{:keys [lat lng radius]}]
|
||||
(food-items-by-distance @pooled-db {:dist radius :lng lng :lat lat}))
|
||||
(defn get-orderby [orderby & args]
|
||||
(apply
|
||||
(cond
|
||||
(= orderby "distance") by-distance
|
||||
(= orderby "lastupdated") by-last-updated
|
||||
(= orderby "quantity") by-quantity
|
||||
:else by-distance)
|
||||
args))
|
||||
|
||||
(defn get-where [{:keys [:lat :lng :filter]}]
|
||||
(let [radius (or (get filter "radius") 10)
|
||||
categories (get filter "categories")]
|
||||
(cond
|
||||
categories (has-category {:categories categories :lat lat :lng lng :dist radius})
|
||||
:else (within-radius {:lat lat :lng lng :dist radius}))))
|
||||
|
||||
(defn query-food-items [{lat "lat" lng "lng" filter "filter" orderby "orderby"}]
|
||||
(select-food-items
|
||||
@pooled-db
|
||||
{:lat lat
|
||||
:lng lng
|
||||
:where (get-where {:lat lat :lng lng :filter filter})
|
||||
:order (get-orderby orderby)}))
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
(ns aretherecookies.handler
|
||||
(:require [aretherecookies.db :refer [query-food-items-by-distance]]
|
||||
(:require [aretherecookies.db :refer [query-food-items]]
|
||||
[aretherecookies.parsers :refer [food-items-to-json
|
||||
parse-special-types]]
|
||||
[compojure.core :refer :all]
|
||||
[compojure.route :as route]
|
||||
[clojure.data.json :as json]
|
||||
|
|
@ -7,45 +9,15 @@
|
|||
[ring.middleware.anti-forgery :refer :all]
|
||||
[ring.middleware.json :refer [wrap-json-body]]))
|
||||
|
||||
(defn uuid-to-string [key value]
|
||||
(if (instance? java.util.UUID value) (.toString value) value))
|
||||
|
||||
(defn get-coords [item]
|
||||
(->
|
||||
item
|
||||
(get :location)
|
||||
json/read-str
|
||||
(get "coordinates")))
|
||||
|
||||
(defn build-lat-lng [[lng lat]]
|
||||
(hash-map :longitude lng :latitude lat))
|
||||
|
||||
(defn build-latlng [item]
|
||||
(let [[lng lat] (get-coords item)]
|
||||
(hash-map :longitude lng :latitude lat)))
|
||||
|
||||
(defn parse-location [item]
|
||||
(->
|
||||
item
|
||||
build-latlng
|
||||
(merge item)
|
||||
(dissoc :location)))
|
||||
|
||||
(defn food-items-to-json [query-result]
|
||||
(map parse-location query-result))
|
||||
|
||||
(defn food-items-handler [req]
|
||||
(println "req---->" (:body req))
|
||||
(let [{{lat "lat" lng "lng" filter "filter" orderby "orderby"} :body} req]
|
||||
(let [{body :body} req]
|
||||
(json/write-str
|
||||
(hash-map
|
||||
:orderby orderby
|
||||
:filter filter
|
||||
:fooditems (food-items-to-json
|
||||
(query-food-items-by-distance {:lat lat
|
||||
:lng lng
|
||||
:radius (get filter "radius")})))
|
||||
:value-fn uuid-to-string)))
|
||||
:orderby (get body "orderby")
|
||||
:filter (get body "filter")
|
||||
:fooditems (food-items-to-json (query-food-items body)))
|
||||
:value-fn parse-special-types)))
|
||||
|
||||
(defroutes app-routes
|
||||
(GET "/" [] (str {:csrf-token
|
||||
|
|
|
|||
35
src/aretherecookies/parsers.clj
Normal file
35
src/aretherecookies/parsers.clj
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
(ns aretherecookies.parsers
|
||||
(:require [clojure.data.json :as json]
|
||||
[clojure.string :as str]
|
||||
[ring.middleware.anti-forgery :refer :all]
|
||||
[ring.middleware.json :refer [wrap-json-body]]))
|
||||
|
||||
(defn parse-special-types [key value]
|
||||
(cond
|
||||
(instance? java.util.UUID value) (.toString value)
|
||||
(instance? java.sql.Timestamp value) (.getTime value)
|
||||
:else value))
|
||||
|
||||
(defn get-coords [item]
|
||||
(->
|
||||
item
|
||||
(get :location)
|
||||
json/read-str
|
||||
(get "coordinates")))
|
||||
|
||||
(defn build-lat-lng [[lng lat]]
|
||||
(hash-map :longitude lng :latitude lat))
|
||||
|
||||
(defn build-latlng [item]
|
||||
(let [[lng lat] (get-coords item)]
|
||||
(hash-map :longitude lng :latitude lat)))
|
||||
|
||||
(defn parse-location [item]
|
||||
(->
|
||||
item
|
||||
build-latlng
|
||||
(merge item)
|
||||
(dissoc :location)))
|
||||
|
||||
(defn food-items-to-json [query-result]
|
||||
(map parse-location query-result))
|
||||
|
|
@ -1,13 +1,37 @@
|
|||
-- :name food-items-by-distance :raw
|
||||
-- :name select-food-items :? :raw
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
place_id,
|
||||
category,
|
||||
images,
|
||||
thumbImage,
|
||||
ST_AsGeoJSON(loc) as location,
|
||||
ST_Distance(loc, ST_SetSRID(ST_Point(:lng, :lat),4326)::geography) / 1609 as distance
|
||||
FROM food_items
|
||||
WHERE ST_DWithin(loc, ST_SetSRID(ST_Point(:lng, :lat),4326)::geography, :dist * 1609)
|
||||
ORDER BY distance ASC
|
||||
f.id AS id,
|
||||
f.name AS name,
|
||||
f.place_id AS place_id,
|
||||
f.category AS category,
|
||||
f.images AS images,
|
||||
f.thumbImage AS thumbImage,
|
||||
ST_AsGeoJSON(f.loc) AS location,
|
||||
ST_Distance(f.loc, ST_SetSRID(ST_Point(:lng, :lat), 4326)::geography) / 1609 AS distance,
|
||||
q.quantity AS quantity,
|
||||
q.updated AS lastUpdated
|
||||
FROM food_items f
|
||||
LEFT OUTER JOIN (
|
||||
SELECT food_item_id, quantity, MAX(date) AS updated FROM quantities GROUP BY food_item_id, quantity
|
||||
) q
|
||||
ON f.id = q.food_item_id
|
||||
:snip:where
|
||||
:snip:order
|
||||
|
||||
-- :snip has-category
|
||||
WHERE
|
||||
ST_DWithin(loc, ST_SetSRID(ST_Point(:lng, :lat), 4326)::geography, :dist * 1609)
|
||||
AND
|
||||
category IN (:categories)
|
||||
|
||||
-- :snip within-radius
|
||||
WHERE ST_DWithin(loc, ST_SetSRID(ST_Point(:lng, :lat), 4326)::geography, :dist * 1609)
|
||||
|
||||
-- :snip by-distance
|
||||
ORDER BY distance ASC
|
||||
|
||||
-- :snip by-last-updated
|
||||
ORDER BY lastUpdated DESC
|
||||
|
||||
-- :snip by-quantity
|
||||
ORDER BY quantity DESC
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
(ns aretherecookies.handler-test
|
||||
(:require [clojure.test :refer :all]
|
||||
[ring.mock.request :as mock]
|
||||
[aretherecookies.handler :refer :all]))
|
||||
[aretherecookies.app :refer :all]))
|
||||
|
||||
(deftest test-app
|
||||
(testing "main route"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue