Skip to content
Snippets Groups Projects
Commit 1356c0e4 authored by Cam Saul's avatar Cam Saul
Browse files

working implementation of Search v1 in only 90 LOC

parent f5c3b86b
No related branches found
No related tags found
No related merge requests found
......@@ -9,6 +9,7 @@
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/core.async "LATEST"] ; facilities for async programming + communication (using 'LATEST' because this is an alpha library)
[org.clojure/core.match "0.3.0-alpha4"] ; optimized pattern matching library for Clojure
[org.clojure/math.numeric-tower "0.0.4"] ; math functions like `ceil`
[org.clojure/core.memoize "0.5.6"] ; needed by core.match; has useful FIFO, LRU, etc. caching mechanisms
[org.clojure/data.json "0.2.5"] ; JSON parsing / generation
[org.clojure/java.jdbc "0.3.6"] ; basic jdbc access from clojure
......
(ns metabase.api.meta.field
(:require [compojure.core :refer [GET]]
[metabase.api.common :refer :all]
[metabase.db :refer :all]
(metabase.models [hydrate :refer [hydrate]]
[field :refer [Field]])))
(defendpoint GET "/:id" [id]
(->404 (sel :one Field :id id)
(hydrate [:table :db])))
(define-routes)
......@@ -8,10 +8,12 @@
[qs :as qs]
[query :as query]
[result :as result]
[search :as search]
[session :as session]
[user :as user])
(metabase.api.meta [dataset :as dataset]
[db :as db]
[field :as field]
[table :as table])))
;; placeholder until we actually define real API routes
......@@ -22,11 +24,13 @@
(context "/dash" [] dash/routes)
(context "/meta/dataset" [] dataset/routes)
(context "/meta/db" [] db/routes)
(context "/meta/field" [] field/routes)
(context "/meta/table" [] table/routes)
(context "/org" [] org/routes)
(context "/qs" [] qs/routes)
(context "/query" [] query/routes)
(context "/result" [] result/routes)
(context "/search" [] search/routes)
(context "/session" [] session/routes)
(context "/user" [] user/routes)
(route/not-found (fn [{:keys [request-method uri]}]
......
(ns metabase.api.search
"/api/search endpoints."
(:require [clojure.math.numeric-tower :as math]
[compojure.core :refer [GET POST]]
[metabase.api.common :refer :all]
[metabase.db :refer :all]
(metabase.models [card :refer [Card]]
[field :refer [Field]]
[dashboard :refer [Dashboard]]
[database :refer [Database]]
[org :refer [Org]]
[table :refer [Table]])))
(def search-choices
"Different things that can be searched for.
TODO: Foreign Key, Query"
{:card {:name "Card"
:plural-name "Cards"
:entity Card
:url-prefix "card/"}
:dashboard {:name "Dashboard"
:plural-name "Dashboards"
:entity Dashboard
:url-prefix "dash/"}
:database {:name "Database"
:plural-name "Databases"
:entity Database
:url-prefix "admin/databases/"}
:field {:name "Field"
:plural-name "Fields"
:entity Field
:url-prefix "admin/datasets/field/"}
:table {:name "Table"
:plural-name "Tables"
:entity Table
:url-prefix "explore/table/"}})
(defn get-search-results
"Get search results for a given MODEL choice.
(get-search-results \"main_\" :table)"
[query {:keys [entity url-prefix] :as model}]
(->> (sel :many [entity :name :description :id] :name [like (str "%" query "%")])
(map (fn [{:keys [name description id]}]
{:display_type (:name model)
:name name
:description description
:url (str url-prefix id)}))))
(defn results-for-models
"Given a set of search-choices MODELS, get matching search results for QUERY.
(results-for-models #{:card :dashboard} \"guides\")"
[models query]
(mapcat (partial get-search-results query)
models))
;; primary search endpoint
(defendpoint POST "/" [:as {{:keys [org page results_per_page load_all q models]
:org {page 1
results_per_page 10}} :body}]
(let [models (if (empty? models) (vals search-choices) ; if search-choices is unspecified default to all choices
(->> models ; otherwise get corresponding model-choice maps
(map keyword)
(map search-choices)))
results (results-for-models models q)
offset (* results_per_page (- page 1))
num-results (count results)
num-pages (math/ceil (/ num-results results_per_page))
page-results (->> results
(drop offset)
(take results_per_page))]
{:results page-results
:page {:num_results num-results
:has_next (< page num-pages)
:has_previous (> page 1)
:num_results_per_page results_per_page
:page_number page
:num_pages num-pages
:start_index (+ 1 offset)
:end_index (+ offset (count page-results))}}))
;; return map of available search choices -> plural name like `{:table "Tables"}`
(defendpoint GET "/model_choices" [org]
{:choices {:metabase (->> search-choices
(map (fn [[choice {:keys [plural-name]}]]
{choice plural-name}))
(reduce merge))}})
(define-routes)
......@@ -81,6 +81,10 @@
(defentity Field
(table :metabase_field))
(defmethod post-select Field [_ {:keys [table_id] :as field}]
(assoc field
:table (sel-fn :one "metabase.models.table/Table" :id table_id)))
(defmethod pre-insert Field [_ field]
(let [defaults {:created_at (util/new-sql-date)
:updated_at (util/new-sql-date)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment