Skip to content

Commit fffa70b

Browse files
authored
Merge pull request #290 from tharropoulos/infix
feat: add type-safe infix parameter validation & separate test TypeScript config
2 parents aa366cd + fc81918 commit fffa70b

File tree

11 files changed

+228
-75
lines changed

11 files changed

+228
-75
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
"build": "npm run build:tsc && npm run build:web:dev && npm run build:web:prod",
9999
"test:vitest": "vitest",
100100
"build:tsc": "tsc",
101+
"typecheck": "tsc --noEmit -p tsconfig.test.json",
101102
"build:web:dev": "webpack --config webpack.config.js --mode development",
102103
"build:web:prod": "webpack --config webpack.config.js --mode production",
103104
"build:tsc:watch": "tsc --watch",

src/Typesense/Documents.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ export type ImportResponse = ImportResponseSuccess | ImportResponseFail;
4040

4141
export type DocumentSchema = Record<string, any>;
4242

43-
export interface SearchParamsWithPreset<T extends DocumentSchema>
44-
extends Partial<SearchParams<T>> {
43+
export interface SearchParamsWithPreset<
44+
T extends DocumentSchema,
45+
Infix extends string,
46+
> extends Partial<SearchParams<T, Infix>> {
4547
preset: string;
4648
}
4749

src/Typesense/Keys.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ export interface KeysRetrieveSchema {
1010
keys: KeySchema[];
1111
}
1212

13-
export interface GenerateScopedSearchKeyParams<T extends DocumentSchema>
14-
extends Partial<SearchParams<T>> {
13+
export interface GenerateScopedSearchKeyParams<
14+
T extends DocumentSchema,
15+
Infix extends string,
16+
> extends Partial<SearchParams<T, Infix>> {
1517
expires_at?: number;
1618
cache_ttl?: number;
1719
limit_multi_searches?: number;
@@ -30,15 +32,17 @@ export default class Keys {
3032
return this.apiCall.get<KeysRetrieveSchema>(RESOURCEPATH);
3133
}
3234

33-
generateScopedSearchKey<T extends DocumentSchema>(
35+
generateScopedSearchKey<T extends DocumentSchema, const Infix extends string>(
3436
searchKey: string,
35-
parameters: GenerateScopedSearchKeyParams<T>,
37+
parameters: GenerateScopedSearchKeyParams<T, Infix>,
3638
): string {
3739
// Note: only a key generated with the `documents:search` action will be
38-
// accepted by the server, when usined with the search endpoint.
39-
const normalizedParams = normalizeArrayableParams<T, SearchParams<T>>(
40-
parameters,
41-
);
40+
// accepted by the server, when used with the search endpoint.
41+
const normalizedParams = normalizeArrayableParams<
42+
T,
43+
SearchParams<T, Infix>,
44+
Infix
45+
>(parameters);
4246
const paramsJSON = JSON.stringify(normalizedParams);
4347
const digest = Buffer.from(
4448
createHmac("sha256", searchKey).update(paramsJSON).digest("base64"),

src/Typesense/MultiSearch.ts

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,48 +35,63 @@ export default class MultiSearch {
3535
this.requestWithCache.clearCache();
3636
}
3737

38-
async perform<const T extends DocumentSchema[] = []>(
39-
searchRequests: MultiSearchRequestsWithUnionSchema<T[number]>,
40-
commonParams?: MultiSearchUnionParameters<T[number]>,
38+
async perform<
39+
const T extends DocumentSchema[] = [],
40+
const Infix extends string = string,
41+
>(
42+
searchRequests: MultiSearchRequestsWithUnionSchema<T[number], Infix>,
43+
commonParams?: MultiSearchUnionParameters<T[number], Infix>,
4144
options?: { cacheSearchResultsForSeconds?: number },
4245
): Promise<UnionSearchResponse<T[number]>>;
4346

44-
async perform<const T extends DocumentSchema[] = []>(
45-
searchRequests: MultiSearchRequestsWithoutUnionSchema<T[number]>,
46-
commonParams?: MultiSearchResultsParameters<T>,
47+
async perform<
48+
const T extends DocumentSchema[] = [],
49+
const Infix extends string = string,
50+
>(
51+
searchRequests: MultiSearchRequestsWithoutUnionSchema<T[number], Infix>,
52+
commonParams?: MultiSearchResultsParameters<T, Infix>,
4753
options?: { cacheSearchResultsForSeconds?: number },
4854
): Promise<{
4955
results: { [Index in keyof T]: SearchResponse<T[Index]> } & {
5056
length: T["length"];
5157
};
5258
}>;
5359

54-
async perform<const T extends DocumentSchema[] = []>(
55-
searchRequests: MultiSearchRequestsSchema<T[number]>,
60+
async perform<
61+
const T extends DocumentSchema[] = [],
62+
const Infix extends string = string,
63+
>(
64+
searchRequests: MultiSearchRequestsSchema<T[number], Infix>,
5665
commonParams?:
57-
| MultiSearchUnionParameters<T[number]>
58-
| MultiSearchResultsParameters<T>,
66+
| MultiSearchUnionParameters<T[number], Infix>
67+
| MultiSearchResultsParameters<T, Infix>,
5968
{
6069
cacheSearchResultsForSeconds = this.configuration
6170
.cacheSearchResultsForSeconds,
6271
}: { cacheSearchResultsForSeconds?: number } = {},
63-
): Promise<MultiSearchResponse<T>> {
72+
): Promise<MultiSearchResponse<T, Infix>> {
6473
const params = commonParams ? { ...commonParams } : {};
6574

6675
if (this.configuration.useServerSideSearchCache === true) {
6776
params.use_cache = true;
6877
}
6978

7079
const normalizedSearchRequests: Omit<typeof searchRequests, "searches"> & {
71-
searches: ExtractBaseTypes<SearchParams<T[number]>>[];
80+
searches: ExtractBaseTypes<SearchParams<T[number], Infix>>[];
7281
} = {
7382
union: searchRequests.union,
74-
searches: searchRequests.searches.map(normalizeArrayableParams),
83+
searches: searchRequests.searches.map(
84+
normalizeArrayableParams<
85+
T[number],
86+
SearchParams<T[number], Infix>,
87+
Infix
88+
>,
89+
),
7590
};
7691

7792
const { streamConfig, ...paramsWithoutStream } = params;
7893
const normalizedQueryParams = normalizeArrayableParams(
79-
paramsWithoutStream as SearchParams<T[number]>,
94+
paramsWithoutStream as SearchParams<T[number], Infix>,
8095
);
8196

8297
return this.requestWithCache.perform(

src/Typesense/Preset.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { DocumentSchema } from "./Documents";
33
import Presets, { PresetCreateSchema } from "./Presets";
44

55
export interface PresetSchema<T extends DocumentSchema>
6-
extends PresetCreateSchema<T> {
6+
extends PresetCreateSchema<T, string> {
77
name: string;
88
}
99

src/Typesense/Presets.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import { normalizeArrayableParams } from "./Utils";
66

77
const RESOURCEPATH = "/presets";
88

9-
export interface PresetCreateSchema<T extends DocumentSchema> {
10-
value: SearchParams<T> | MultiSearchRequestsSchema<T>;
9+
export interface PresetCreateSchema<
10+
T extends DocumentSchema,
11+
Infix extends string,
12+
> {
13+
value: SearchParams<T, Infix> | MultiSearchRequestsSchema<T, Infix>;
1114
}
1215

1316
export interface PresetsRetrieveSchema<T extends DocumentSchema> {
@@ -17,22 +20,24 @@ export interface PresetsRetrieveSchema<T extends DocumentSchema> {
1720
export default class Presets {
1821
constructor(private apiCall: ApiCall) {}
1922

20-
async upsert<T extends DocumentSchema>(
23+
async upsert<T extends DocumentSchema, const Infix extends string>(
2124
presetId: string,
22-
params: PresetCreateSchema<T>,
25+
params: PresetCreateSchema<T, Infix>,
2326
): Promise<PresetSchema<T>> {
2427
if (typeof params.value === "object" && "searches" in params.value) {
2528
const normalizedParams = params.value.searches.map((search) =>
26-
normalizeArrayableParams<T, SearchParams<T>>(search),
29+
normalizeArrayableParams<T, SearchParams<T, Infix>, Infix>(search),
2730
);
2831

2932
return this.apiCall.put<PresetSchema<T>>(this.endpointPath(presetId), {
3033
value: { searches: normalizedParams },
3134
});
3235
}
33-
const normalizedParams = normalizeArrayableParams<T, SearchParams<T>>(
34-
params.value,
35-
);
36+
const normalizedParams = normalizeArrayableParams<
37+
T,
38+
SearchParams<T, Infix>,
39+
Infix
40+
>(params.value);
3641

3742
return this.apiCall.put<PresetSchema<T>>(this.endpointPath(presetId), {
3843
value: normalizedParams,

src/Typesense/SearchOnlyDocuments.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ export class SearchOnlyDocuments<T extends DocumentSchema>
2828
this.requestWithCache.clearCache();
2929
}
3030

31-
async search(
32-
searchParameters: SearchParams<T> | SearchParamsWithPreset<T>,
31+
async search<const Infix extends string>(
32+
searchParameters: SearchParams<T, Infix> | SearchParamsWithPreset<T, Infix>,
3333
{
3434
cacheSearchResultsForSeconds = this.configuration
3535
.cacheSearchResultsForSeconds,
@@ -43,7 +43,8 @@ export class SearchOnlyDocuments<T extends DocumentSchema>
4343

4444
const { streamConfig, ...rest } = normalizeArrayableParams<
4545
T,
46-
SearchParams<T>
46+
SearchParams<T, Infix>,
47+
Infix
4748
>(searchParameters);
4849

4950
const queryParams = {

0 commit comments

Comments
 (0)