Skip to content

Commit 0dfc39f

Browse files
committed
Merge with main
2 parents 65fb90e + 7da269f commit 0dfc39f

15 files changed

+252
-25
lines changed

.code-samples.meilisearch.yaml

+8-2
Original file line numberDiff line numberDiff line change
@@ -528,8 +528,14 @@ get_filterable_attributes_1: |-
528528
update_filterable_attributes_1: |-
529529
client.index('movies')
530530
.setting.updateFilterableAttributes([
531-
'genres',
532-
'director'
531+
"genres",
532+
{
533+
attributePatterns: ["genre"],
534+
features: {
535+
facetSearch: true,
536+
filter: { equality: true, comparison: false },
537+
},
538+
}
533539
])
534540
reset_filterable_attributes_1: |-
535541
client.index('movies').setting.resetFilterableAttributes()

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "meilisearch",
3-
"version": "0.49.0",
3+
"version": "0.50.0",
44
"description": "The Meilisearch JS client for Node.js and the browser.",
55
"keywords": [
66
"meilisearch",
@@ -78,7 +78,7 @@
7878
"eslint-config-prettier": "^10.1.1",
7979
"eslint-plugin-tsdoc": "^0.4.0",
8080
"typescript": "^5.8.2",
81-
"vite": "^6.2.5",
81+
"vite": "^6.2.6",
8282
"globals": "^16.0.0",
8383
"husky": "^9.1.7",
8484
"lint-staged": "15.5.0",

src/package-version.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const PACKAGE_VERSION = "0.49.0";
1+
export const PACKAGE_VERSION = "0.50.0";

src/types/settings.ts

+34-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
import type { PascalToCamelCase } from "./shared.js";
22

3+
/** @see `milli::filterable_attributes_rules::FilterFeatures` */
4+
export type FilterFeatures = {
5+
equality?: boolean;
6+
comparison?: boolean;
7+
};
8+
9+
/** @see `milli::filterable_attributes_rules::FilterableAttributesFeatures` */
10+
export type FilterableAttributesFeatures = {
11+
facetSearch?: boolean;
12+
filter?: FilterFeatures;
13+
};
14+
15+
/** @see `milli::filterable_attributes_rules::FilterableAttributesPatterns` */
16+
export type FilterableAttributesPatterns = {
17+
attributePatterns: string[];
18+
features?: FilterableAttributesFeatures;
19+
};
20+
21+
/** @see `milli::filterable_attributes_rules::FilterableAttributesRule` */
22+
export type FilterableAttributesRule = string | FilterableAttributesPatterns;
23+
324
/** Deeply map every property of a record to itself excluding null. */
425
type NonNullableDeepRecordValues<T> = {
526
[TKey in keyof T]: Exclude<NonNullableDeepRecordValues<T[TKey]>, null>;
@@ -63,17 +84,24 @@ export type FacetingSettings = PartialAndNullable<{
6384
export type PaginationSettings = PartialAndNullable<{ maxTotalHits: number }>;
6485

6586
/**
66-
* @see `distribution` at {@link https://www.meilisearch.com/docs/reference/api/settings#embedders}
87+
* `distribution` at
88+
* {@link https://www.meilisearch.com/docs/reference/api/settings#embedders}
89+
*
6790
* @see `milli::vector::DistributionShift`
6891
*/
6992
export type DistributionShift = {
7093
mean: number;
7194
sigma: number;
7295
};
7396

74-
/** @see `source` at {@link https://www.meilisearch.com/docs/reference/api/settings#embedders} */
97+
/**
98+
* `source` at
99+
* {@link https://www.meilisearch.com/docs/reference/api/settings#embedders}
100+
*
101+
* @see `milli::vector::settings::EmbedderSource`
102+
*/
75103
export type EmbedderSource = PascalToCamelCase<
76-
"OpenAi" | "HuggingFace" | "Ollama" | "UserProvided" | "Rest"
104+
"OpenAi" | "HuggingFace" | "Ollama" | "UserProvided" | "Rest" | "Composite"
77105
>;
78106

79107
/** @see `milli::vector::hf::OverridePooling` */
@@ -105,9 +133,8 @@ export type SubEmbeddingSettings = PartialAndNullable<{
105133
export type EmbeddingSettings = PartialAndNullable<{
106134
distribution: DistributionShift;
107135
binaryQuantized: boolean;
108-
// upcoming properties
109-
// searchEmbedder: SubEmbeddingSettings;
110-
// indexingEmbedder: SubEmbeddingSettings;
136+
searchEmbedder: SubEmbeddingSettings;
137+
indexingEmbedder: SubEmbeddingSettings;
111138
}> &
112139
SubEmbeddingSettings;
113140

@@ -146,7 +173,7 @@ export type UpdatableSettings = PartialAndNullable<{
146173
/** {@link https://www.meilisearch.com/docs/reference/api/settings#searchable-attributes} */
147174
searchableAttributes: string[];
148175
/** {@link https://www.meilisearch.com/docs/reference/api/settings#filterable-attributes} */
149-
filterableAttributes: string[];
176+
filterableAttributes: FilterableAttributesRule[];
150177
/** {@link https://www.meilisearch.com/docs/reference/api/settings#sortable-attributes} */
151178
sortableAttributes: string[];
152179
/** {@link https://www.meilisearch.com/docs/reference/api/settings#ranking-rules} */

src/types/task_and_batch.ts

+3
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ type BatchStats = {
168168
status: Record<TaskStatus, number>;
169169
types: Record<TaskType, number>;
170170
indexUids: Record<string, number>;
171+
progressTrace: Record<string, number>;
172+
// Do not type this field because the keys can change in a breaking way
173+
internalDatabaseSizes?: Record<string, number>;
171174
};
172175

173176
/**

src/types/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ export type Crop = {
183183
// `facetName` becomes mandatory when using `searchForFacetValues`
184184
export type SearchForFacetValuesParams = Omit<SearchParams, "facetName"> & {
185185
facetName: string;
186+
/**
187+
* If true, the facet search will return the exhaustive count of the facet
188+
* values.
189+
*/
190+
exhaustiveFacetCount?: boolean;
186191
};
187192

188193
export type FacetHit = {
@@ -469,6 +474,7 @@ export type RawDocumentAdditionOptions = DocumentOptions & {
469474
};
470475

471476
export type DocumentsQuery<T = RecordAny> = ResourceQuery & {
477+
ids?: string[] | number[];
472478
fields?: Fields<T>;
473479
filter?: Filter;
474480
limit?: number;

tests/__snapshots__/facet_search.test.ts.snap

+39
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ exports[`Test on POST search > Admin key: basic facet value search 1`] = `
1717
}
1818
`;
1919

20+
exports[`Test on POST search > Admin key: facet value search with exhaustive facet count 1`] = `
21+
{
22+
"facetHits": [
23+
{
24+
"count": 1,
25+
"value": "adventure",
26+
},
27+
],
28+
"facetQuery": "a",
29+
"processingTimeMs": 0,
30+
}
31+
`;
32+
2033
exports[`Test on POST search > Admin key: facet value search with filter 1`] = `
2134
{
2235
"facetHits": [
@@ -85,6 +98,19 @@ exports[`Test on POST search > Master key: basic facet value search 1`] = `
8598
}
8699
`;
87100

101+
exports[`Test on POST search > Master key: facet value search with exhaustive facet count 1`] = `
102+
{
103+
"facetHits": [
104+
{
105+
"count": 1,
106+
"value": "adventure",
107+
},
108+
],
109+
"facetQuery": "a",
110+
"processingTimeMs": 0,
111+
}
112+
`;
113+
88114
exports[`Test on POST search > Master key: facet value search with filter 1`] = `
89115
{
90116
"facetHits": [
@@ -153,6 +179,19 @@ exports[`Test on POST search > Search key: basic facet value search 1`] = `
153179
}
154180
`;
155181

182+
exports[`Test on POST search > Search key: facet value search with exhaustive facet count 1`] = `
183+
{
184+
"facetHits": [
185+
{
186+
"count": 1,
187+
"value": "adventure",
188+
},
189+
],
190+
"facetQuery": "a",
191+
"processingTimeMs": 0,
192+
}
193+
`;
194+
156195
exports[`Test on POST search > Search key: facet value search with filter 1`] = `
157196
{
158197
"facetHits": [

tests/__snapshots__/settings.test.ts.snap

+2
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ exports[`Test on settings > Admin key: Update embedders settings 1`] = `
268268
{% endif %}{% endfor %}",
269269
"documentTemplateMaxBytes": 400,
270270
"model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
271+
"pooling": "useModel",
271272
"source": "huggingFace",
272273
},
273274
},
@@ -958,6 +959,7 @@ exports[`Test on settings > Master key: Update embedders settings 1`] = `
958959
{% endif %}{% endfor %}",
959960
"documentTemplateMaxBytes": 400,
960961
"model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
962+
"pooling": "useModel",
961963
"source": "huggingFace",
962964
},
963965
},

tests/batch.test.ts

+3
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
3333
const batches = await client.batches.getBatches();
3434
const batch = await client.batches.getBatch(batches.results[0].uid);
3535
expect(batch.uid).toEqual(batches.results[0].uid);
36+
37+
// Can't use toMatchSnapshot because the output changes every time
3638
expect(batch.details).toBeDefined();
3739
expect(batch.stats).toHaveProperty("totalNbTasks");
3840
expect(batch.stats).toHaveProperty("status");
3941
expect(batch.stats).toHaveProperty("types");
4042
expect(batch.stats).toHaveProperty("indexUids");
43+
expect(batch.stats).toHaveProperty("progressTrace");
4144
expect(batch.duration).toBeDefined();
4245
expect(batch.startedAt).toBeDefined();
4346
expect(batch.finishedAt).toBeDefined();

tests/documents.test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ describe("Documents tests", () => {
7979
expect(document.id).toBeUndefined();
8080
});
8181

82+
test(`${permission} key: Get multiple documents by IDs`, async () => {
83+
const client = await getClient(permission);
84+
await client.index(indexPk.uid).addDocuments(dataset).waitTask();
85+
86+
const documents = await client
87+
.index(indexPk.uid)
88+
.getDocuments<Book>({ ids: [1, 2] });
89+
90+
expect(documents.results.length).toEqual(2);
91+
expect(documents.results.map(({ id }) => id).sort()).toEqual([1, 2]);
92+
});
93+
8294
test(`${permission} key: Get documents with string fields`, async () => {
8395
const client = await getClient(permission);
8496

tests/embedders.test.ts

+48
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
BAD_HOST,
77
MeiliSearch,
88
getClient,
9+
getKey,
10+
HOST,
911
} from "./utils/meilisearch-test-utils.js";
1012

1113
const index = {
@@ -136,6 +138,7 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
136138
mean: 0.7,
137139
sigma: 0.3,
138140
},
141+
pooling: "useModel",
139142
documentTemplateMaxBytes: 500,
140143
binaryQuantized: false,
141144
},
@@ -250,6 +253,51 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
250253
expect(response).toEqual(newEmbedder);
251254
});
252255

256+
test(`${permission} key: Update embedders with composite embedder`, async () => {
257+
const adminKey = await getKey("Admin");
258+
259+
// first enable the network endpoint.
260+
await fetch(`${HOST}/experimental-features`, {
261+
body: JSON.stringify({ compositeEmbedders: true }),
262+
headers: {
263+
Authorization: `Bearer ${adminKey}`,
264+
"Content-Type": "application/json",
265+
},
266+
method: "PATCH",
267+
});
268+
269+
const client = await getClient(permission);
270+
const embedders: IndividualUpdatableSettings["embedders"] = {
271+
default: {
272+
source: "composite",
273+
searchEmbedder: {
274+
source: "huggingFace",
275+
model:
276+
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
277+
pooling: "useModel",
278+
},
279+
indexingEmbedder: {
280+
source: "huggingFace",
281+
model:
282+
"sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
283+
documentTemplate: "{{doc.title}}",
284+
pooling: "useModel",
285+
documentTemplateMaxBytes: 500,
286+
},
287+
},
288+
};
289+
290+
const task = await client
291+
.index(index.uid)
292+
.setting.updateEmbedders(embedders)
293+
.waitTask();
294+
const response = await client.index(index.uid).setting.getEmbedders();
295+
296+
const processedTask = await client.tasks.getTask(task.uid);
297+
expect(processedTask.status).toEqual("succeeded");
298+
expect(response).toEqual(embedders);
299+
});
300+
253301
test(`${permission} key: Reset embedders`, async () => {
254302
const client = await getClient(permission);
255303
await client.index(index.uid).setting.resetEmbedders().waitTask();

tests/facet_search.test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,21 @@ describe.each([
9898
// @TODO: This is flaky, processingTimeMs is not guaranteed
9999
expect(response).toMatchSnapshot();
100100
});
101+
102+
test(`${permission} key: facet value search with exhaustive facet count`, async () => {
103+
const client = await getClient(permission);
104+
105+
const params = {
106+
facetName: "genres",
107+
facetQuery: "a",
108+
q: "Alice",
109+
exhaustiveFacetCount: true,
110+
};
111+
const response = await client.index(index.uid).searchForFacetValues(params);
112+
113+
// @TODO: This is flaky, processingTimeMs is not guaranteed
114+
expect(response).toMatchSnapshot();
115+
});
101116
});
102117

103118
afterAll(() => {

tests/filterable_attributes.test.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { expect, test, describe, beforeEach, afterAll } from "vitest";
2-
import { ErrorStatusCode } from "../src/index.js";
2+
import {
3+
ErrorStatusCode,
4+
type IndividualUpdatableSettings,
5+
} from "../src/index.js";
36
import {
47
clearAllIndexes,
58
config,
@@ -62,6 +65,30 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])(
6265
expect(response?.sort()).toEqual([]);
6366
});
6467

68+
test(`${permission} key: Update attributes with granular attribute syntax`, async () => {
69+
const client = await getClient(permission);
70+
const newFilterableAttributes: IndividualUpdatableSettings["filterableAttributes"] =
71+
[
72+
"author",
73+
{
74+
attributePatterns: ["genre"],
75+
features: {
76+
facetSearch: true,
77+
filter: { equality: true, comparison: false },
78+
},
79+
},
80+
];
81+
await client
82+
.index(index.uid)
83+
.setting.updateFilterableAttributes(newFilterableAttributes)
84+
.waitTask();
85+
86+
const response = await client
87+
.index(index.uid)
88+
.setting.getFilterableAttributes();
89+
expect(response).toEqual(newFilterableAttributes);
90+
});
91+
6592
test(`${permission} key: Reset attributes for filtering`, async () => {
6693
const client = await getClient(permission);
6794
await client

0 commit comments

Comments
 (0)