@jpbberry/opensearch-typed
v0.0.4
Published
Take an Opensearch request object and turn it into a fully-typed response
Readme
opensearch-typed
Take an Opensearch request object and turn it into a fully-typesafe Opensearch response.
Library WIP
Only the following aggregations have been implemented:
termsfilterdate_histogramauto_date_histogramavgmulti_terms
Usage
Create a function to wrap your Opensearch queries, using the @jpbberry/opensearch-typed type interpreters.
There is no dependency on the Opensearch library allowing you to use whatever version you would like, but you will need to combine the types using & in order to get a typed experience on the query writing
E.g
import {
OpensearchRequest,
OpensearchResponse,
} from "@jpbberry/opensearch-typed";
import {
Search_Request,
Search_Response,
} from "@opensearch-project/opensearch/api/index.js";
export type IndexList = [
// Define your index list, more info below
{
pattern: `${string}-test`;
schema: SchemaObject;
}
];
export async function query<
// You will need to store some generics
N extends number,
K extends string | number | symbol,
I extends IndexList[number]["pattern"],
// Main request type
R extends OpensearchRequest<N, K, I> & Search_Request // Your own search request type for enforcing inputs types
>(
request: T
): Promise<
Search_Response & { body: OpensearchResponse<N, IndexList, T> } // Your own search response type for other Opensearch response fields // Override the body response type, this will only take over aggregations & hits, others types will come from Search_Response
> {
return await client.search(request); // The request type maps directly with the @opensearch-project/opensearch library
}
// In your implementation
const data = await query({
body: {
aggs: {
// or aggregations
things: {
terms: {
// should be typed from opensearch-project
field: "field.keyword",
},
aggs: {
other_thing: {
filter: {
term: {
"thing.keyword": "abc",
},
},
},
},
},
},
},
});
data.body.aggregations.things.buckets[0].other_thing.doc_count; // fully typed!!Hits source controlling
Depending on the schema you have defined the fields will be typed as well. E.g
interface SchemaObject {
abc: string;
def: string;
}
export type IndexList = [
{
pattern: `${string}-test`;
schema: SchemaObject;
}
];
// In your query function, use IndexList as the input for OpensearchResponse<N, IndexList, T>
const data = await query({
index: "*-test",
body: {
query: {
match_all: {},
},
},
});
data.hits.hits[0]._source; // { abc: string, def: string }You can also control the field sources in the body:
const data = await query({
index: "*-test",
body: {
_source: ["abc"], // typed
query: {
match_all: {},
},
},
});
data.hits.hits[0]._source; // { abc: string }If defining size as 0, the hits array will also be never
const data = await query({
size: 0,
body: {...}
})
data.hits.hits // neverIf the IndexList is defined as [], then the _source will be any, unless, _source is defined on the body, if it is, the source response will be defined as the keys in that array, with value any.
// With OpensearchResponse<N, [], T>
const data = await query({
index: '*-unknown',
body: {...}
})
data.hits.hits[0] // any
const data = await query({
index: '*-unknown',
body: {
_source: ['abc']
}
})
data.hits.hits[0] // { abc: any }