Use POST requests with JSON bodies for searching instead of GETs with query string params
This commit is contained in:
parent
053928420f
commit
1e8c485ad3
|
@ -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}>"`
|
||||
return query
|
||||
}
|
||||
|
||||
buildSearchBody() {
|
||||
let body = {
|
||||
q: this.buildSearchQuery(),
|
||||
limit: Math.min(this.limit, 200),
|
||||
include_docs: this.includeDocs,
|
||||
}
|
||||
if (this.bookmark) {
|
||||
url += `&bookmark=${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
|
||||
}
|
||||
|
||||
// Fix any double slashes in the URL
|
||||
return checkSlashesInUrl(url)
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue