Skip to content

Improve Settings types #1864

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
166 changes: 83 additions & 83 deletions .code-samples.meilisearch.yaml

Large diffs are not rendered by default.

116 changes: 58 additions & 58 deletions README.md

Large diffs are not rendered by default.

908 changes: 56 additions & 852 deletions src/indexes.ts

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions src/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { HttpRequests } from "./http-requests.js";
import type { HttpRequestsWithEnqueuedTaskPromise } from "./task.js";
import type {
EnqueuedTaskPromise,
IndividualUpdatableSettings,
RecordAny,
} from "./types/index.js";

/** Each setting property mapped to their REST method required for updates. */
type MakeSettingsRecord = {
[TKey in keyof IndividualUpdatableSettings]: "put" | "patch";
};

/** Each setting property mapped to its get, update and reset functions. */
export type SettingFns = {
[TKey in keyof IndividualUpdatableSettings as `get${Capitalize<TKey>}`]: () => Promise<
IndividualUpdatableSettings[TKey]
>;
} & {
[TKey in keyof IndividualUpdatableSettings as `update${Capitalize<TKey>}`]: (
body: IndividualUpdatableSettings[TKey],
) => EnqueuedTaskPromise;
} & {
[TKey in keyof IndividualUpdatableSettings as `reset${Capitalize<TKey>}`]: () => EnqueuedTaskPromise;
};

function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}

function camelToKebabCase(str: string): string {
return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
}

/** Returns an object containing all the setting functions. */
export function makeSettingFns(
httpRequest: HttpRequests,
httpRequestsWithTask: HttpRequestsWithEnqueuedTaskPromise,
basePath: string,
opts: MakeSettingsRecord,
): SettingFns {
const settingFns = {} as RecordAny;

for (const [name, method] of Object.entries(opts)) {
const uppercaseName = capitalize(name);
const path = `${basePath}/${camelToKebabCase(name)}`;

settingFns[`get${uppercaseName}`] = async function (): Promise<
IndividualUpdatableSettings[keyof typeof opts]
> {
return await httpRequest.get({ path });
};

settingFns[`update${uppercaseName}`] = function (
body: IndividualUpdatableSettings[keyof typeof opts],
): EnqueuedTaskPromise {
return httpRequestsWithTask[method]({ path, body });
};

settingFns[`reset${uppercaseName}`] = function (): EnqueuedTaskPromise {
return httpRequestsWithTask.delete({ path });
};
}

return settingFns as SettingFns;
}
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./settings.js";
export * from "./task_and_batch.js";
export * from "./token.js";
export * from "./types.js";
197 changes: 197 additions & 0 deletions src/types/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import type { PascalToCamelCase } from "./shared.js";

/** Deeply map every property of a record to itself excluding null. */
type NonNullableDeepRecordValues<T> = {
[TKey in keyof T]: Exclude<NonNullableDeepRecordValues<T[TKey]>, null>;
};

/** Map properties of a record to be optional and nullable. */
type PartialAndNullable<T> = { [P in keyof T]?: T[P] | null };

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#proximity-precision}
*
* @see `meilisearch_types::settings::ProximityPrecisionView`
*/
export type ProximityPrecisionView = PascalToCamelCase<
"ByWord" | "ByAttribute"
>;

/**
* @see `minWordSizeForTypos` at {@link https://www.meilisearch.com/docs/reference/api/settings#typo-tolerance}
*
* @see `meilisearch_types::settings::MinWordSizeTyposSetting`
*/
export type MinWordSizeTyposSetting = PartialAndNullable<{
oneTypo: number;
twoTypos: number;
}>;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#typo-tolerance}
*
* @see `meilisearch_types::settings::TypoSettings`
*/
export type TypoSettings = PartialAndNullable<{
enabled: boolean;
minWordSizeForTypos: MinWordSizeTyposSetting;
disableOnWords: string[];
disableOnAttributes: string[];
}>;

/**
* @see `sortFacetValuesBy` at {@link https://www.meilisearch.com/docs/reference/api/settings#faceting}
* @see `meilisearch_types::facet_values_sort::FacetValuesSort`
*/
export type FacetValuesSort = PascalToCamelCase<"Alpha" | "Count">;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#faceting}
*
* @see `meilisearch_types::settings::FacetingSettings`
*/
export type FacetingSettings = PartialAndNullable<{
maxValuesPerFacet: number;
sortFacetValuesBy: Record<string, FacetValuesSort>;
}>;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#pagination}
*
* @see `meilisearch_types::settings::PaginationSettings`
*/
export type PaginationSettings = PartialAndNullable<{ maxTotalHits: number }>;

/**
* @see `distribution` at {@link https://www.meilisearch.com/docs/reference/api/settings#embedders}
* @see `milli::vector::DistributionShift`
*/
export type DistributionShift = {
mean: number;
sigma: number;
};

