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