Use POST requests with JSON bodies for searching instead of GETs with query string params
This commit is contained in:
parent
053928420f
commit
1e8c485ad3
1 changed files with 43 additions and 31 deletions
|
@ -33,6 +33,7 @@ class QueryBuilder {
|
||||||
this.limit = 50
|
this.limit = 50
|
||||||
this.sortOrder = "ascending"
|
this.sortOrder = "ascending"
|
||||||
this.sortType = "string"
|
this.sortType = "string"
|
||||||
|
this.includeDocs = true
|
||||||
}
|
}
|
||||||
|
|
||||||
setTable(tableId) {
|
setTable(tableId) {
|
||||||
|
@ -65,6 +66,11 @@ class QueryBuilder {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
excludeDocs() {
|
||||||
|
this.includeDocs = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
addString(key, partial) {
|
addString(key, partial) {
|
||||||
this.query.string[key] = partial
|
this.query.string[key] = partial
|
||||||
return this
|
return this
|
||||||
|
@ -103,15 +109,16 @@ class QueryBuilder {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSearchURL(excludeDocs = false) {
|
buildSearchQuery() {
|
||||||
let output = "*:*"
|
let query = "*:*"
|
||||||
|
|
||||||
function build(structure, queryFn) {
|
function build(structure, queryFn) {
|
||||||
for (let [key, value] of Object.entries(structure)) {
|
for (let [key, value] of Object.entries(structure)) {
|
||||||
const expression = queryFn(luceneEscape(key.replace(/ /, "_")), value)
|
const expression = queryFn(luceneEscape(key.replace(/ /, "_")), value)
|
||||||
if (expression == null) {
|
if (expression == null) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
output += ` AND ${expression}`
|
query += ` AND ${expression}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,35 +164,43 @@ class QueryBuilder {
|
||||||
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the full search URL
|
return query
|
||||||
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}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix any double slashes in the URL
|
buildSearchBody() {
|
||||||
return checkSlashesInUrl(url)
|
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.
|
* 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: []}>}
|
* @returns {Promise<{rows: []}>}
|
||||||
*/
|
*/
|
||||||
const runQuery = async query => {
|
const runQuery = async (url, body) => {
|
||||||
const response = await fetch(query, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
body: JSON.stringify(body),
|
||||||
|
method: "POST",
|
||||||
})
|
})
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
let output = {
|
let output = {
|
||||||
|
@ -227,15 +242,14 @@ const recursiveSearch = async (appId, query, params) => {
|
||||||
if (rows.length > params.limit - 200) {
|
if (rows.length > params.limit - 200) {
|
||||||
pageSize = params.limit - rows.length
|
pageSize = params.limit - rows.length
|
||||||
}
|
}
|
||||||
const url = new QueryBuilder(appId, query)
|
const page = await new QueryBuilder(appId, query)
|
||||||
.setTable(params.tableId)
|
.setTable(params.tableId)
|
||||||
.setBookmark(bookmark)
|
.setBookmark(bookmark)
|
||||||
.setLimit(pageSize)
|
.setLimit(pageSize)
|
||||||
.setSort(params.sort)
|
.setSort(params.sort)
|
||||||
.setSortOrder(params.sortOrder)
|
.setSortOrder(params.sortOrder)
|
||||||
.setSortType(params.sortType)
|
.setSortType(params.sortType)
|
||||||
.buildSearchURL()
|
.run()
|
||||||
const page = await runQuery(url)
|
|
||||||
if (!page.rows.length) {
|
if (!page.rows.length) {
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
@ -272,24 +286,22 @@ exports.paginatedSearch = async (appId, query, params) => {
|
||||||
limit = 50
|
limit = 50
|
||||||
}
|
}
|
||||||
limit = Math.min(limit, 200)
|
limit = Math.min(limit, 200)
|
||||||
const builder = new QueryBuilder(appId, query)
|
const search = new QueryBuilder(appId, query)
|
||||||
.setTable(params.tableId)
|
.setTable(params.tableId)
|
||||||
.setSort(params.sort)
|
.setSort(params.sort)
|
||||||
.setSortOrder(params.sortOrder)
|
.setSortOrder(params.sortOrder)
|
||||||
.setSortType(params.sortType)
|
.setSortType(params.sortType)
|
||||||
const searchUrl = builder
|
const searchResults = await search
|
||||||
.setBookmark(params.bookmark)
|
.setBookmark(params.bookmark)
|
||||||
.setLimit(limit)
|
.setLimit(limit)
|
||||||
.buildSearchURL()
|
.run()
|
||||||
const searchResults = await runQuery(searchUrl)
|
|
||||||
|
|
||||||
// Try fetching 1 row in the next page to see if another page of results
|
// Try fetching 1 row in the next page to see if another page of results
|
||||||
// exists or not
|
// exists or not
|
||||||
const nextUrl = builder
|
const nextResults = await search
|
||||||
.setBookmark(searchResults.bookmark)
|
.setBookmark(searchResults.bookmark)
|
||||||
.setLimit(1)
|
.setLimit(1)
|
||||||
.buildSearchURL()
|
.run()
|
||||||
const nextResults = await runQuery(nextUrl)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...searchResults,
|
...searchResults,
|
||||||
|
|
Loading…
Reference in a new issue