/** @see `source` at {@link https://www.meilisearch.com/docs/reference/api/settings#embedders} */
export type EmbedderSource = PascalToCamelCase<
"OpenAi" | "HuggingFace" | "Ollama" | "UserProvided" | "Rest"
>;

/** @see `milli::vector::hf::OverridePooling` */
export type OverridePooling = PascalToCamelCase<
"UseModel" | "ForceCls" | "ForceMean"
>;

/** @see `milli::vector::settings::SubEmbeddingSettings` */
export type SubEmbeddingSettings = PartialAndNullable<{
source: EmbedderSource;
model: string;
revision: string;
pooling: OverridePooling;
apiKey: string;
dimensions: number;
documentTemplate: string;
documentTemplateMaxBytes: number;
url: string;
request: unknown;
response: unknown;
headers: Record<string, string>;
}>;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#embedders}
*
* @see `milli::vector::settings::EmbeddingSettings`
*/
export type EmbeddingSettings = PartialAndNullable<{
distribution: DistributionShift;
binaryQuantized: boolean;
// upcoming properties
// searchEmbedder: SubEmbeddingSettings;
// indexingEmbedder: SubEmbeddingSettings;
}> &
SubEmbeddingSettings;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#localized-attributes}
*
* @see `meilisearch_types::locales::LocalizedAttributesRuleView`
*/
export type LocalizedAttributesRuleView = {
/** @see `milli::attribute_patterns::AttributePatterns` */
attributePatterns: string[];
/** @see `meilisearch_types::locales::Locale` */
locales: string[];
};

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#prefix-search}
*
* @see `meilisearch_types::settings::PrefixSearchSettings`
*/
export type PrefixSearchSettings = PascalToCamelCase<
"IndexingTime" | "Disabled"
>;

/** @see `meilisearch_types::settings::RankingRuleView` */
export type RankingRuleView =
| PascalToCamelCase<
"Words" | "Typo" | "Proximity" | "Attribute" | "Sort" | "Exactness"
>
| `${string}:${"asc" | "desc"}`;

/** A version of {@link Settings} that can be used to update the settings. */
export type UpdatableSettings = PartialAndNullable<{
/** {@link https://www.meilisearch.com/docs/reference/api/settings#displayed-attributes} */
displayedAttributes: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#searchable-attributes} */
searchableAttributes: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes} */
filterableAttributes: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes} */
sortableAttributes: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#ranking-rules} */
rankingRules: RankingRuleView[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#stop-words} */
stopWords: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#non-separator-tokens} */
nonSeparatorTokens: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#separator-tokens} */
separatorTokens: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#dictionary} */
dictionary: string[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#synonyms} */
synonyms: Record<string, string[]>;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#distinct-attribute} */
distinctAttribute: string;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#proximity-precision} */
proximityPrecision: ProximityPrecisionView;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#typo-tolerance} */
typoTolerance: TypoSettings;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#faceting} */
faceting: FacetingSettings;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#pagination} */
pagination: PaginationSettings;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#embedders} */
embedders: PartialAndNullable<Record<string, EmbeddingSettings>>;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#search-cutoff} */
searchCutoffMs: number;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#localized-attributes} */
localizedAttributes: LocalizedAttributesRuleView[];
/** {@link https://www.meilisearch.com/docs/reference/api/settings#facet-search} */
facetSearch: boolean;
/** {@link https://www.meilisearch.com/docs/reference/api/settings#prefix-search} */
prefixSearch: PrefixSearchSettings;
}>;

/**
* A version of {@link UpdatableSettings}, the first layer of properties of which
* is used to update or get individual settings.
*/
export type IndividualUpdatableSettings = Required<UpdatableSettings>;

/**
* {@link https://www.meilisearch.com/docs/reference/api/settings#body}
*
* @see `meilisearch_types::settings::Settings`
*/
export type Settings = NonNullableDeepRecordValues<UpdatableSettings>;
12 changes: 2 additions & 10 deletions src/types/shared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { RecordAny } from "./types.js";

export type CursorResults<T> = {
results: T[];
limit: number;
Expand All @@ -8,11 +6,5 @@ export type CursorResults<T> = {
total: number;
};

export type NonNullableDeepRecordValues<T> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[P in keyof T]: T[P] extends any[]
? Array<NonNullableDeepRecordValues<T[P][number]>>
: T[P] extends RecordAny
? NonNullableDeepRecordValues<T[P]>
: NonNullable<T[P]>;
};
// taken from https://stackoverflow.com/a/65642944
export type PascalToCamelCase<S extends string> = Uncapitalize<S>;
2 changes: 1 addition & 1 deletion src/types/task_and_batch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Settings } from "./types.js";
import type { Settings } from "./settings.js";
import type { CursorResults } from "./shared.js";
import type { MeiliSearchErrorResponse } from "./types.js";

Expand Down
Loading