From 537a6bea106c8aaf581ad1c506c60b3d11462c84 Mon Sep 17 00:00:00 2001 From: Guillaume Hivert Date: Mon, 6 May 2024 20:16:04 +0200 Subject: [PATCH] feat: try full text search Signed-off-by: Guillaume Hivert --- apps/backend/src/backend/router.gleam | 54 ++++++++++++++++++++++++++- apps/backend/src/backend/web.gleam | 9 ----- apps/frontend/index.html | 2 +- apps/frontend/src/data/msg.gleam | 3 ++ apps/frontend/src/frontend.gleam | 18 ++++++++- 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/apps/backend/src/backend/router.gleam b/apps/backend/src/backend/router.gleam index cf50451..ed3726d 100644 --- a/apps/backend/src/backend/router.gleam +++ b/apps/backend/src/backend/router.gleam @@ -1,10 +1,16 @@ import api/hex import backend/config.{type Config, type Context} +import backend/error import backend/postgres/postgres import backend/web import cors_builder as cors +import gleam/dynamic +import gleam/function import gleam/http import gleam/io +import gleam/json +import gleam/list +import gleam/pgo import gleam/result import gleam/string_builder import tasks/hex as syncing @@ -19,7 +25,52 @@ fn empty_json() { pub fn handle_get(req: Request, ctx: Context) { case wisp.path_segments(req) { - [] -> empty_json() + ["search"] -> { + wisp.get_query(req) + |> list.find(fn(item) { item.0 == "q" }) + |> result.replace_error(error.EmptyError) + |> result.try(fn(item) { + let query = pgo.text("'" <> item.1 <> "'") + "SELECT + s.name, + s.json_signature, + m.name, + p.name + FROM package_type_fun_signature s + JOIN package_module m + ON m.id = s.package_module_id + JOIN package_release r + ON r.id = m.package_release_id + JOIN package p + ON p.id = r.package_id + WHERE to_tsvector(s.signature_) @@ to_tsquery($1)" + |> pgo.execute( + ctx.db, + [query], + dynamic.decode4( + fn(a, b, c, d) { + json.object([ + #("name", json.string(a)), + #("json_signature", dynamic.unsafe_coerce(b)), + #("module_name", json.string(c)), + #("package_name", json.string(d)), + ]) + }, + dynamic.element(0, dynamic.string), + dynamic.element(1, dynamic.dynamic), + dynamic.element(2, dynamic.string), + dynamic.element(3, dynamic.string), + ), + ) + |> result.map_error(error.DatabaseError) + }) + |> result.map(fn(r) { r.rows }) + |> result.unwrap([]) + |> function.tap(fn(a) { io.debug(list.length(a)) }) + |> json.preprocessed_array() + |> json.to_string_builder() + |> wisp.json_response(200) + } _ -> wisp.not_found() } } @@ -40,7 +91,6 @@ pub fn handle_post(req: Request, ctx: Context) { pub fn handle_request(req: Request, cnf: Config) -> Response { use req <- cors.wisp_handle(req, web.cors()) use req <- web.foundations(req) - use req <- web.reroute_non_json_request(req) use ctx <- postgres.middleware(cnf) case req.method { http.Get -> handle_get(req, ctx) diff --git a/apps/backend/src/backend/web.gleam b/apps/backend/src/backend/web.gleam index 942eb68..74e7253 100644 --- a/apps/backend/src/backend/web.gleam +++ b/apps/backend/src/backend/web.gleam @@ -1,5 +1,4 @@ import backend/config -import backend/request import cors_builder as cors import gleam/http import wisp.{type Request, type Response} @@ -14,14 +13,6 @@ pub fn foundations(req: Request, handler: Handler) -> Response { handler(req) } -pub fn reroute_non_json_request(req: Request, handler: Handler) -> Response { - case req.method, request.is_json_request(req) { - http.Get, True -> handler(req) - http.Get, False -> wisp.ok() - _, _ -> handler(req) - } -} - pub fn cors() { let origin = case config.is_dev() { True -> "http://localhost:5173" diff --git a/apps/frontend/index.html b/apps/frontend/index.html index a82ec9f..cf06651 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -6,7 +6,7 @@ - gloogle + Gloogle
diff --git a/apps/frontend/src/data/msg.gleam b/apps/frontend/src/data/msg.gleam index 2589935..1b7d293 100644 --- a/apps/frontend/src/data/msg.gleam +++ b/apps/frontend/src/data/msg.gleam @@ -1,5 +1,8 @@ +import lustre_http as http + pub type Msg { None SubmitSearch + SearchResults(Result(String, http.HttpError)) UpdateInput(String) } diff --git a/apps/frontend/src/frontend.gleam b/apps/frontend/src/frontend.gleam index 155cf51..c094654 100644 --- a/apps/frontend/src/frontend.gleam +++ b/apps/frontend/src/frontend.gleam @@ -1,9 +1,12 @@ import data/model.{type Model} import data/msg.{type Msg} import frontend/view +import gleam/dynamic +import gleam/io import lustre import lustre/effect import lustre/update +import lustre_http as http import sketch/lustre as sketch import sketch/options as sketch_options import tardis @@ -32,7 +35,20 @@ fn update(model: Model, msg: Msg) { model |> model.update_input(content) |> update.none() - msg.SubmitSearch -> update.none(model) + msg.SubmitSearch -> { + let input = model.input + #( + model, + http.get( + "http://localhost:3000/search?q=" <> input, + http.expect_text(msg.SearchResults), + ), + ) + } + msg.SearchResults(res) -> { + io.debug(res) + update.none(model) + } msg.None -> update.none(model) } }