mirror of https://github.com/Budibase/budibase.git
10 changed files with 240 additions and 61 deletions
@ -0,0 +1,138 @@ |
|||
const fetch = require("node-fetch") |
|||
const { SearchIndexes } = require("../../db/utils") |
|||
const { checkSlashesInUrl } = require("../../utilities") |
|||
const env = require("../../environment") |
|||
|
|||
function buildSearchUrl( |
|||
appId, |
|||
query, |
|||
bookmark = null, |
|||
limit = 50, |
|||
includeDocs = true |
|||
) { |
|||
let url = `${env.COUCH_DB_URL}/${appId}/_design/database/_search` |
|||
url += `/${SearchIndexes.ROWS}?q=${query}` |
|||
if (includeDocs) { |
|||
url += "&include_docs=true" |
|||
} |
|||
if (limit) { |
|||
url += `&limit=${limit}` |
|||
} |
|||
if (bookmark) { |
|||
url += `&bookmark=${bookmark}` |
|||
} |
|||
return checkSlashesInUrl(url) |
|||
} |
|||
|
|||
class QueryBuilder { |
|||
constructor(appId, base) { |
|||
this.appId = appId |
|||
this.query = { |
|||
string: {}, |
|||
fuzzy: {}, |
|||
range: {}, |
|||
equal: {}, |
|||
meta: {}, |
|||
...base, |
|||
} |
|||
this.limit = 50 |
|||
this.bookmark = null |
|||
} |
|||
|
|||
setLimit(limit) { |
|||
this.limit = limit |
|||
return this |
|||
} |
|||
|
|||
setBookmark(bookmark) { |
|||
this.bookmark = bookmark |
|||
return this |
|||
} |
|||
|
|||
addString(key, partial) { |
|||
this.query.string[key] = partial |
|||
return this |
|||
} |
|||
|
|||
addFuzzy(key, fuzzy) { |
|||
this.query.fuzzy[key] = fuzzy |
|||
return this |
|||
} |
|||
|
|||
addRange(key, low, high) { |
|||
this.query.range = { |
|||
low, |
|||
high, |
|||
} |
|||
return this |
|||
} |
|||
|
|||
addEqual(key, value) { |
|||
this.query.equal[key] = value |
|||
return this |
|||
} |
|||
|
|||
addTable(tableId) { |
|||
this.query.equal.tableId = tableId |
|||
return this |
|||
} |
|||
|
|||
complete() { |
|||
let output = "" |
|||
function build(structure, queryFn) { |
|||
for (let [key, value] of Object.entries(structure)) { |
|||
if (output.length !== 0) { |
|||
output += " AND " |
|||
} |
|||
output += queryFn(key, value) |
|||
} |
|||
} |
|||
|
|||
if (this.query.string) { |
|||
build(this.query.string, (key, value) => `${key}:${value}*`) |
|||
} |
|||
if (this.query.number) { |
|||
build(this.query.number, (key, value) => |
|||
value.length == null |
|||
? `${key}:${value}` |
|||
: `${key}:[${value[0]} TO ${value[1]}]` |
|||
) |
|||
} |
|||
if (this.query.fuzzy) { |
|||
build(this.query.fuzzy, (key, value) => `${key}:${value}~`) |
|||
} |
|||
return buildSearchUrl(this.appId, output, this.bookmark, this.limit) |
|||
} |
|||
} |
|||
|
|||
exports.QueryBuilder = QueryBuilder |
|||
|
|||
exports.search = async query => { |
|||
const response = await fetch(query, { |
|||
method: "GET", |
|||
}) |
|||
const json = await response.json() |
|||
let output = { |
|||
rows: [], |
|||
} |
|||
if (json.rows != null && json.rows.length > 0) { |
|||
output.rows = json.rows.map(row => row.doc) |
|||
} |
|||
if (json.bookmark) { |
|||
output.bookmark = json.bookmark |
|||
} |
|||
return output |
|||
} |
|||
|
|||
exports.rowSearch = async ctx => { |
|||
// this can't be done through pouch, have to reach for trusty node-fetch
|
|||
const appId = ctx.user.appId |
|||
const bookmark = ctx.params.bookmark |
|||
let url |
|||
if (ctx.params.query) { |
|||
url = new QueryBuilder(appId, ctx.params.query, bookmark).complete() |
|||
} else if (ctx.params.raw) { |
|||
url = buildSearchUrl(appId, ctx.params.raw, bookmark) |
|||
} |
|||
ctx.body = await exports.search(url) |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/search") |
|||
|
|||
const router = Router() |
|||
|
|||
router.get("/api/search/rows", controller.rowSearch) |
|||
|
|||
module.exports = router |
|||
Loading…
Reference in new issue