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:
Tomas Della Vedova
2019-10-02 11:17:32 +02:00
committed by GitHub
parent 69805d8393
commit 7472c5ee94
288 changed files with 3353 additions and 4552 deletions

View File

@ -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

View File

@ -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'
}, '')

View File

@ -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