Skip to content

Commit 6779f3b

Browse files
authored
Switched request and response generics position (#1132)
* Updated code generation * Switched request and response generics position * Updated test * API generation * Removed unused generics * Test type definitions for callback style API as well * Fix comments * Fix conflict * API generation * Updated type def
1 parent e67b55d commit 6779f3b

File tree

10 files changed

+2624
-2327
lines changed

10 files changed

+2624
-2327
lines changed

index.d.ts

Lines changed: 2253 additions & 2254 deletions
Large diffs are not rendered by default.

lib/Helpers.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
// See the LICENSE file in the project root for more information
44

55
import { Readable as ReadableStream } from 'stream'
6-
import { TransportRequestOptions, ApiResponse, RequestBody, ResponseBody } from './Transport'
6+
import { TransportRequestOptions, ApiResponse, RequestBody } from './Transport'
77
import { Search, Bulk } from '../api/requestParams'
88

99
export default class Helpers {
10-
search<TRequestBody extends RequestBody, TDocument = unknown>(params: Search<TRequestBody>, options?: TransportRequestOptions): Promise<TDocument[]>
11-
scrollSearch<TRequestBody extends RequestBody, TDocument = unknown, TResponse = ResponseBody, TContext = unknown>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<ScrollSearchResponse<TDocument, TResponse, TContext>>
12-
scrollDocuments<TRequestBody extends RequestBody, TDocument = unknown>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<TDocument>
10+
search<TDocument = unknown, TRequestBody extends RequestBody = Record<string, any>>(params: Search<TRequestBody>, options?: TransportRequestOptions): Promise<TDocument[]>
11+
scrollSearch<TDocument = unknown, TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = unknown>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<ScrollSearchResponse<TDocument, TResponse, TContext>>
12+
scrollDocuments<TDocument = unknown, TRequestBody extends RequestBody = Record<string, any>>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<TDocument>
1313
bulk<TDocument = unknown>(options: BulkHelperOptions<TDocument>): BulkHelper<BulkStats>
1414
}
1515

16-
export interface ScrollSearchResponse<TDocument = unknown, TResponse = ResponseBody, TContext = unknown> extends ApiResponse<TResponse, TContext> {
16+
export interface ScrollSearchResponse<TDocument = unknown, TResponse = Record<string, any>, TContext = unknown> extends ApiResponse<TResponse, TContext> {
1717
clear: () => Promise<void>
1818
documents: TDocument[]
1919
}

lib/Transport.d.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ interface TransportOptions {
4545
opaqueIdPrefix?: string;
4646
}
4747

48-
export interface RequestEvent<TResponse = ResponseBody, TContext = unknown> {
48+
export interface RequestEvent<TResponse = Record<string, any>, TContext = unknown> {
4949
body: TResponse;
5050
statusCode: number | null;
5151
headers: Record<string, any> | null;
@@ -70,11 +70,10 @@ export interface RequestEvent<TResponse = ResponseBody, TContext = unknown> {
7070

7171
// ApiResponse and RequestEvent are the same thing
7272
// we are doing this for have more clear names
73-
export interface ApiResponse<TResponse = ResponseBody, TContext = unknown> extends RequestEvent<TResponse, TContext> {}
73+
export interface ApiResponse<TResponse = Record<string, any>, TContext = unknown> extends RequestEvent<TResponse, TContext> {}
7474

75-
export type RequestBody<T = Record<string, any>> = T | string | Buffer | ReadableStream
76-
export type RequestNDBody<T = Record<string, any>[]> = T | string[] | Buffer | ReadableStream
77-
export type ResponseBody<T = Record<string, any>> = T | string | boolean | ReadableStream
75+
export type RequestBody<T = Record<string, any>> = T | string | Buffer | ReadableStream
76+
export type RequestNDBody<T = Record<string, any>[]> = T | string | string[] | Buffer | ReadableStream
7877

7978
export interface TransportRequestParams {
8079
method: string;

lib/errors.d.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
44

5-
import { ApiResponse, ResponseBody } from './Transport'
5+
import { ApiResponse } from './Transport'
66

77
export declare class ElasticsearchClientError extends Error {
88
name: string;
99
message: string;
1010
}
1111

12-
export declare class TimeoutError extends ElasticsearchClientError {
12+
export declare class TimeoutError<TResponse = Record<string, any>, TContext = unknown> extends ElasticsearchClientError {
1313
name: string;
1414
message: string;
15-
meta: ApiResponse;
15+
meta: ApiResponse<TResponse, TContext>;
1616
constructor(message: string, meta: ApiResponse);
1717
}
1818

19-
export declare class ConnectionError extends ElasticsearchClientError {
19+
export declare class ConnectionError<TResponse = Record<string, any>, TContext = unknown> extends ElasticsearchClientError {
2020
name: string;
2121
message: string;
22-
meta: ApiResponse;
22+
meta: ApiResponse<TResponse, TContext>;
2323
constructor(message: string, meta: ApiResponse);
2424
}
2525

26-
export declare class NoLivingConnectionsError extends ElasticsearchClientError {
26+
export declare class NoLivingConnectionsError<TResponse = Record<string, any>, TContext = unknown> extends ElasticsearchClientError {
2727
name: string;
2828
message: string;
29-
meta: ApiResponse;
29+
meta: ApiResponse<TResponse, TContext>;
3030
constructor(message: string, meta: ApiResponse);
3131
}
3232

@@ -50,19 +50,19 @@ export declare class ConfigurationError extends ElasticsearchClientError {
5050
constructor(message: string);
5151
}
5252

53-
export declare class ResponseError extends ElasticsearchClientError {
53+
export declare class ResponseError<TResponse = Record<string, any>, TContext = unknown> extends ElasticsearchClientError {
5454
name: string;
5555
message: string;
56-
meta: ApiResponse;
57-
body: ResponseBody;
56+
meta: ApiResponse<TResponse, TContext>;
57+
body: TResponse;
5858
statusCode: number;
5959
headers: Record<string, any>;
6060
constructor(meta: ApiResponse);
6161
}
6262

63-
export declare class RequestAbortedError extends ElasticsearchClientError {
63+
export declare class RequestAbortedError<TResponse = Record<string, any>, TContext = unknown> extends ElasticsearchClientError {
6464
name: string;
6565
message: string;
66-
meta: ApiResponse;
66+
meta: ApiResponse<TResponse, TContext>;
6767
constructor(message: string, meta: ApiResponse);
6868
}

scripts/utils/generateMain.js

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -180,36 +180,37 @@ function toPascalCase (str) {
180180
function buildMethodDefinition (api, name, hasBody) {
181181
const Name = toPascalCase(name)
182182
const bodyType = ndjsonApiKey.includes(Name) ? 'RequestNDBody' : 'RequestBody'
183+
const defaultBodyType = ndjsonApiKey.includes(Name) ? 'Record<string, any>[]' : 'Record<string, any>'
183184

184185
if (hasBody) {
185186
let methods = [
186-
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
187-
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
188-
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
189-
{ key: `${api}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
187+
{ key: `${api}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
188+
{ key: `${api}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
189+
{ key: `${api}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
190+
{ key: `${api}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
190191
]
191192
if (isSnakeCased(api)) {
192193
methods = methods.concat([
193-
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
194-
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
195-
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
196-
{ key: `${camelify(api)}<TRequestBody extends ${bodyType}, TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
194+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params?: RequestParams.${Name}<TRequestBody>, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
195+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
196+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
197+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TRequestBody extends ${bodyType} = ${defaultBodyType}, TContext = unknown>(params: RequestParams.${Name}<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
197198
])
198199
}
199200
return methods
200201
} else {
201202
let methods = [
202-
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
203-
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
204-
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
205-
{ key: `${api}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
203+
{ key: `${api}<TResponse = Record<string, any>, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
204+
{ key: `${api}<TResponse = Record<string, any>, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
205+
{ key: `${api}<TResponse = Record<string, any>, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
206+
{ key: `${api}<TResponse = Record<string, any>, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
206207
]
207208
if (isSnakeCased(api)) {
208209
methods = methods.concat([
209-
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
210-
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
211-
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
212-
{ key: `${camelify(api)}<TResponse = ResponseBody, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
210+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TContext = unknown>(params?: RequestParams.${Name}, options?: TransportRequestOptions)`, val: `TransportRequestPromise<ApiResponse<TResponse, TContext>>` },
211+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TContext = unknown>(callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
212+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TContext = unknown>(params: RequestParams.${Name}, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` },
213+
{ key: `${camelify(api)}<TResponse = Record<string, any>, TContext = unknown>(params: RequestParams.${Name}, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>)`, val: `TransportRequestCallback` }
213214
])
214215
}
215216
return methods

test/types/api-response-body.test-d.ts

Lines changed: 153 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
// See the LICENSE file in the project root for more information
44

55
import { expectType, expectError } from 'tsd'
6-
import { ResponseBody } from '../../lib/Transport'
7-
import { Client } from '../../'
6+
import { Readable as ReadableStream } from 'stream';
7+
import { TransportRequestCallback } from '../../lib/Transport'
8+
import { Client, ApiError } from '../../'
89

910
const client = new Client({
1011
node: 'http://localhost:9200'
@@ -59,15 +60,15 @@ interface Source {
5960
foo: string
6061
}
6162

62-
// Use a bad body
63+
// body that does not respect the RequestBody constraint
6364
expectError(
6465
client.search({
6566
index: 'hello',
6667
body: 42
6768
}).then(console.log)
6869
)
6970

70-
// No generics
71+
// No generics (promise style)
7172
{
7273
const response = await client.search({
7374
index: 'test',
@@ -78,13 +79,13 @@ expectError(
7879
}
7980
})
8081

81-
expectType<ResponseBody>(response.body)
82+
expectType<Record<string, any>>(response.body)
8283
expectType<unknown>(response.meta.context)
8384
}
8485

85-
// Define only the request body
86+
// Define only the response body (promise style)
8687
{
87-
const response = await client.search<SearchBody>({
88+
const response = await client.search<SearchResponse<Source>>({
8889
index: 'test',
8990
body: {
9091
query: {
@@ -93,13 +94,13 @@ expectError(
9394
}
9495
})
9596

96-
expectType<ResponseBody>(response.body)
97+
expectType<SearchResponse<Source>>(response.body)
9798
expectType<unknown>(response.meta.context)
9899
}
99100

100-
// Define request body and response body
101+
// Define response body and request body (promise style)
101102
{
102-
const response = await client.search<SearchBody, SearchResponse<Source>>({
103+
const response = await client.search<SearchResponse<Source>, SearchBody>({
103104
index: 'test',
104105
body: {
105106
query: {
@@ -112,9 +113,9 @@ expectError(
112113
expectType<unknown>(response.meta.context)
113114
}
114115

115-
// Define request body, response body and the context
116+
// Define response body, request body and the context (promise style)
116117
{
117-
const response = await client.search<SearchBody, SearchResponse<Source>, string>({
118+
const response = await client.search<SearchResponse<Source>, SearchBody, string>({
118119
index: 'test',
119120
body: {
120121
query: {
@@ -126,3 +127,143 @@ expectError(
126127
expectType<SearchResponse<Source>>(response.body)
127128
expectType<string>(response.meta.context)
128129
}
130+
131+
// Send request body as string (promise style)
132+
{
133+
const response = await client.search({
134+
index: 'test',
135+
body: 'hello world'
136+
})
137+
138+
expectType<Record<string, any>>(response.body)
139+
expectType<unknown>(response.meta.context)
140+
}
141+
142+
// Send request body as buffer (promise style)
143+
{
144+
const response = await client.search({
145+
index: 'test',
146+
body: Buffer.from('hello world')
147+
})
148+
149+
expectType<Record<string, any>>(response.body)
150+
expectType<unknown>(response.meta.context)
151+
}
152+
153+
// Send request body as readable stream (promise style)
154+
{
155+
const response = await client.search({
156+
index: 'test',
157+
body: new ReadableStream()
158+
})
159+
160+
expectType<Record<string, any>>(response.body)
161+
expectType<unknown>(response.meta.context)
162+
}
163+
164+
// No generics (callback style)
165+
{
166+
const result = client.search({
167+
index: 'test',
168+
body: {
169+
query: {
170+
match: { foo: 'bar' }
171+
}
172+
}
173+
}, (err, response) => {
174+
expectType<ApiError>(err)
175+
expectType<Record<string, any>>(response.body)
176+
expectType<unknown>(response.meta.context)
177+
})
178+
expectType<TransportRequestCallback>(result)
179+
}
180+
181+
// Define only the response body (callback style)
182+
{
183+
const result = client.search<SearchResponse<Source>>({
184+
index: 'test',
185+
body: {
186+
query: {
187+
match: { foo: 'bar' }
188+
}
189+
}
190+
}, (err, response) => {
191+
expectType<ApiError>(err)
192+
expectType<SearchResponse<Source>>(response.body)
193+
expectType<unknown>(response.meta.context)
194+
})
195+
expectType<TransportRequestCallback>(result)
196+
}
197+
198+
// Define response body and request body (callback style)
199+
{
200+
const result = client.search<SearchResponse<Source>, SearchBody>({
201+
index: 'test',
202+
body: {
203+
query: {
204+
match: { foo: 'bar' }
205+
}
206+
}
207+
}, (err, response) => {
208+
expectType<ApiError>(err)
209+
expectType<SearchResponse<Source>>(response.body)
210+
expectType<unknown>(response.meta.context)
211+
})
212+
expectType<TransportRequestCallback>(result)
213+
}
214+
215+
// Define response body, request body and the context (callback style)
216+
{
217+
const result = client.search<SearchResponse<Source>, SearchBody, string>({
218+
index: 'test',
219+
body: {
220+
query: {
221+
match: { foo: 'bar' }
222+
}
223+
}
224+
}, (err, response) => {
225+
expectType<ApiError>(err)
226+
expectType<SearchResponse<Source>>(response.body)
227+
expectType<string>(response.meta.context)
228+
})
229+
expectType<TransportRequestCallback>(result)
230+
}
231+
232+
// Send request body as string (callback style)
233+
{
234+
const result = client.search({
235+
index: 'test',
236+
body: 'hello world'
237+
}, (err, response) => {
238+
expectType<ApiError>(err)
239+
expectType<Record<string, any>>(response.body)
240+
expectType<unknown>(response.meta.context)
241+
})
242+
expectType<TransportRequestCallback>(result)
243+
}
244+
245+
// Send request body as buffer (callback style)
246+
{
247+
const result = client.search({
248+
index: 'test',
249+
body: Buffer.from('hello world')
250+
}, (err, response) => {
251+
expectType<ApiError>(err)
252+
expectType<Record<string, any>>(response.body)
253+
expectType<unknown>(response.meta.context)
254+
})
255+
expectType<TransportRequestCallback>(result)
256+
}
257+
258+
// Send request body as readable stream (callback style)
259+
{
260+
const result = client.search({
261+
index: 'test',
262+
body: new ReadableStream()
263+
}, (err, response) => {
264+
expectType<ApiError>(err)
265+
expectType<Record<string, any>>(response.body)
266+
expectType<unknown>(response.meta.context)
267+
})
268+
expectType<TransportRequestCallback>(result)
269+
}

0 commit comments

Comments
 (0)