Support for Elasticsearch 7.4 (#979)
* Update code generation (#969) * Updated code generation scripts to use the new spec * API generation * Fix bad link * Updated API reference doc (#945) * Updated API reference doc * Updated docs script * Fix issue; node roles are defaulting to true when undefined (fal… (#967) * Fix issue; nodeFilter was unable to filter because master, data, and ingest role were true if even they were false on the node. * Test nodesToHost of BaseConnectionPool correctly maps node roles * API generation * Docker: use 7.4-SNAPSHOT * API generation * Use 7.4 stable
This commit is contained in:
committed by
GitHub
parent
69805d8393
commit
7472c5ee94
@ -62,21 +62,39 @@ function generate (version, spec, common) {
|
||||
.replace(/\.([a-z])/g, k => k[1].toUpperCase())
|
||||
.replace(/_([a-z])/g, k => k[1].toUpperCase())
|
||||
|
||||
const methods = spec[api].methods
|
||||
const { paths, deprecated_paths, parts, params } = spec[api].url
|
||||
const { paths } = spec[api].url
|
||||
const { params } = spec[api]
|
||||
const acceptedQuerystring = []
|
||||
const required = []
|
||||
|
||||
if (deprecated_paths) {
|
||||
for (const p of deprecated_paths) {
|
||||
paths.push(p.path)
|
||||
const methods = paths.reduce((acc, val) => {
|
||||
for (const method of val.methods) {
|
||||
if (!acc.includes(method)) acc.push(method)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
const parts = paths.reduce((acc, val) => {
|
||||
if (!val.parts) return acc
|
||||
for (const part of Object.keys(val.parts)) {
|
||||
if (!acc.includes(part)) acc.push(part)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
// get the required parts from the url
|
||||
// if the url has at least one static path,
|
||||
// then there are not required parts of the url
|
||||
var allParts = []
|
||||
for (const path of paths) {
|
||||
if (path.parts) {
|
||||
allParts.push(Object.keys(path.parts))
|
||||
} else {
|
||||
allParts = []
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in parts) {
|
||||
if (parts[key].required) {
|
||||
required.push(key)
|
||||
}
|
||||
if (allParts.length > 0) {
|
||||
intersect(...allParts).forEach(r => required.push(r))
|
||||
}
|
||||
|
||||
for (const key in params) {
|
||||
@ -129,10 +147,6 @@ function generate (version, spec, common) {
|
||||
var { ${genQueryBlacklist(false)}, ...querystring } = params
|
||||
querystring = snakeCaseKeys(acceptedQuerystring, snakeCase, querystring, warnings)
|
||||
|
||||
if (method == null) {
|
||||
${generatePickMethod(methods)}
|
||||
}
|
||||
|
||||
var ignore = options.ignore
|
||||
if (typeof ignore === 'number') {
|
||||
options.ignore = [ignore]
|
||||
@ -168,7 +182,6 @@ function generate (version, spec, common) {
|
||||
function build${name[0].toUpperCase() + name.slice(1)} (opts) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const { makeRequest, ConfigurationError, handleError, snakeCaseKeys } = opts
|
||||
${generateDocumentation(spec[api], api)}
|
||||
|
||||
const acceptedQuerystring = [
|
||||
${acceptedQuerystring.map(q => `'${q}'`).join(',\n')}
|
||||
@ -178,6 +191,7 @@ function generate (version, spec, common) {
|
||||
${genSnakeCaseMap()}
|
||||
}
|
||||
|
||||
${generateDocumentation(spec[api], api)}
|
||||
return ${code}
|
||||
}
|
||||
|
||||
@ -260,13 +274,11 @@ function generate (version, spec, common) {
|
||||
}
|
||||
|
||||
const blacklist = ['method', 'body']
|
||||
if (typeof parts === 'object' && parts !== null) {
|
||||
Object.keys(parts).forEach(p => {
|
||||
const camelStr = toCamelCase(p)
|
||||
if (camelStr !== p) blacklist.push(`${camelStr}`)
|
||||
blacklist.push(`${p}`)
|
||||
})
|
||||
}
|
||||
parts.forEach(p => {
|
||||
const camelStr = toCamelCase(p)
|
||||
if (camelStr !== p) blacklist.push(`${camelStr}`)
|
||||
blacklist.push(`${p}`)
|
||||
})
|
||||
return addQuotes ? blacklist.map(q => `'${q}'`) : blacklist
|
||||
}
|
||||
|
||||
@ -302,44 +314,88 @@ function generate (version, spec, common) {
|
||||
return path.length > 0 ? ('\'/\' + ' + path) : '\'/\''
|
||||
}
|
||||
|
||||
var code = ''
|
||||
var hasStaticPath = false
|
||||
var singlePathComponent = false
|
||||
paths
|
||||
.filter(path => {
|
||||
if (path.indexOf('{') > -1) return true
|
||||
if (hasStaticPath === false) {
|
||||
const sortedPaths = paths
|
||||
// some legacy API have mutliple statis paths
|
||||
// this filter removes them
|
||||
.filter(p => {
|
||||
if (p.path.includes('{')) return true
|
||||
if (hasStaticPath === false && p.deprecated == null) {
|
||||
hasStaticPath = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
.sort((a, b) => (b.split('{').length + b.split('/').length) - (a.split('{').length + a.split('/').length))
|
||||
.forEach((path, index, arr) => {
|
||||
if (arr.length === 1) {
|
||||
singlePathComponent = true
|
||||
code += `
|
||||
path = ${genPath(path)}
|
||||
`
|
||||
} else if (index === 0) {
|
||||
code += `
|
||||
if (${genCheck(path)}) {
|
||||
path = ${genPath(path)}
|
||||
`
|
||||
} else if (index === arr.length - 1) {
|
||||
code += `
|
||||
} else {
|
||||
path = ${genPath(path)}
|
||||
`
|
||||
} else {
|
||||
code += `
|
||||
} else if (${genCheck(path)}) {
|
||||
path = ${genPath(path)}
|
||||
`
|
||||
}
|
||||
})
|
||||
// sort by number of parameters (desc)
|
||||
.sort((a, b) => Object.keys(b.parts || {}).length - Object.keys(a.parts || {}).length)
|
||||
|
||||
code += singlePathComponent ? '' : '}'
|
||||
var code = ''
|
||||
for (var i = 0; i < sortedPaths.length; i++) {
|
||||
const { path, methods } = sortedPaths[i]
|
||||
if (sortedPaths.length === 1) {
|
||||
code += `
|
||||
if (method == null) method = ${generatePickMethod(methods)}
|
||||
path = ${genPath(path)}
|
||||
`
|
||||
} else if (i === 0) {
|
||||
code += `
|
||||
if (${genCheck(path)}) {
|
||||
if (method == null) method = ${generatePickMethod(methods)}
|
||||
path = ${genPath(path)}
|
||||
}
|
||||
`
|
||||
} else if (i === sortedPaths.length - 1) {
|
||||
code += ` else {
|
||||
if (method == null) method = ${generatePickMethod(methods)}
|
||||
path = ${genPath(path)}
|
||||
}
|
||||
`
|
||||
} else {
|
||||
code += ` else if (${genCheck(path)}) {
|
||||
if (method == null) method = ${generatePickMethod(methods)}
|
||||
path = ${genPath(path)}
|
||||
}
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
// var hasStaticPath = false
|
||||
// var singlePathComponent = false
|
||||
// paths
|
||||
// .filter(path => {
|
||||
// if (path.indexOf('{') > -1) return true
|
||||
// if (hasStaticPath === false) {
|
||||
// hasStaticPath = true
|
||||
// return true
|
||||
// }
|
||||
// return false
|
||||
// })
|
||||
// .sort((a, b) => (b.split('{').length + b.split('/').length) - (a.split('{').length + a.split('/').length))
|
||||
// .forEach((path, index, arr) => {
|
||||
// if (arr.length === 1) {
|
||||
// singlePathComponent = true
|
||||
// code += `
|
||||
// path = ${genPath(path)}
|
||||
// `
|
||||
// } else if (index === 0) {
|
||||
// code += `
|
||||
// if (${genCheck(path)}) {
|
||||
// path = ${genPath(path)}
|
||||
// `
|
||||
// } else if (index === arr.length - 1) {
|
||||
// code += `
|
||||
// } else {
|
||||
// path = ${genPath(path)}
|
||||
// `
|
||||
// } else {
|
||||
// code += `
|
||||
// } else if (${genCheck(path)}) {
|
||||
// path = ${genPath(path)}
|
||||
// `
|
||||
// }
|
||||
// })
|
||||
|
||||
// code += singlePathComponent ? '' : '}'
|
||||
return code
|
||||
}
|
||||
}
|
||||
@ -359,20 +415,16 @@ function safeWords (str) {
|
||||
|
||||
function generatePickMethod (methods) {
|
||||
if (methods.length === 1) {
|
||||
return `method = '${methods[0]}'`
|
||||
return `'${methods[0]}'`
|
||||
}
|
||||
const bodyMethod = getBodyMethod(methods)
|
||||
const noBodyMethod = getNoBodyMethod(methods)
|
||||
if (bodyMethod && noBodyMethod) {
|
||||
return `method = body == null ? '${noBodyMethod}' : '${bodyMethod}'`
|
||||
return `body == null ? '${noBodyMethod}' : '${bodyMethod}'`
|
||||
} else if (bodyMethod) {
|
||||
return `
|
||||
method = '${bodyMethod}'
|
||||
`.trim()
|
||||
return `'${bodyMethod}'`
|
||||
} else {
|
||||
return `
|
||||
method = '${noBodyMethod}'
|
||||
`.trim()
|
||||
return `'${noBodyMethod}'`
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,7 +461,10 @@ function genUrlValidation (paths, api) {
|
||||
// then we reverse it. A parameters always require what is
|
||||
// at its right in the array.
|
||||
const chunks = paths
|
||||
.reduce((a, b) => a.split('/').length > b.split('/').length ? a : b)
|
||||
.sort((a, b) => Object.keys(a.parts || {}).length > Object.keys(b.parts || {}).length ? -1 : 1)
|
||||
.slice(0, 1)
|
||||
.reduce((acc, val) => val.path, '')
|
||||
// .reduce((a, b) => a.path.split('/').length > b.path.split('/').length ? a.path : b.path)
|
||||
.split('/')
|
||||
.filter(s => s.startsWith('{'))
|
||||
.map(s => s.slice(1, -1))
|
||||
@ -460,32 +515,20 @@ function genUrlValidation (paths, api) {
|
||||
return code.trim()
|
||||
}
|
||||
|
||||
function generateDocumentation (api, op) {
|
||||
const { parts = {}, params = {} } = api.url
|
||||
const { body } = api
|
||||
|
||||
function generateDocumentation ({ documentation }, op) {
|
||||
// we use `replace(/\u00A0/g, ' ')` to remove no breaking spaces
|
||||
// because some parts of the description fields are using it
|
||||
|
||||
if (documentation == null) return ''
|
||||
|
||||
var doc = '/**\n'
|
||||
doc += ` * Perform a [${op}](${api.documentation}) request\n *\n`
|
||||
Object.keys(parts).forEach(part => {
|
||||
const obj = parts[part]
|
||||
const description = obj.description || ''
|
||||
doc += ` * @param {${obj.type}} ${part} - ${description.replace(/\u00A0/g, ' ')}\n`
|
||||
})
|
||||
|
||||
Object.keys(params).forEach(param => {
|
||||
const obj = params[param]
|
||||
const description = obj.description || ''
|
||||
doc += ` * @param {${obj.type}} ${param} - ${description.replace(/\u00A0/g, ' ')}\n`
|
||||
})
|
||||
|
||||
if (body) {
|
||||
const description = body.description || ''
|
||||
doc += ` * @param {${body.type || 'object'}} body - ${description.replace(/\u00A0/g, ' ')}\n`
|
||||
doc += ` * Perform a ${op} request\n`
|
||||
if (documentation.description) {
|
||||
doc += ` * ${documentation.description.replace(/\u00A0/g, ' ')}\n`
|
||||
}
|
||||
if (documentation.url) {
|
||||
doc += ` * ${documentation.url}\n`
|
||||
}
|
||||
|
||||
doc += ' */'
|
||||
|
||||
return doc
|
||||
@ -495,4 +538,10 @@ function needsPathValidation (api) {
|
||||
return noPathValidation.indexOf(api) === -1
|
||||
}
|
||||
|
||||
function intersect (first, ...rest) {
|
||||
return rest.reduce((accum, current) => {
|
||||
return accum.filter(x => current.indexOf(x) !== -1)
|
||||
}, first)
|
||||
}
|
||||
|
||||
module.exports = generate
|
||||
|
||||
@ -11,6 +11,42 @@ function generateDocs (common, spec) {
|
||||
[[api-reference]]
|
||||
== API Reference
|
||||
|
||||
This document contains the entire list of the Elasticsearch API supported by the client, both OSS and commercial. The client is entirely licensed under Apache 2.0.
|
||||
|
||||
Elasticsearch exposes an HTTP layer to communicate with, and the client is a library that will help you do this. Because of this reason, you will see HTTP related parameters, such as ${'`'}body${'`'} or ${'`'}headers${'`'}.
|
||||
|
||||
Every API can accept two objects, the first contains all the parameters that will be sent to Elasticsearch, while the second includes the request specific parameters, such as timeouts, headers, and so on.
|
||||
In the first object, every parameter but the body will be sent via querystring or url parameter, depending on the API, and every unrecognized parameter will be sent as querystring.
|
||||
|
||||
[source,js]
|
||||
----
|
||||
// promise API
|
||||
const result = await client.search({
|
||||
index: 'my-index',
|
||||
from: 20,
|
||||
size: 10,
|
||||
body: { foo: 'bar' }
|
||||
}, {
|
||||
ignore: [404],
|
||||
maxRetries: 3
|
||||
})
|
||||
|
||||
// calback API
|
||||
client.search({
|
||||
index: 'my-index',
|
||||
from: 20,
|
||||
size: 10,
|
||||
body: { foo: 'bar' }
|
||||
}, {
|
||||
ignore: [404],
|
||||
maxRetries: 3
|
||||
}, (err, result) => {
|
||||
if (err) console.log(err)
|
||||
})
|
||||
----
|
||||
|
||||
In this document, you will find the reference of every parameter accepted by the querystring or the url. If you also need to send the body, you can find the documentation of its format in the reference link that is present along with every endpoint.
|
||||
|
||||
////////
|
||||
|
||||
This documentation is generated by running:
|
||||
@ -57,30 +93,43 @@ function commonParameters (spec) {
|
||||
|
||||
function generateApiDoc (spec) {
|
||||
const name = Object.keys(spec)[0]
|
||||
const documentationUrl = fixLink(name, spec[name].documentation)
|
||||
const documentationUrl = spec[name].documentation && spec[name].documentation.url
|
||||
? fixLink(name, spec[name].documentation.url)
|
||||
: ''
|
||||
const params = []
|
||||
// url params
|
||||
const urlParts = spec[name].url.parts
|
||||
const urlParts = spec[name].url.paths.reduce((acc, path) => {
|
||||
if (!path.parts) return acc
|
||||
for (const part in path.parts) {
|
||||
if (acc[part] != null) continue
|
||||
acc[part] = path.parts[part]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
if (urlParts) {
|
||||
Object.keys(urlParts).forEach(param => {
|
||||
params.push({
|
||||
name: param,
|
||||
type: getType(urlParts[param].type, urlParts[param].options),
|
||||
description: urlParts[param].description,
|
||||
default: urlParts[param].default
|
||||
default: urlParts[param].default,
|
||||
deprecated: !!urlParts[param].deprecated
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// query params
|
||||
const urlParams = spec[name].url.params
|
||||
const urlParams = spec[name].params
|
||||
if (urlParams) {
|
||||
Object.keys(urlParams).forEach(param => {
|
||||
const duplicate = params.find(ele => ele.name === param)
|
||||
if (duplicate) return
|
||||
params.push({
|
||||
name: param,
|
||||
type: getType(urlParams[param].type, urlParams[param].options),
|
||||
description: urlParams[param].description,
|
||||
default: urlParams[param].default
|
||||
default: urlParams[param].default,
|
||||
deprecated: !!urlParams[param].deprecated
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -92,7 +141,8 @@ function generateApiDoc (spec) {
|
||||
name: 'body',
|
||||
type: 'object',
|
||||
description: body.description,
|
||||
default: body.default
|
||||
default: body.default,
|
||||
deprecated: !!body.deprecated
|
||||
})
|
||||
}
|
||||
|
||||
@ -108,8 +158,13 @@ function generateApiDoc (spec) {
|
||||
// remove last comma
|
||||
.slice(0, -1)
|
||||
|
||||
const stability = spec[name].stability === 'stable'
|
||||
? ''
|
||||
: `*Stability:* ${spec[name].stability}`
|
||||
|
||||
var doc = dedent`
|
||||
=== ${camelify(name)}
|
||||
${stability}
|
||||
[source,ts]
|
||||
----
|
||||
client.${camelify(name)}(${codeParameters.length > 0 ? `{\n ${codeParameters}\n}` : ''})
|
||||
@ -131,6 +186,9 @@ function generateApiDoc (spec) {
|
||||
if (val.default) {
|
||||
acc += ` +\n_Default:_ ${'`' + val.default + '`'}`
|
||||
}
|
||||
if (val.deprecated) {
|
||||
acc += ` +\n\nWARNING: This parameter has been deprecated.`
|
||||
}
|
||||
return acc + '\n\n'
|
||||
}, '')
|
||||
|
||||
|
||||
@ -33,11 +33,34 @@ export interface Generic {
|
||||
.replace(/\.([a-z])/g, k => k[1].toUpperCase())
|
||||
.replace(/_([a-z])/g, k => k[1].toUpperCase())
|
||||
|
||||
const { parts = {}, params = {} } = spec[api].url
|
||||
const { body } = spec[api]
|
||||
const { paths = {} } = spec[api].url
|
||||
const { body, params = {} } = spec[api]
|
||||
|
||||
const partsArr = Object.keys(parts)
|
||||
.map(k => ({ key: k, value: parts[k] }))
|
||||
// get the required parts from the url
|
||||
// if the url has at least one static path,
|
||||
// then there are not required parts of the url
|
||||
var allParts = []
|
||||
var requiredParts = []
|
||||
for (const path of paths) {
|
||||
if (path.parts) {
|
||||
allParts.push(Object.keys(path.parts))
|
||||
} else {
|
||||
allParts = []
|
||||
break
|
||||
}
|
||||
}
|
||||
if (allParts.length > 0) {
|
||||
requiredParts = intersect(...allParts)
|
||||
}
|
||||
|
||||
const parts = paths.reduce((acc, path) => {
|
||||
if (!path.parts) return acc
|
||||
for (const part in path.parts) {
|
||||
if (acc[part] != null) continue
|
||||
acc[part] = { key: part, value: path.parts[part], required: requiredParts.includes(part) }
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
const deprecatedParametersToAdd = []
|
||||
const paramsArr = Object.keys(params)
|
||||
.filter(k => !Object.keys(parts).includes(k))
|
||||
@ -45,16 +68,18 @@ export interface Generic {
|
||||
if (deprecatedParameters[release] && deprecatedParameters[release][k]) {
|
||||
deprecatedParametersToAdd.push({
|
||||
key: deprecatedParameters[release][k],
|
||||
value: params[k]
|
||||
value: params[k],
|
||||
required: params[k].required
|
||||
})
|
||||
}
|
||||
return { key: k, value: params[k] }
|
||||
return { key: k, value: params[k], required: params[k].required }
|
||||
})
|
||||
|
||||
const partsArr = Object.keys(parts).map(k => parts[k])
|
||||
deprecatedParametersToAdd.forEach(k => partsArr.push(k))
|
||||
|
||||
const genLine = e => {
|
||||
const optional = e.value.required ? '' : '?'
|
||||
const optional = e.required ? '' : '?'
|
||||
return `${e.key}${optional}: ${getType(e.value.type, e.value.options)};`
|
||||
}
|
||||
|
||||
@ -91,4 +116,10 @@ export interface ${name[0].toUpperCase() + name.slice(1)}${body ? '<T = any>' :
|
||||
}
|
||||
}
|
||||
|
||||
function intersect (first, ...rest) {
|
||||
return rest.reduce((accum, current) => {
|
||||
return accum.filter(x => current.indexOf(x) !== -1)
|
||||
}, first)
|
||||
}
|
||||
|
||||
module.exports = generate
|
||||
|
||||
Reference in New Issue
Block a user