Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -617,3 +617,16 @@ update_network_1: |-
}
}
})
list_dynamic_search_rules_1: |-
client.getDynamicSearchRules()
get_dynamic_search_rule_1: |-
client.getDynamicSearchRule('RULE_UID')
patch_dynamic_search_rule_1: |-
client.updateDynamicSearchRule('RULE_UID', {
actions: [{
selector: { indexUid: 'movies', id: '299537' },
action: { type: 'pin', position: 0 }
}]
})
delete_dynamic_search_rule_1: |-
client.deleteDynamicSearchRule('RULE_UID')
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
services:
meilisearch:
image: getmeili/meilisearch-enterprise:v1.40
image: getmeili/meilisearch-enterprise:v1.42
env:
MEILI_MASTER_KEY: "masterKey"
MEILI_NO_ANALYTICS: "true"
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:
- ./:/home/package

meilisearch:
image: getmeili/meilisearch-enterprise:v1.40
image: getmeili/meilisearch-enterprise:v1.42
ports:
- "7700:7700"
environment:
Expand Down
61 changes: 61 additions & 0 deletions src/meilisearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import type {
RecordAny,
RuntimeTogglableFeatures,
ResourceResults,
SearchRule,
SearchRuleUpdatePayload,
SearchRuleListPayload,
Remote,
Webhook,
ResultsWrapper,
Expand Down Expand Up @@ -311,6 +314,64 @@ export class Meilisearch {
});
}

///
/// DYNAMIC SEARCH RULES
///

/**
* Get all dynamic search rules
*
* @param parameters - Parameters to browse dynamic search rules
* @returns Promise returning an object with dynamic search rules
*/
async getDynamicSearchRules(
parameters?: SearchRuleListPayload,
): Promise<ResourceResults<SearchRule[]>> {
return await this.httpRequest.post({
path: "dynamic-search-rules",
body: parameters ?? {},
});
}

/**
* Get a dynamic search rule
*
* @param uid - Dynamic search rule UID
* @returns Promise returning the dynamic search rule
*/
async getDynamicSearchRule(uid: string): Promise<SearchRule> {
return await this.httpRequest.get({
path: `dynamic-search-rules/${uid}`,
});
}

/**
* Update a dynamic search rule
*
* @param uid - Dynamic search rule UID
* @param rule - Dynamic search rule to update
* @returns Promise returning the updated dynamic search rule
*/
async updateDynamicSearchRule(
uid: string,
rule: SearchRuleUpdatePayload,
): Promise<SearchRule> {
return await this.httpRequest.patch({
path: `dynamic-search-rules/${uid}`,
body: rule,
});
}

/**
* Delete a dynamic search rule
*
* @param uid - Dynamic search rule UID
* @returns Promise returning void
*/
async deleteDynamicSearchRule(uid: string): Promise<void> {
await this.httpRequest.delete({ path: `dynamic-search-rules/${uid}` });
}

