Use POST requests with JSON bodies for searching instead of GETs with query string params

This commit is contained in:
Andrew Kingston 2021-05-17 08:16:04 +01:00
parent 053928420f
commit 1e8c485ad3
1 changed files with 43 additions and 31 deletions

View File

@ -33,6 +33,7 @@ class QueryBuilder {
this.limit = 50
this.sortOrder = "ascending"
this.sortType = "string"
this.includeDocs = true
}
setTable(tableId) {
@ -65,6 +66,11 @@ class QueryBuilder {
return this
}
excludeDocs() {
this.includeDocs = false
return this
}
addString(key, partial) {
this.query.string[key] = partial
return this
@ -103,15 +109,16 @@ class QueryBuilder {
return this
}
buildSearchURL(excludeDocs = false) {
let output = "*:*"
buildSearchQuery() {
let query = "*:*"
function build(structure, queryFn) {
for (let [key, value] of Object.entries(structure)) {
const expression = queryFn(luceneEscape(key.replace(/ /, "_")), value)
if (expression == null) {
continue
}
output += ` AND ${expression}`
query += ` AND ${expression}`
}
}
@ -157,35 +164,43 @@ class QueryBuilder {
build(this.query.notEmpty, key => `${key}:["" TO *]`)
}
// Build the full search URL
let url = `${env.COUCH_DB_URL}/${this.appId}/_design/database/_search`
url += `/${SearchIndexes.ROWS}?q=${output}`
url += `&limit=${Math.min(this.limit, 200)}`
if (!excludeDocs) {
url += "&include_docs=true"
}
if (this.sort) {
const orderChar = this.sortOrder === "descending" ? "-" : ""
url += `&sort="${orderChar}${this.sort.replace(/ /, "_")}`
url += `<${this.sortType}>"`
}
if (this.bookmark) {
url += `&bookmark=${this.bookmark}`
return query
}
// Fix any double slashes in the URL
return checkSlashesInUrl(url)
buildSearchBody() {
let body = {
q: this.buildSearchQuery(),
limit: Math.min(this.limit, 200),
include_docs: this.includeDocs,
}
if (this.bookmark) {
body.bookmark = this.bookmark
}
if (this.sort) {
const order = this.sortOrder === "descending" ? "-" : ""
const type = `<${this.sortType}>`
body.sort = `${order}${this.sort.replace(/ /, "_")}${type}`
}
return body
}
async run() {
const url = `${env.COUCH_DB_URL}/${this.appId}/_design/database/_search/${SearchIndexes.ROWS}`
const body = this.buildSearchBody()
return await runQuery(url, body)
}
}
/**
* Executes a lucene search query.
* @param query The query URL
* @param url The query URL
* @param body The request body defining search criteria
* @returns {Promise<{rows: []}>}
*/
const runQuery = async query => {
const response = await fetch(query, {
method: "GET",
const runQuery = async (url, body) => {
const response = await fetch(url, {
body: JSON.stringify(body),
method: "POST",
})
const json = await response.json()
let output = {
@ -227,15 +242,14 @@ const recursiveSearch = async (appId, query, params) => {
if (rows.length > params.limit - 200) {
pageSize = params.limit - rows.length
}
const url = new QueryBuilder(appId, query)
const page = await new QueryBuilder(appId, query)
.setTable(params.tableId)
.setBookmark(bookmark)
.setLimit(pageSize)
.setSort(params.sort)
.setSortOrder(params.sortOrder)
.setSortType(params.sortType)
.buildSearchURL()
const page = await runQuery(url)
.run()
if (!page.rows.length) {
return rows
}
@ -272,24 +286,22 @@ exports.paginatedSearch = async (appId, query, params) => {
limit = 50
}
limit = Math.min(limit, 200)
const builder = new QueryBuilder(appId, query)
const search = new QueryBuilder(appId, query)
.setTable(params.tableId)
.setSort(params.sort)
.setSortOrder(params.sortOrder)
.setSortType(params.sortType)
const searchUrl = builder
const searchResults = await search
.setBookmark(params.bookmark)
.setLimit(limit)
.buildSearchURL()
const searchResults = await runQuery(searchUrl)
.run()
// Try fetching 1 row in the next page to see if another page of results
// exists or not
const nextUrl = builder
const nextResults = await search
.setBookmark(searchResults.bookmark)
.setLimit(1)
.buildSearchURL()
const nextResults = await runQuery(nextUrl)
.run()
return {
...searchResults,