///
/// WEBHOOKS
///
Expand Down
4 changes: 1 addition & 3 deletions src/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ export class TaskClient {
const ac = timeout > 0 ? new AbortController() : null;

const toId =
ac !== null
? setTimeout(() => void ac.abort(TIMEOUT_ID), timeout)
: undefined;
ac !== null ? setTimeout(() => ac.abort(TIMEOUT_ID), timeout) : undefined;

try {
for (;;) {
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./experimental-features.js";
export * from "./search-rules.js";
export * from "./fields.js";
export * from "./network.js";
export * from "./task-and-batch.js";
Expand Down
60 changes: 60 additions & 0 deletions src/types/search-rules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export type SearchRuleListFilterPayload = {
attributePatterns?: string[] | null;
active?: boolean | null;
};

export type SearchRuleListPayload = {
offset?: number;
limit?: number;
filter?: SearchRuleListFilterPayload | null;
};

export type SearchRuleSelector = {
indexUid?: string | null;
id?: string | null;
};

export type SearchRulePinAction = {
type: "pin";
position: number;
};

export type SearchRuleAction = {
selector: SearchRuleSelector;
action: SearchRulePinAction;
};

export type SearchRuleQueryCondition = {
scope: "query";
isEmpty?: boolean | null;
contains?: string | null;
};

export type SearchRuleTimeCondition = {
scope: "time";
start?: string | null;
end?: string | null;
};

export type SearchRuleCondition =
| SearchRuleQueryCondition
| SearchRuleTimeCondition;

/** Dynamic search rule object */
export type SearchRule = {
uid: string;
description?: string | null;
priority?: number | null;
active?: boolean;
conditions?: SearchRuleCondition[];
actions: SearchRuleAction[];
};

/** Partial update payload for a dynamic search rule */
export type SearchRuleUpdatePayload = {
description?: string | null;
priority?: number | null;
active?: boolean | null;
conditions?: SearchRuleCondition[] | null;
actions?: SearchRuleAction[] | null;
};
6 changes: 3 additions & 3 deletions tests/get_search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ describe.each([
expect(response).toHaveProperty("hits");
expect(Array.isArray(response.hits)).toBe(true);
expect(response).toHaveProperty("query", "prince");
expect(Object.keys(hit).join(",")).toEqual(
Object.keys(dataset[1]).join(","),
);
Object.keys(dataset[1]).forEach((key) => {
expect(hit).toHaveProperty(key);
});
Comment thread
Strift marked this conversation as resolved.
});

test(`${permission} key: search on attributesToSearchOn`, async () => {
Expand Down
83 changes: 83 additions & 0 deletions tests/search-rules.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { getClient } from "./utils/meilisearch-test-utils.js";
import { Meilisearch, type SearchRuleUpdatePayload } from "../src/index.js";

let adminClient: Meilisearch;
let masterClient: Meilisearch;

const SEARCH_RULE_UID = "movie-rule";
const SEARCH_RULE_PATCH: SearchRuleUpdatePayload = {
actions: [
{
selector: {
indexUid: "movies",
id: "1",
},
action: {
type: "pin",
position: 1,
},
},
],
};

beforeAll(async () => {
adminClient = await getClient("Admin");
masterClient = await getClient("Master");
const dynamicSearchRulesFeature = {
dynamicSearchRules: true,
} as unknown as Parameters<Meilisearch["updateExperimentalFeatures"]>[0];
await masterClient.updateExperimentalFeatures(dynamicSearchRulesFeature);
Comment thread
Strift marked this conversation as resolved.
Outdated
});

afterAll(async () => {
const response = await masterClient.getDynamicSearchRules();
for (const rule of response.results) {
await masterClient.deleteDynamicSearchRule(rule.uid);
}
});

describe("dynamic search rules", () => {
it("can list dynamic search rules", async () => {
const response = await adminClient.getDynamicSearchRules({
offset: 0,
limit: 20,
filter: { attributePatterns: [SEARCH_RULE_UID] },
});
expect(response).toHaveProperty("results");
expect(response.results).toBeInstanceOf(Array);
});

it("can create or update a dynamic search rule with patch payload", async () => {
const response = await adminClient.updateDynamicSearchRule(
SEARCH_RULE_UID,
SEARCH_RULE_PATCH,
);

expect(response).toHaveProperty("uid", SEARCH_RULE_UID);
expect(response).toHaveProperty("actions", SEARCH_RULE_PATCH.actions);
});

it("can fetch a dynamic search rule", async () => {
await adminClient.updateDynamicSearchRule(
SEARCH_RULE_UID,
SEARCH_RULE_PATCH,
);

const response = await adminClient.getDynamicSearchRule(SEARCH_RULE_UID);

expect(response).toHaveProperty("uid", SEARCH_RULE_UID);
expect(response).toHaveProperty("actions", SEARCH_RULE_PATCH.actions);
});

it("can delete a dynamic search rule", async () => {
await adminClient.updateDynamicSearchRule(
SEARCH_RULE_UID,
SEARCH_RULE_PATCH,
);

const response = await adminClient.deleteDynamicSearchRule(SEARCH_RULE_UID);

expect(response).toBeUndefined();
});
});
Loading